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.