gendwarfksyms: Expand subroutine_type

Add support for expanding DW_TAG_subroutine_type and the parameters
in DW_TAG_formal_parameter. Use this to also expand subprograms.

Example output with --dump-dies:

  subprogram (
    formal_parameter pointer_type {
      const_type {
        base_type char byte_size(1) encoding(6)
      }
    }
  )
  -> base_type unsigned long byte_size(8) encoding(7)

Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
This commit is contained in:
Sami Tolvanen
2025-01-03 20:45:28 +00:00
committed by Masahiro Yamada
parent 06b8b036ab
commit 220a0857f3
2 changed files with 85 additions and 3 deletions

View File

@@ -212,6 +212,15 @@ DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
/* Match functions -- die_match_callback_t */
#define DEFINE_MATCH(type) \
static bool match_##type##_type(Dwarf_Die *die) \
{ \
return dwarf_tag(die) == DW_TAG_##type##_type; \
}
DEFINE_MATCH(formal_parameter)
bool match_all(Dwarf_Die *die)
{
return true;
@@ -224,19 +233,28 @@ int process_die_container(struct state *state, struct die *cache,
Dwarf_Die current;
int res;
/* Track the first item in lists. */
if (state)
state->first_list_item = true;
res = checkp(dwarf_child(die, &current));
while (!res) {
if (match(&current)) {
/* <0 = error, 0 = continue, >0 = stop */
res = checkp(func(state, cache, &current));
if (res)
return res;
goto out;
}
res = checkp(dwarf_siblingof(&current, &current));
}
return 0;
res = 0;
out:
if (state)
state->first_list_item = false;
return res;
}
static int process_type(struct state *state, struct die *parent,
@@ -256,6 +274,40 @@ static void process_type_attr(struct state *state, struct die *cache,
process(cache, "base_type void");
}
static void process_list_comma(struct state *state, struct die *cache)
{
if (state->first_list_item) {
state->first_list_item = false;
} else {
process(cache, " ,");
process_linebreak(cache, 0);
}
}
/* Comma-separated with DW_AT_type */
static void __process_list_type(struct state *state, struct die *cache,
Dwarf_Die *die, const char *type)
{
const char *name = get_name_attr(die);
process_list_comma(state, cache);
process(cache, type);
process_type_attr(state, cache, die);
if (name) {
process(cache, " ");
process(cache, name);
}
}
#define DEFINE_PROCESS_LIST_TYPE(type) \
static void process_##type##_type(struct state *state, \
struct die *cache, Dwarf_Die *die) \
{ \
__process_list_type(state, cache, die, #type " "); \
}
DEFINE_PROCESS_LIST_TYPE(formal_parameter)
/* Container types with DW_AT_type */
static void __process_type(struct state *state, struct die *cache,
Dwarf_Die *die, const char *type)
@@ -290,6 +342,29 @@ DEFINE_PROCESS_TYPE(shared)
DEFINE_PROCESS_TYPE(volatile)
DEFINE_PROCESS_TYPE(typedef)
static void __process_subroutine_type(struct state *state, struct die *cache,
Dwarf_Die *die, const char *type)
{
process(cache, type);
process(cache, " (");
process_linebreak(cache, 1);
/* Parameters */
check(process_die_container(state, cache, die, process_type,
match_formal_parameter_type));
process_linebreak(cache, -1);
process(cache, ")");
process_linebreak(cache, 0);
/* Return type */
process(cache, "-> ");
process_type_attr(state, cache, die);
}
static void process_subroutine_type(struct state *state, struct die *cache,
Dwarf_Die *die)
{
__process_subroutine_type(state, cache, die, "subroutine_type");
}
static void process_base_type(struct state *state, struct die *cache,
Dwarf_Die *die)
{
@@ -360,8 +435,11 @@ static int process_type(struct state *state, struct die *parent, Dwarf_Die *die)
PROCESS_TYPE(rvalue_reference)
PROCESS_TYPE(shared)
PROCESS_TYPE(volatile)
/* Subtypes */
PROCESS_TYPE(formal_parameter)
/* Other types */
PROCESS_TYPE(base)
PROCESS_TYPE(subroutine)
PROCESS_TYPE(typedef)
default:
debug("unimplemented type: %x", tag);
@@ -391,7 +469,7 @@ static void process_symbol(struct state *state, Dwarf_Die *die,
static int __process_subprogram(struct state *state, struct die *cache,
Dwarf_Die *die)
{
process(cache, "subprogram");
__process_subroutine_type(state, cache, die, "subprogram");
return 0;
}

View File

@@ -60,6 +60,7 @@ extern int dump_dies;
#define checkp(expr) __check(expr, __res < 0)
/* Consistent aliases (DW_TAG_<type>_type) for DWARF tags */
#define DW_TAG_formal_parameter_type DW_TAG_formal_parameter
#define DW_TAG_typedef_type DW_TAG_typedef
/*
@@ -154,6 +155,9 @@ void die_map_free(void);
struct state {
struct symbol *sym;
Dwarf_Die die;
/* List expansion */
bool first_list_item;
};
typedef int (*die_callback_t)(struct state *state, struct die *cache,