From 1aff7173105c9540bbbef75727aa200f5c288b2e Mon Sep 17 00:00:00 2001 From: Kevin Buettner Date: Sat, 1 Jun 2019 13:42:29 -0700 Subject: [PATCH] dwarf2-frame.c: Fix FDE processing bug involving non-contiguous ranges 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. gdb/ChangeLog: * dwarf2-frame.c (dwarf2_frame_cache): Don't decode FDE instructions for entry pc when entry pc is out of range for that FDE. --- gdb/ChangeLog | 7 +++++++ gdb/dwarf2-frame.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 82ef5038f1f..a3c6bcfeaf4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -15,6 +15,13 @@ Restrict cases in which use of minimal symbol is preferred to that of a found symbol. Update comments. + * dwarf2-frame.c (dwarf2_frame_cache): Don't decode FDE instructions + for entry pc when entry pc is out of range for that FDE. + + * printcmd.c (print_address_symbolic): Print negative offsets. + (build_address_symbolic): Force signed arithmetic when computing + offset. + 2019-07-26 Brian Callahan PR gdb/24839: diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index cad6b7b0ce0..7839942b8c7 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, -- 2.30.2