Commit bc7d7abf authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Facebook GitHub Bot

folly: symbolizer: check if findSubProgramDieForAddress found the...

folly: symbolizer: check if findSubProgramDieForAddress found the DW_TAG_subprogram for address & terminate DFS early

Summary:
It's legal that a CU has `DW_AT_ranges` listing all addresses, but not have a `DW_TAG_subprogram` child DIE for some of those addresses.

Check for `findSubProgramDieForAddress` success before reading potentially empty `subprogram` attributes in `eachParameterName`.

This is a bugfix. If `DW_TAG_subprogram` is missing, we read attributes for using offsets in the uninitialized DIE `subprogram`.

Initialize all struct members to avoid wasting time debugging uninitialized memory access (had fun with uninitialized `subprogram.abbr.tag` magically picking up `DW_TAG_subprogram` or garbage on the stack from previous calls).

 ---

Terminate `findSubProgramDieForAddress` DFS on match.

Before:
- when the DW_TAG_subprogram DIE was found we stopped scanning its direct siblings (the above "return false" when `pcMatch` or `rangeMatch` are true).
- but when we returned from recursion in the parent DIE we discarded the fact that we found the DW_TAG_subprogram and continued the DFS scan through all remaining DIEs.

After:
- after finding the DW_TAG_subprogram that owns that address the scan stops.

As reference when using `-fno-debug-types-section` type info is part of `.debug_info`.

```
namespace folly::symbolizer::test {
void function_A();
class SomeClass { void some_member_function() {} };
void function_B();
} // folly::symbolizer::test
```

```
0x0000004c:   DW_TAG_namespace [2] *
                DW_AT_name [DW_FORM_strp]       ( "folly")

0x00000051:     DW_TAG_namespace [2] *
                  DW_AT_name [DW_FORM_strp]     ( "symbolizer")

0x00000056:       DW_TAG_namespace [2] *
                    DW_AT_name [DW_FORM_strp]   ( "test")

0x0000012e:         DW_TAG_subprogram [7] *
                      DW_AT_name [DW_FORM_strp] ( "function_A")

0x0000022d:         DW_TAG_class_type [14] *
                      DW_AT_name [DW_FORM_strp] ( "SomeClass")

0x00000243:           DW_TAG_subprogram [16] *
                        DW_AT_name [DW_FORM_strp]       ( "some_member_function")

0x000002ed:         DW_TAG_subprogram [9] *
                      DW_AT_name [DW_FORM_strp] ( "function_B")
```

Before:
- if `address` corresponds to code inside `SomeClass::some_member_function` we stopped iterating over `SomeClass::some_member_function`'s sibling DIEs, and returned.
- but we still continued scanning over `SomeClass`'s sibling DIEs and all their children recursively (DFS), and then `SomeClass`'s parents siblings etc until reaching the end of the CU

After:
- we stop DFS on match

FWIW: trees are somewhat flatter when using `-fdebug-types-section`: member functions are extracted from their classes, but they're still part of namespace subtrees so the code unnecessarily explored siblings of the innermost namespace.

Differential Revision: D25799618

fbshipit-source-id: 9a0267e12a7d496ad00263bf30a12dc548764288
parent 5a9b1bb0
This diff is collapsed.
...@@ -117,24 +117,25 @@ class Dwarf { ...@@ -117,24 +117,25 @@ class Dwarf {
class LineNumberVM; class LineNumberVM;
/** /**
* Finds location info (file and line) for a given address in the given * Find the @locationInfo for @address in the compilation unit @cu.
* compilation unit. Invokes `eachParameterName`, if set, for each parameter *
* of the given function. * Best effort:
* - fills @inlineFrames if mode == FULL_WITH_INLINE,
* - calls @eachParameterName on the function parameters.
*/ */
bool findLocation( bool findLocation(
uintptr_t address, uintptr_t address,
const LocationInfoMode mode, const LocationInfoMode mode,
detail::CompilationUnit& cu, detail::CompilationUnit& cu,
LocationInfo& info, LocationInfo& info,
folly::Range<SymbolizedFrame*> inlineFrames = {}, folly::Range<SymbolizedFrame*> inlineFrames,
folly::FunctionRef<void(folly::StringPiece)> eachParameterName = {}) folly::FunctionRef<void(folly::StringPiece)> eachParameterName) const;
const;
/** /**
* Finds a subprogram debugging info entry that contains a given address among * Finds a subprogram debugging info entry that contains a given address among
* children of given die. Depth first search. * children of given die. Depth first search.
*/ */
void findSubProgramDieForAddress( bool findSubProgramDieForAddress(
const detail::CompilationUnit& cu, const detail::CompilationUnit& cu,
const detail::Die& die, const detail::Die& die,
uint64_t address, uint64_t address,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment