gcc/g++ is generating the same DWARF DW_AT_ranges info for two different functions. This makes translation from a PC address to the function difficult since a given PC can map to two different functions. Using the following test file: // Compile as "g++ -O2 -ggdb --save-temps -o t t.cc" #include <vector> using namespace std; int main () { vector<int> V(10); V[10] = 1; } the DWARF info emitted by gcc assigns a block of addresses to two different functions, get_allocator and _S_get_pool. Here is an edited dump of the DWARF info produced by readelf. <2><2523>: Abbrev Number: 38 (DW_TAG_subprogram) DW_AT_name : (indirect string, offset: 0x1d35): get_allocator <1><3807>: Abbrev Number: 77 (DW_TAG_subprogram) DW_AT_specification: <2523> DW_AT_inline : 3 (declared as inline and inlined) <3><39de>: Abbrev Number: 92 (DW_TAG_inlined_subroutine) DW_AT_abstract_origin: <3807> DW_AT_ranges : 0x5c8 000005c8 080488c9 080488d0 000005c8 08048a50 08048af6 000005c8 080488dc 080488e2 000005c8 <End of list> <2><227c>: Abbrev Number: 64 (DW_TAG_subprogram) DW_AT_name : (indirect string, offset: 0x666): _S_get_pool <1><2e03>: Abbrev Number: 77 (DW_TAG_subprogram) DW_AT_specification: <227c> DW_AT_inline : 3 (declared as inline and inlined) <6><3a12>: Abbrev Number: 92 (DW_TAG_inlined_subroutine) DW_AT_abstract_origin: <2e03> DW_AT_ranges : 0x628 00000628 080488c9 080488d0 00000628 08048a50 08048af6 00000628 080488dc 080488e2 00000628 <End of list> When one function inlines another, and all of the associated code is generated for the inlinee with no code generated for the inliner, my reading of the draft DWARF 3 spec, which describes DW_AT_ranges, would indicate that no DW_AT_low_pc, DW_AT_high_pc, or DW_AT_ranges attributes should be generated for the inliner function: 2.16 Code Addresses and Ranges Any debugging information entry describing an entity that has a machine code address or range of machine code addresses, which includes compilation units, module initialization, subroutines, ordinary blocks, try/catch blocks, labels and the like, may have " A DW_AT_low_pc attribute for a single address, " A DW_AT_low_pc and DW_AT_high_pc pair of attributes for a single contiguous range of addresses, or " A DW_AT_ranges attribute for a non-contiguous range of addresses. If an entity has no associated machine code, none of these attributes are specified. My understanding, perhaps incorrect, is that the entire purpose of using the DW_AT_ranges attribute, instead of the DW_AT_low_pc/DW_AT_high_pc attributes, is to be able to accurately describe situations like this, where code from different functions is interleaved due to optimization. No given address should appear in more than one DW_AT_ranges entry.
No version information. Is this HEAD, with Jim's earlier DW_AT_ranges patch? I don't think your understanding is correct, but you didn't show enough of the DIE tree to be sure. Ignore inlined functions for a moment; let's just think about functions and lexical blocks. A lexical block normally has a range of associated PC addresses, and a function normally has a high and low pc. The lexical block is a strict subset of the function, so it should be included in the pc attributes of the function. I'm guessing from your description that _S_get_pool is inlined into get_allocator is inlined into main. Because _S_get_pool is inside of get_allocator, it makes sense for its PC ranges to be a subset of those for get_allocator. A PC always belongs to the innermost block.
> No version information. Is this HEAD, with Jim's earlier DW_AT_ranges patch? Yes, sorry I didn't mention it. Originally I tried to report this bug with "gccbug" but the report seems to have gone into a black hole. Perhaps gccbug is broken. Thanks for the comments. I'll go back and review the spec again. The one I'm looking at is Dwarf3-draft9.pdf, 1320652 bytes. Can't recall offhand where I found it but I should probably check around for a newer one. > I'm guessing from your description that _S_get_pool is inlined into > get_allocator is inlined into main Yes, though there is actually a little more inlining going on, so these aren't the only two duplicates.
Subject: Re: g++ generates same DW_AT_ranges info for two different functions It's a question of what "associated machine code" means. I think that the machine code is in fact associated with more than one DIE. Now, if the two DIEs in question weren't nested - then we'd have a problem.
My opinion is roughly the same as Daniel's. The debug info being emitted by gcc here is fine. The underlying problem here is that Fred is trying to improve support for inlined function calls, and the current structure of the debug info emitted by gcc makes this difficult. However, Fred pointed me at the dwarf3 docs for DW_AT_call_file and DW_AT_call_line. It turns out to be easy to make gcc emit this extra debug info, and I have written a patch that does so. This patch does not fix this PR, but it does make it moot.
Created attachment 8760 [details] Emit DW_AT_call_file and DW_AT_CALL_line for inlined subroutines. This emits extra debug info that describes where an inlined subroutine was called from. This extra info would allow one to construct backtraces that contain info about inlined subroutines. This has been tested with an x86-linux bootstrap, make check, and gdb make check. There were no regressions. I haven't checked in the patch yet as I have no proof that it does anything useful, since neither binutils nor gdb handle this new debug info. I'm waiting for patches from Fred that will make use of this new info.
Created attachment 8881 [details] Emit DW_AT_call_file and DW_AT_call_line for inlined subroutines.
The problem reported here is not a bug. There is nothing wrong with having two different functions with the same DW_AT_ranges info. The underlying problem that prompted this bug report, insufficient debug info for inlined function calls, has been fixed by adding a patch to emit DW_AT_call_file and DW_AT_call_line info. The final patch has one additional bug fix over the one attached here, so take the one on the gcc-patches list if you need it.