Message ID | 20190608195434.26512-3-kevinb@redhat.com |
---|---|
State | New |
Headers | show |
On 6/8/19 8:54 PM, Kevin Buettner wrote: > In the course of revising the test case for > gdb.dwarf2/dw2-ranges-func.exp, I added a new .c file which would > cause the "cold" range to be at a higher address than the rest of the > function. In these tests, the range in question isn't really cold in > the sense that a compiler has determined that it'll be executed less > frequently. Instead, it's simply the range that does not include the > entry pc. These tests are intended to mimic the output of such a > compiler, so I'll continue to refer to this range as "cold" in the > following discussion. > > The original test case had only tested a cold range placed > at lower addresses than the rest of the function. During testing of the > new code where the cold range was placed at higher addresses, I found > that I could produce the following backtrace: > > (gdb) bt > #0 0x0000000000401138 in baz () > at dw2-ranges-func-hi-cold.c:72 > #1 0x0000000000401131 in foo_cold () > at dw2-ranges-func-hi-cold.c:64 > #2 0x000000000040111e in foo () > at dw2-ranges-func-hi-cold.c:50 > #3 0x0000000000401144 in main () > at dw2-ranges-func-hi-cold.c:78 > > This is correct, except that we'd like to see foo() listed instead > of foo_cold(). (I handle that problem in another patch.) > > Now look at what happens for a similar backtrace where the cold range > is at a lower address than the foo's entry pc: > > (gdb) bt > #0 0x000000000040110a in baz () > at dw2-ranges-func-lo-cold.c:48 > #1 0x0000000000401116 in foo () > at dw2-ranges-func-lo-cold.c:54 > #2 0x00007fffffffd4c0 in ?? () > #3 0x0000000000401138 in foo () > at dw2-ranges-func-lo-cold.c:70 > > Note that the backtrace doesn't go all the way back to main(). Moreover, > frame #2 is messed up. > > I had seen this behavior when I had worked on the non-contiguous > address problem last year. At the time I convinced myself that the > mangled backtrace was "okay" since we're doing strange things with > the DWARF assembler. We're taking a function called foo_cold (though > it was originally called foo_low - my recent changes to the test case > changed the name) and via the magic of the DWARF assembler, we're > combining it into a separate (non-contiguous) range for foo. Thus, > it was a surprise to me when I got a good and complete backtrace when > the cold symbol is placed at an address that's greater than entry pc. > > The function dwarf2_frame_cache (in dwarf2-frame.c) is making this > call: > > if (get_frame_func_if_available (this_frame, &entry_pc)) ... > > If that call succeeds (returns a true value), the FDE is then > processed up to the entry pc. It doesn't make sense to do this, > however, when the FDE in question does not contain the entry pc. This > can happen when the function in question is comprised of more than one > (non-contiguous) address range. > > My fix is to add some comparisons to the test above to ensure that > ENTRY_PC is within the address range covered by the FDE. Looks reasonable. Thanks, Pedro Alves
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 0f2502b4c6..c98e2f232f 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -1023,7 +1023,13 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) /* Save the initialized register set. */ fs.initial = fs.regs; - if (get_frame_func_if_available (this_frame, &entry_pc)) + /* Fetching the entry pc for THIS_FRAME won't necessarily result + in an address that's within the range of FDE locations. This + is due to the possibility of the function occupying non-contiguous + ranges. */ + if (get_frame_func_if_available (this_frame, &entry_pc) + && fde->initial_location <= entry_pc + && entry_pc < fde->initial_location + fde->address_range) { /* Decode the insns in the FDE up to the entry PC. */ instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,