Hey all, can someone explain me the difference between dwarf_getscopes and dwarf_getscopes_die? Ideally, this should then be added to the documentation too.
Currently, the documentation states: ``` /* Return scope DIEs containing PC address. Sets *SCOPES to a malloc'd array of Dwarf_Die structures, and returns the number of elements in the array. (*SCOPES)[0] is the DIE for the innermost scope containing PC, (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. Returns -1 for errors or 0 if no scopes match PC. */ extern int dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes); /* Return scope DIEs containing the given DIE. Sets *SCOPES to a malloc'd array of Dwarf_Die structures, and returns the number of elements in the array. (*SCOPES)[0] is a copy of DIE. (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. Returns -1 for errors or 0 if DIE is not found in any scope entry. */ extern int dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes); ``` Most notably, both say: ``` (*SCOPES)[1] is the DIE for the scope containing that scope, and so on. ``` But in practice, there seems to be a difference. Inspired by the code form eu- addr2line we resolve inline frames like this: ``` Dwarf_Addr bias = 0; Dwarf_Die *cudie = dwfl_module_addrdie(module, ip, &bias); Dwarf_Die *subroutine = nullptr; Dwarf_Die *scopes = nullptr; int nscopes = dwarf_getscopes(cudie, ip - bias, &scopes); for (int i = 0; i < nscopes; ++i) { Dwarf_Die *scope = &scopes[i]; const int tag = dwarf_tag(scope); if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { subroutine = scope; break; } } Dwarf_Die *scopes_die = nullptr; int nscopes_die = dwarf_getscopes_die(subroutine, &scopes_die); for (int i = 0; i < nscopes_die; ++i) { Dwarf_Die *scope = &scopes_die[i]; const int tag = dwarf_tag(scope); if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { // do stuff } } free(scopes_die); free(scopes); ``` In the above, subroutine points to somewhere in dwarf_getscopes. As such, passing it to dwarf_getscopes_die, one would assume from the documentation (see above) that we get the sames scopes we already found via `dwarf_getscopes` (with an offset), but that is clearly no the case. Here is an example: ``` dwarf_getscopes: n = 2 i = 1, tag = 0x11, name = "../../../manual/clients/vector.cpp" i = 0, tag = 0x1d, name = "_ZN9__gnu_cxx13new_allocatorIdE10deallocateEPdm" ``` Then, we use the DIE at i = 0 from above to call dwarf_getscopes_die, which yields: ``` dwarf_getscopes_die, n = 6 i = 5, tag = 0x11, name = "../../../manual/clients/vector.cpp" i = 4, tag = 0x2e, name = "_ZNSt6vectorIdSaIdEE17_M_realloc_insertIJdEEEvN9__gnu_cxx17__normal_iteratorIPdS1_EEDpOT_" i = 3, tag = 0x1d, name = "_ZNSt12_Vector_baseIdSaIdEE13_M_deallocateEPdm" i = 2, tag = 0x0b i = 1, tag = 0x1d, name = "_ZNSt16allocator_traitsISaIdEE10deallocateERS0_Pdm" i = 0, tag = 0x1d, name = "_ZN9__gnu_cxx13new_allocatorIdE10deallocateEPdm" ``` As we can see, dwarf_getscopes_die returns more scopes than dwarf_getscopes. For me, the documentation for `dwarf_getscopes` is confusing. I would have expected that it should be a superset of dwarf_getscopes_die, but apparently that is not the case. Thanks -- Milian Wolff m...@milianw.de http://milianw.de
signature.asc
Description: This is a digitally signed message part.