summaryrefslogtreecommitdiff
path: root/scripts/gendwarfksyms/dwarf.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gendwarfksyms/dwarf.c')
-rw-r--r--scripts/gendwarfksyms/dwarf.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c
index 746a89d9e3d4..534d9aa7c114 100644
--- a/scripts/gendwarfksyms/dwarf.c
+++ b/scripts/gendwarfksyms/dwarf.c
@@ -1061,6 +1061,31 @@ static void process_variable(struct state *state, Dwarf_Die *die)
process_symbol(state, die, __process_variable);
}
+static void save_symbol_ptr(struct state *state)
+{
+ Dwarf_Die ptr_type;
+ Dwarf_Die type;
+
+ if (!get_ref_die_attr(&state->die, DW_AT_type, &ptr_type) ||
+ dwarf_tag(&ptr_type) != DW_TAG_pointer_type)
+ error("%s must be a pointer type!",
+ get_symbol_name(&state->die));
+
+ if (!get_ref_die_attr(&ptr_type, DW_AT_type, &type))
+ error("%s pointer missing a type attribute?",
+ get_symbol_name(&state->die));
+
+ /*
+ * Save the symbol pointer DIE in case the actual symbol is
+ * missing from the DWARF. Clang, for example, intentionally
+ * omits external symbols from the debugging information.
+ */
+ if (dwarf_tag(&type) == DW_TAG_subroutine_type)
+ symbol_set_ptr(state->sym, &type);
+ else
+ symbol_set_ptr(state->sym, &ptr_type);
+}
+
static int process_exported_symbols(struct state *unused, struct die *cache,
Dwarf_Die *die)
{
@@ -1084,7 +1109,9 @@ static int process_exported_symbols(struct state *unused, struct die *cache,
state_init(&state);
- if (tag == DW_TAG_subprogram)
+ if (is_symbol_ptr(get_symbol_name(&state.die)))
+ save_symbol_ptr(&state);
+ else if (tag == DW_TAG_subprogram)
process_subprogram(&state, &state.die);
else
process_variable(&state, &state.die);
@@ -1097,10 +1124,36 @@ static int process_exported_symbols(struct state *unused, struct die *cache,
}
}
+static void process_symbol_ptr(struct symbol *sym, void *arg)
+{
+ struct state state;
+ Dwarf *dwarf = arg;
+
+ if (sym->state != SYMBOL_UNPROCESSED || !sym->ptr_die_addr)
+ return;
+
+ debug("%s", sym->name);
+ state_init(&state);
+ state.sym = sym;
+
+ if (!dwarf_die_addr_die(dwarf, (void *)sym->ptr_die_addr, &state.die))
+ error("dwarf_die_addr_die failed for symbol ptr: '%s'",
+ sym->name);
+
+ if (dwarf_tag(&state.die) == DW_TAG_subroutine_type)
+ process_subprogram(&state, &state.die);
+ else
+ process_variable(&state, &state.die);
+
+ cache_free(&state.expansion_cache);
+}
+
void process_cu(Dwarf_Die *cudie)
{
check(process_die_container(NULL, NULL, cudie, process_exported_symbols,
match_all));
+ symbol_for_each(process_symbol_ptr, dwarf_cu_getdwarf(cudie->cu));
+
cache_free(&srcfile_cache);
}