|
|
01917d |
commit 1ec56e88aa9b052ab10b806d82fbdbc8d153d977
|
|
|
01917d |
Author: Pedro Alves <palves@redhat.com>
|
|
|
01917d |
Date: Fri Nov 22 13:17:46 2013 +0000
|
|
|
01917d |
|
|
|
01917d |
Eliminate dwarf2_frame_cache recursion, don't unwind from the dwarf2 sniffer (move dwarf2_tailcall_sniffer_first elsewhere).
|
|
|
01917d |
|
|
|
01917d |
Two rationales, same patch.
|
|
|
01917d |
|
|
|
01917d |
TL;DR 1:
|
|
|
01917d |
|
|
|
01917d |
dwarf2_frame_cache recursion is evil. dwarf2_frame_cache calls
|
|
|
01917d |
dwarf2_tailcall_sniffer_first which then recurses into
|
|
|
01917d |
dwarf2_frame_cache.
|
|
|
01917d |
|
|
|
01917d |
TL;DR 2:
|
|
|
01917d |
|
|
|
01917d |
An unwinder trying to unwind is evil. dwarf2_frame_sniffer calls
|
|
|
01917d |
dwarf2_frame_cache which calls dwarf2_tailcall_sniffer_first which
|
|
|
01917d |
then tries to unwind the PC of the previous frame.
|
|
|
01917d |
|
|
|
01917d |
Avoid all that by deferring dwarf2_tailcall_sniffer_first until it's
|
|
|
01917d |
really necessary.
|
|
|
01917d |
|
|
|
01917d |
Rationale 1
|
|
|
01917d |
===========
|
|
|
01917d |
|
|
|
01917d |
A frame sniffer should not try to unwind, because that bypasses all
|
|
|
01917d |
the validation checks done by get_prev_frame. The UNWIND_SAME_ID
|
|
|
01917d |
scenario is one such case where GDB is currently broken because (in
|
|
|
01917d |
part) of this (the next patch adds a test that would fail without
|
|
|
01917d |
this).
|
|
|
01917d |
|
|
|
01917d |
GDB goes into an infinite loop in value_fetch_lazy, here:
|
|
|
01917d |
|
|
|
01917d |
while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
|
|
|
01917d |
{
|
|
|
01917d |
frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
|
|
|
01917d |
...
|
|
|
01917d |
new_val = get_frame_register_value (frame, regnum);
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
(top-gdb) bt
|
|
|
01917d |
#0 value_fetch_lazy (val=0x11516d0) at ../../src/gdb/value.c:3510
|
|
|
01917d |
#1 0x0000000000584bd8 in value_optimized_out (value=0x11516d0) at ../../src/gdb/value.c:1096
|
|
|
01917d |
#2 0x00000000006fe7a1 in frame_register_unwind (frame=0x1492600, regnum=16, optimizedp=0x7fffffffcdec, unavailablep=0x7fffffffcde8, lvalp=0x7fffffffcdd8, addrp=
|
|
|
01917d |
0x7fffffffcde0, realnump=0x7fffffffcddc, bufferp=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:940
|
|
|
01917d |
#3 0x00000000006fea3a in frame_unwind_register (frame=0x1492600, regnum=16, buf=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:990
|
|
|
01917d |
#4 0x0000000000473b9b in i386_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/i386-tdep.c:1771
|
|
|
01917d |
#5 0x0000000000601dfa in gdbarch_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/gdbarch.c:2870
|
|
|
01917d |
#6 0x0000000000693db5 in dwarf2_tailcall_sniffer_first (this_frame=0x1492600, tailcall_cachep=0x14926f0, entry_cfa_sp_offsetp=0x7fffffffcf00)
|
|
|
01917d |
at ../../src/gdb/dwarf2-frame-tailcall.c:389
|
|
|
01917d |
#7 0x0000000000690928 in dwarf2_frame_cache (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1245
|
|
|
01917d |
#8 0x0000000000690f46 in dwarf2_frame_sniffer (self=0x8e4980, this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1423
|
|
|
01917d |
#9 0x000000000070203b in frame_unwind_find_by_frame (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/frame-unwind.c:112
|
|
|
01917d |
#10 0x00000000006fd681 in get_frame_id (fi=0x1492600) at ../../src/gdb/frame.c:408
|
|
|
01917d |
#11 0x00000000007006c2 in get_prev_frame_1 (this_frame=0xdc1860) at ../../src/gdb/frame.c:1826
|
|
|
01917d |
#12 0x0000000000700b7a in get_prev_frame (this_frame=0xdc1860) at ../../src/gdb/frame.c:2056
|
|
|
01917d |
#13 0x0000000000514588 in frame_info_to_frame_object (frame=0xdc1860) at ../../src/gdb/python/py-frame.c:322
|
|
|
01917d |
#14 0x000000000051784c in bootstrap_python_frame_filters (frame=0xdc1860, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1396
|
|
|
01917d |
#15 0x0000000000517a6f in apply_frame_filter (frame=0xdc1860, flags=7, args_type=CLI_SCALAR_VALUES, out=0xed7a90, frame_low=0, frame_high=-1)
|
|
|
01917d |
at ../../src/gdb/python/py-framefilter.c:1492
|
|
|
01917d |
#16 0x00000000005e77b0 in backtrace_command_1 (count_exp=0x0, show_locals=0, no_filters=0, from_tty=1) at ../../src/gdb/stack.c:1777
|
|
|
01917d |
#17 0x00000000005e7c0f in backtrace_command (arg=0x0, from_tty=1) at ../../src/gdb/stack.c:1891
|
|
|
01917d |
#18 0x00000000004e37a7 in do_cfunc (c=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:107
|
|
|
01917d |
#19 0x00000000004e683c in cmd_func (cmd=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1882
|
|
|
01917d |
#20 0x00000000006f35ed in execute_command (p=0xcc66c2 "", from_tty=1) at ../../src/gdb/top.c:468
|
|
|
01917d |
#21 0x00000000005f8853 in command_handler (command=0xcc66c0 "bt") at ../../src/gdb/event-top.c:435
|
|
|
01917d |
#22 0x00000000005f8e12 in command_line_handler (rl=0xfe05f0 "@") at ../../src/gdb/event-top.c:632
|
|
|
01917d |
#23 0x000000000074d2c6 in rl_callback_read_char () at ../../src/readline/callback.c:220
|
|
|
01917d |
#24 0x00000000005f8375 in rl_callback_read_char_wrapper (client_data=0x0) at ../../src/gdb/event-top.c:164
|
|
|
01917d |
#25 0x00000000005f876a in stdin_event_handler (error=0, client_data=0x0) at ../../src/gdb/event-top.c:375
|
|
|
01917d |
#26 0x00000000005f72fa in handle_file_event (data=...) at ../../src/gdb/event-loop.c:768
|
|
|
01917d |
#27 0x00000000005f67a3 in process_event () at ../../src/gdb/event-loop.c:342
|
|
|
01917d |
#28 0x00000000005f686a in gdb_do_one_event () at ../../src/gdb/event-loop.c:406
|
|
|
01917d |
#29 0x00000000005f68bb in start_event_loop () at ../../src/gdb/event-loop.c:431
|
|
|
01917d |
#30 0x00000000005f83a7 in cli_command_loop (data=0x0) at ../../src/gdb/event-top.c:179
|
|
|
01917d |
#31 0x00000000005eeed3 in current_interp_command_loop () at ../../src/gdb/interps.c:327
|
|
|
01917d |
#32 0x00000000005ef8ff in captured_command_loop (data=0x0) at ../../src/gdb/main.c:267
|
|
|
01917d |
#33 0x00000000005ed2f6 in catch_errors (func=0x5ef8e4 <captured_command_loop>, func_args=0x0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL)
|
|
|
01917d |
at ../../src/gdb/exceptions.c:524
|
|
|
01917d |
#34 0x00000000005f0d21 in captured_main (data=0x7fffffffd9e0) at ../../src/gdb/main.c:1067
|
|
|
01917d |
#35 0x00000000005ed2f6 in catch_errors (func=0x5efb9b <captured_main>, func_args=0x7fffffffd9e0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL)
|
|
|
01917d |
at ../../src/gdb/exceptions.c:524
|
|
|
01917d |
#36 0x00000000005f0d57 in gdb_main (args=0x7fffffffd9e0) at ../../src/gdb/main.c:1076
|
|
|
01917d |
#37 0x000000000045bb6a in main (argc=4, argv=0x7fffffffdae8) at ../../src/gdb/gdb.c:34
|
|
|
01917d |
(top-gdb)
|
|
|
01917d |
|
|
|
01917d |
GDB is trying to unwind the PC register of the previous frame (frame
|
|
|
01917d |
#5 above), starting from the frame being sniffed (the THIS frame).
|
|
|
01917d |
But the THIS frame's unwinder says the PC of the previous frame is
|
|
|
01917d |
actually the same as the previous's frame's next frame (which is the
|
|
|
01917d |
same frame we started with, the THIS frame), therefore it returns an
|
|
|
01917d |
lval_register lazy value with frame set to THIS frame. And so the
|
|
|
01917d |
value_fetch_lazy loop never ends.
|
|
|
01917d |
|
|
|
01917d |
|
|
|
01917d |
Rationale 2
|
|
|
01917d |
===========
|
|
|
01917d |
|
|
|
01917d |
As an experiment, I tried making dwarf2-frame.c:read_addr_from_reg use
|
|
|
01917d |
address_from_register. That caused a bunch of regressions, but it
|
|
|
01917d |
actually took me a long while to figure out what was going on. Turns
|
|
|
01917d |
out dwarf2-frame.c:read_addr_from_reg is called while computing the
|
|
|
01917d |
frame's CFA, from within dwarf2_frame_cache. address_from_register
|
|
|
01917d |
wants to create a register with frame_id set to the frame being
|
|
|
01917d |
constructed. To create the frame id, we again call dwarf2_frame_cache,
|
|
|
01917d |
which given:
|
|
|
01917d |
|
|
|
01917d |
static struct dwarf2_frame_cache *
|
|
|
01917d |
dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
|
|
|
01917d |
{
|
|
|
01917d |
...
|
|
|
01917d |
if (*this_cache)
|
|
|
01917d |
return *this_cache;
|
|
|
01917d |
|
|
|
01917d |
returns an incomplete object to the caller:
|
|
|
01917d |
static void
|
|
|
01917d |
dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
|
|
|
01917d |
struct frame_id *this_id)
|
|
|
01917d |
{
|
|
|
01917d |
struct dwarf2_frame_cache *cache =
|
|
|
01917d |
dwarf2_frame_cache (this_frame, this_cache);
|
|
|
01917d |
...
|
|
|
01917d |
(*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame));
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
As cache->cfa is still 0 (we were trying to compute it!), and
|
|
|
01917d |
get_frame_id recalls this id from here on, we end up with a broken
|
|
|
01917d |
frame id in recorded for this frame. Later, when inspecting locals,
|
|
|
01917d |
the dwarf machinery needs to know the selected frame's base, which
|
|
|
01917d |
calls get_frame_base:
|
|
|
01917d |
|
|
|
01917d |
CORE_ADDR
|
|
|
01917d |
get_frame_base (struct frame_info *fi)
|
|
|
01917d |
{
|
|
|
01917d |
return get_frame_id (fi).stack_addr;
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
which as seen above then returns 0 ...
|
|
|
01917d |
|
|
|
01917d |
So I gave up using address_from_register.
|
|
|
01917d |
|
|
|
01917d |
But, the pain of investigating this made me want to have GDB itself
|
|
|
01917d |
assert that recursion never happens here. So I wrote a patch to do
|
|
|
01917d |
that. But, it triggers on current mainline, because
|
|
|
01917d |
dwarf2_tailcall_sniffer_first, called from dwarf2_frame_cache, unwinds
|
|
|
01917d |
the this_frame.
|
|
|
01917d |
|
|
|
01917d |
A sniffer shouldn't be trying to unwind, exactly because of this sort
|
|
|
01917d |
of tricky issue. The patch defers calling
|
|
|
01917d |
dwarf2_tailcall_sniffer_first until it's really necessary, in
|
|
|
01917d |
dwarf2_frame_prev_register (thus actually outside the sniffer path).
|
|
|
01917d |
As this makes the call to dwarf2_frame_sniffer in dwarf2_frame_cache
|
|
|
01917d |
unnecessary again, the patch removes that too.
|
|
|
01917d |
|
|
|
01917d |
Tested on x86_64 Fedora 17.
|
|
|
01917d |
|
|
|
01917d |
gdb/
|
|
|
01917d |
2013-11-22 Pedro Alves <palves@redhat.com>
|
|
|
01917d |
|
|
|
01917d |
PR 16155
|
|
|
01917d |
* dwarf2-frame.c (struct dwarf2_frame_cache)
|
|
|
01917d |
|
|
|
01917d |
entry_cfa_sp_offset_p>: New fields.
|
|
|
01917d |
(dwarf2_frame_cache): Adjust to use the new cache fields instead
|
|
|
01917d |
of locals. Don't call dwarf2_tailcall_sniffer_first here.
|
|
|
01917d |
(dwarf2_frame_prev_register): Call it here, but only once.
|
|
|
01917d |
|
|
|
01917d |
Index: gdb-7.6.1/gdb/dwarf2-frame.c
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- gdb-7.6.1.orig/gdb/dwarf2-frame.c
|
|
|
01917d |
+++ gdb-7.6.1/gdb/dwarf2-frame.c
|
|
|
01917d |
@@ -984,12 +984,22 @@ struct dwarf2_frame_cache
|
|
|
01917d |
/* The .text offset. */
|
|
|
01917d |
CORE_ADDR text_offset;
|
|
|
01917d |
|
|
|
01917d |
+ /* True if we already checked whether this frame is the bottom frame
|
|
|
01917d |
+ of a virtual tail call frame chain. */
|
|
|
01917d |
+ int checked_tailcall_bottom;
|
|
|
01917d |
+
|
|
|
01917d |
/* If not NULL then this frame is the bottom frame of a TAILCALL_FRAME
|
|
|
01917d |
sequence. If NULL then it is a normal case with no TAILCALL_FRAME
|
|
|
01917d |
involved. Non-bottom frames of a virtual tail call frames chain use
|
|
|
01917d |
dwarf2_tailcall_frame_unwind unwinder so this field does not apply for
|
|
|
01917d |
them. */
|
|
|
01917d |
void *tailcall_cache;
|
|
|
01917d |
+
|
|
|
01917d |
+ /* The number of bytes to subtract from TAILCALL_FRAME frames frame
|
|
|
01917d |
+ base to get the SP, to simulate the return address pushed on the
|
|
|
01917d |
+ stack. */
|
|
|
01917d |
+ LONGEST entry_cfa_sp_offset;
|
|
|
01917d |
+ int entry_cfa_sp_offset_p;
|
|
|
01917d |
};
|
|
|
01917d |
|
|
|
01917d |
/* A cleanup that sets a pointer to NULL. */
|
|
|
01917d |
@@ -1014,8 +1024,6 @@ dwarf2_frame_cache (struct frame_info *t
|
|
|
01917d |
struct dwarf2_fde *fde;
|
|
|
01917d |
volatile struct gdb_exception ex;
|
|
|
01917d |
CORE_ADDR entry_pc;
|
|
|
01917d |
- LONGEST entry_cfa_sp_offset;
|
|
|
01917d |
- int entry_cfa_sp_offset_p = 0;
|
|
|
01917d |
const gdb_byte *instr;
|
|
|
01917d |
|
|
|
01917d |
if (*this_cache)
|
|
|
01917d |
@@ -1080,8 +1088,8 @@ dwarf2_frame_cache (struct frame_info *t
|
|
|
01917d |
&& (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
|
|
|
01917d |
== gdbarch_sp_regnum (gdbarch)))
|
|
|
01917d |
{
|
|
|
01917d |
- entry_cfa_sp_offset = fs->regs.cfa_offset;
|
|
|
01917d |
- entry_cfa_sp_offset_p = 1;
|
|
|
01917d |
+ cache->entry_cfa_sp_offset = fs->regs.cfa_offset;
|
|
|
01917d |
+ cache->entry_cfa_sp_offset_p = 1;
|
|
|
01917d |
}
|
|
|
01917d |
}
|
|
|
01917d |
else
|
|
|
01917d |
@@ -1230,13 +1238,6 @@ incomplete CFI data; unspecified registe
|
|
|
01917d |
cache->undefined_retaddr = 1;
|
|
|
01917d |
|
|
|
01917d |
do_cleanups (old_chain);
|
|
|
01917d |
-
|
|
|
01917d |
- /* Try to find a virtual tail call frames chain with bottom (callee) frame
|
|
|
01917d |
- starting at THIS_FRAME. */
|
|
|
01917d |
- dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache,
|
|
|
01917d |
- (entry_cfa_sp_offset_p
|
|
|
01917d |
- ? &entry_cfa_sp_offset : NULL));
|
|
|
01917d |
-
|
|
|
01917d |
discard_cleanups (reset_cache_cleanup);
|
|
|
01917d |
return cache;
|
|
|
01917d |
}
|
|
|
01917d |
@@ -1282,6 +1283,16 @@ dwarf2_frame_prev_register (struct frame
|
|
|
01917d |
CORE_ADDR addr;
|
|
|
01917d |
int realnum;
|
|
|
01917d |
|
|
|
01917d |
+ /* Check whether THIS_FRAME is the bottom frame of a virtual tail
|
|
|
01917d |
+ call frame chain. */
|
|
|
01917d |
+ if (!cache->checked_tailcall_bottom)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ cache->checked_tailcall_bottom = 1;
|
|
|
01917d |
+ dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache,
|
|
|
01917d |
+ (cache->entry_cfa_sp_offset_p
|
|
|
01917d |
+ ? &cache->entry_cfa_sp_offset : NULL));
|
|
|
01917d |
+ }
|
|
|
01917d |
+
|
|
|
01917d |
/* Non-bottom frames of a virtual tail call frames chain use
|
|
|
01917d |
dwarf2_tailcall_frame_unwind unwinder so this code does not apply for
|
|
|
01917d |
them. If dwarf2_tailcall_prev_register_first does not have specific value
|
|
|
01917d |
@@ -1408,10 +1419,6 @@ dwarf2_frame_sniffer (const struct frame
|
|
|
01917d |
if (self->type != NORMAL_FRAME)
|
|
|
01917d |
return 0;
|
|
|
01917d |
|
|
|
01917d |
- /* Preinitializa the cache so that TAILCALL_FRAME can find the record by
|
|
|
01917d |
- dwarf2_tailcall_sniffer_first. */
|
|
|
01917d |
- dwarf2_frame_cache (this_frame, this_cache);
|
|
|
01917d |
-
|
|
|
01917d |
return 1;
|
|
|
01917d |
}
|
|
|
01917d |
|