aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2013-12-17 20:47:36 +0000
committerPedro Alves <palves@redhat.com>2013-12-17 20:47:36 +0000
commit5ce0145de764dc9c6e92daf2f843fa6e496c49d0 (patch)
tree014f7ca18d39e6901a4d4c27cdbb728bcaa2796b /gdb/frame.c
parente234935207c21a212b5a35928f50b578c65b9649 (diff)
downloadgdb-5ce0145de764dc9c6e92daf2f843fa6e496c49d0.zip
gdb-5ce0145de764dc9c6e92daf2f843fa6e496c49d0.tar.gz
gdb-5ce0145de764dc9c6e92daf2f843fa6e496c49d0.tar.bz2
"tfind" across unavailable-stack frames.
Like when stepping, the current stack frame location is expected to be printed as result of tfind command, if that results in moving to a different function. In tfind_1 we see: if (from_tty && (has_stack_frames () || traceframe_number >= 0)) { enum print_what print_what; /* NOTE: in imitation of the step command, try to determine whether we have made a transition from one function to another. If so, we'll print the "stack frame" (ie. the new function and it's arguments) -- otherwise we'll just show the new source line. */ if (frame_id_eq (old_frame_id, get_frame_id (get_current_frame ()))) print_what = SRC_LINE; else print_what = SRC_AND_LOC; print_stack_frame (get_selected_frame (NULL), 1, print_what, 1); do_displays (); } However, when we haven't collected any registers in the tracepoint (collect $regs), that doesn't actually work: (gdb) tstart (gdb) info tracepoints Num Type Disp Enb Address What 1 tracepoint keep y 0x080483b7 in func0 at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28 collect testload installed on target 2 tracepoint keep y 0x080483bc in func1 at ../.././../git/gdb/testsuite/gdb.trace/circ.c:32 collect testload installed on target (gdb) c Continuing. Breakpoint 3, end () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:72 72 } (gdb) tstop (gdb) tfind start Found trace frame 0, tracepoint 1 #0 func0 () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28 28 } (gdb) tfind Found trace frame 1, tracepoint 2 32 } (gdb) When we don't have info about the stack available (UNWIND_UNAVAILABLE), frames end up with outer_frame_id as frame ID. And in the scenario above, the issue is that both frames before and after the second tfind (the frames for func0 an func1) have the same id (outer_frame_id), so the frame_id_eq check returns false, even though the frames were of different functions. GDB knows that, because the PC is inferred from the tracepoint's address, even if no registers were collected. To fix this, this patch adds support for frame ids with a valid code address, but <unavailable> stack address, and then makes the unwinders use that instead of the catch-all outer_frame_id for such frames. The frame_id_eq check in tfind_1 then automatically does the right thing as expected. I tested with --directory=gdb.trace/ , before/after the patch, and compared the resulting gdb.logs, then adjusted the tests to expect the extra output that came out. Turns out that was only circ.exp, the original test that actually brought this issue to light. Tested on x86_64 Fedora 17, native and gdbserver. gdb/ 2013-12-17 Pedro Alves <palves@redhat.com> * frame.h (enum frame_id_stack_status): New enum. (struct frame_id) <stack_addr>: Adjust comment. <stack_addr_p>: Delete field, replaced with ... <stack_status>: ... this new field. (frame_id_build_unavailable_stack): Declare. * frame.c (frame_addr_hash, fprint_field, outer_frame_id) (frame_id_build_special): Adjust. (frame_id_build_unavailable_stack): New function. (frame_id_build, frame_id_build_wild): Adjust. (frame_id_p, frame_id_eq, frame_id_inner): Adjust to take into account frames with unavailable stack. * amd64-tdep.c (amd64_frame_this_id) (amd64_sigtramp_frame_this_id, amd64_epilogue_frame_this_id): Use frame_id_build_unavailable_stack. * dwarf2-frame.c (dwarf2_frame_this_id): Likewise. * i386-tdep.c (i386_frame_this_id, i386_epilogue_frame_this_id) (i386_sigtramp_frame_this_id): Likewise. gdb/testsuite/ 2013-12-17 Pedro Alves <palves@redhat.com> * gdb.trace/circ.exp: Expect frame info to be printed when switching between frames with unavailable stack, but different functions.
Diffstat (limited to 'gdb/frame.c')
-rw-r--r--gdb/frame.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/gdb/frame.c b/gdb/frame.c
index 6a8b5ae..ed31c9e 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -166,10 +166,11 @@ frame_addr_hash (const void *ap)
const struct frame_id f_id = frame->this_id.value;
hashval_t hash = 0;
- gdb_assert (f_id.stack_addr_p || f_id.code_addr_p
+ gdb_assert (f_id.stack_status != FID_STACK_INVALID
+ || f_id.code_addr_p
|| f_id.special_addr_p);
- if (f_id.stack_addr_p)
+ if (f_id.stack_status == FID_STACK_VALID)
hash = iterative_hash (&f_id.stack_addr,
sizeof (f_id.stack_addr), hash);
if (f_id.code_addr_p)
@@ -317,13 +318,23 @@ void
fprint_frame_id (struct ui_file *file, struct frame_id id)
{
fprintf_unfiltered (file, "{");
- fprint_field (file, "stack", id.stack_addr_p, id.stack_addr);
+
+ if (id.stack_status == FID_STACK_INVALID)
+ fprintf_unfiltered (file, "!stack");
+ else if (id.stack_status == FID_STACK_UNAVAILABLE)
+ fprintf_unfiltered (file, "stack=<unavailable>");
+ else
+ fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr));
fprintf_unfiltered (file, ",");
+
fprint_field (file, "code", id.code_addr_p, id.code_addr);
fprintf_unfiltered (file, ",");
+
fprint_field (file, "special", id.special_addr_p, id.special_addr);
+
if (id.artificial_depth)
fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
+
fprintf_unfiltered (file, "}");
}
@@ -487,7 +498,7 @@ frame_unwind_caller_id (struct frame_info *next_frame)
}
const struct frame_id null_frame_id; /* All zeros. */
-const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 };
+const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 };
struct frame_id
frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
@@ -496,7 +507,7 @@ frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
- id.stack_addr_p = 1;
+ id.stack_status = FID_STACK_VALID;
id.code_addr = code_addr;
id.code_addr_p = 1;
id.special_addr = special_addr;
@@ -504,13 +515,26 @@ frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
return id;
}
+/* See frame.h. */
+
+struct frame_id
+frame_id_build_unavailable_stack (CORE_ADDR code_addr)
+{
+ struct frame_id id = null_frame_id;
+
+ id.stack_status = FID_STACK_UNAVAILABLE;
+ id.code_addr = code_addr;
+ id.code_addr_p = 1;
+ return id;
+}
+
struct frame_id
frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
{
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
- id.stack_addr_p = 1;
+ id.stack_status = FID_STACK_VALID;
id.code_addr = code_addr;
id.code_addr_p = 1;
return id;
@@ -522,7 +546,7 @@ frame_id_build_wild (CORE_ADDR stack_addr)
struct frame_id id = null_frame_id;
id.stack_addr = stack_addr;
- id.stack_addr_p = 1;
+ id.stack_status = FID_STACK_VALID;
return id;
}
@@ -532,7 +556,7 @@ frame_id_p (struct frame_id l)
int p;
/* The frame is valid iff it has a valid stack address. */
- p = l.stack_addr_p;
+ p = l.stack_status != FID_STACK_INVALID;
/* outer_frame_id is also valid. */
if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
p = 1;
@@ -559,19 +583,20 @@ frame_id_eq (struct frame_id l, struct frame_id r)
{
int eq;
- if (!l.stack_addr_p && l.special_addr_p
- && !r.stack_addr_p && r.special_addr_p)
+ if (l.stack_status == FID_STACK_INVALID && l.special_addr_p
+ && r.stack_status == FID_STACK_INVALID && r.special_addr_p)
/* The outermost frame marker is equal to itself. This is the
dodgy thing about outer_frame_id, since between execution steps
we might step into another function - from which we can't
unwind either. More thought required to get rid of
outer_frame_id. */
eq = 1;
- else if (!l.stack_addr_p || !r.stack_addr_p)
+ else if (l.stack_status == FID_STACK_INVALID
+ || l.stack_status == FID_STACK_INVALID)
/* Like a NaN, if either ID is invalid, the result is false.
Note that a frame ID is invalid iff it is the null frame ID. */
eq = 0;
- else if (l.stack_addr != r.stack_addr)
+ else if (l.stack_status != r.stack_status || l.stack_addr != r.stack_addr)
/* If .stack addresses are different, the frames are different. */
eq = 0;
else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
@@ -638,8 +663,9 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
int inner;
- if (!l.stack_addr_p || !r.stack_addr_p)
- /* Like NaN, any operation involving an invalid ID always fails. */
+ if (l.stack_status != FID_STACK_VALID || r.stack_status != FID_STACK_VALID)
+ /* Like NaN, any operation involving an invalid ID always fails.
+ Likewise if either ID has an unavailable stack address. */
inner = 0;
else if (l.artificial_depth > r.artificial_depth
&& l.stack_addr == r.stack_addr