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
Showing
This diff is collapsed.
Please register or sign in to comment