@@ -359,38 +359,48 @@ namespace libdwarf {
359359 return prefix;
360360 }
361361
362+ // Follows DW_AT_specification or DW_AT_abstract_origin reference
363+ static optional<die_object> maybe_resolve_subprogram_reference (const die_object& die) {
364+ if (die.has_attr (DW_AT_specification)) {
365+ return die.resolve_reference_attribute (DW_AT_specification);
366+ }
367+ if (die.has_attr (DW_AT_abstract_origin)) {
368+ return die.resolve_reference_attribute (DW_AT_abstract_origin);
369+ }
370+ return nullopt ;
371+ }
372+
362373 std::string subprogram_symbol (
363374 const die_object& cu_die,
364375 const die_object& die,
365- Dwarf_Half dwversion,
366376 optional<string_view> walked_prefix = nullopt
367377 ) {
368378 ASSERT (die.get_tag () == DW_TAG_subprogram || die.get_tag () == DW_TAG_inlined_subroutine);
369- optional<std::string> name;
370- if (auto linkage_name = die.get_string_attribute (DW_AT_linkage_name)) {
371- name = std::move (linkage_name);
372- } else if (auto linkage_name = die.get_string_attribute (DW_AT_MIPS_linkage_name)) {
373- name = std::move (linkage_name);
374- } else if (auto raw_name = die.get_string_attribute (DW_AT_name)) {
375- // DW_AT_name is unqualified according to the DWARF standard
376- // In cache_mode == speed we preprocess all the namespace prefixes and a cache will hit in
377- // get_die_namespace_prefix, otherwise hopefully we can use the prefix we collected while walking
378- // and otherwise we'll have to re-walk from the cu_die to create the namespace prefix
379+ optional<die_object> ref_holder;
380+ const die_object* current = ¨
381+ while (current) {
382+ if (auto linkage_name = die.get_string_attribute (DW_AT_linkage_name)) {
383+ return std::move (linkage_name).unwrap ();
384+ }
385+ if (auto linkage_name = die.get_string_attribute (DW_AT_MIPS_linkage_name)) {
386+ return std::move (linkage_name).unwrap ();
387+ }
388+ if (auto raw_name = current->get_string_attribute (DW_AT_name)) {
389+ // DW_AT_name is unqualified according to the DWARF standard
390+ // In cache_mode == speed we preprocess all the namespace prefixes and a cache will hit in
391+ // get_die_namespace_prefix, otherwise hopefully we can use the prefix we collected while walking
392+ // and otherwise we'll have to re-walk from the cu_die to create the namespace prefix
379393 auto prefix = walked_prefix.has_value ()
380394 ? std::string (walked_prefix.unwrap ())
381- : get_die_namespace_prefix (cu_die, die );
382- name = prefix + raw_name.unwrap ();
395+ : get_die_namespace_prefix (cu_die, *current );
396+ return prefix + raw_name.unwrap ();
383397 }
384- if (name.has_value ()) {
385- return std::move (name).unwrap ();
386- } else {
387- if (die.has_attr (DW_AT_specification)) {
388- die_object spec = die.resolve_reference_attribute (DW_AT_specification);
389- return subprogram_symbol (cu_die, spec, dwversion);
390- } else if (die.has_attr (DW_AT_abstract_origin)) {
391- die_object spec = die.resolve_reference_attribute (DW_AT_abstract_origin);
392- return subprogram_symbol (cu_die, spec, dwversion);
393- }
398+ // let's try to follow DW_AT_specification / DW_AT_abstract_origin
399+ // when we do so, we discard any walked prefix we have since the referenced die might live in a
400+ // different series of nested namespaces etc
401+ walked_prefix.reset ();
402+ ref_holder = maybe_resolve_subprogram_reference (*current);
403+ current = ref_holder ? &ref_holder.unwrap () : nullptr ;
394404 }
395405 return " " ;
396406 }
@@ -452,7 +462,7 @@ namespace libdwarf {
452462 child,
453463 [this , &cu_die, pc, dwversion, &inlines, &target_die, ¤t_obj_holder] (const die_object& die) {
454464 if (die.get_tag () == DW_TAG_inlined_subroutine && die.pc_in_die (cu_die, dwversion, pc)) {
455- const auto name = subprogram_symbol (cu_die, die, dwversion );
465+ const auto name = subprogram_symbol (cu_die, die);
456466 auto file_i = die.get_unsigned_attribute (DW_AT_call_file);
457467 // TODO: Refactor.... Probably put logic in resolve_filename.
458468 if (file_i) {
@@ -518,7 +528,7 @@ namespace libdwarf {
518528 optional<string_view> walked_prefix = nullopt
519529 ) {
520530 ASSERT (die.get_tag () == DW_TAG_subprogram);
521- const auto name = subprogram_symbol (cu_die, die, dwversion, walked_prefix);
531+ const auto name = subprogram_symbol (cu_die, die, walked_prefix);
522532 if (should_resolve_inlined_calls ()) {
523533 get_inlines_info (cu_die, die, pc, dwversion, inlines);
524534 }
0 commit comments