mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-08-05 21:50:21 +08:00
Associate dummy_frame with ptid
This patch is to add ptid into dummy_frame and extend frame_id to dummy_frame_id (which has a ptid field). With this change, GDB uses dummy_frame_id (thread ptid and frame_id) to find the dummy frames. Currently, dummy frames are looked up by frame_id, which isn't accurate in non-stop or multi-process mode. The test case gdb.multi/dummy-frame-restore.exp shows the problem and this patch can fix it. Test dummy-frame-restore.exp makes two inferiors stop at different functions, say, inferior 1 stops at f1 while inferior 2 stops at f2. Set a breakpoint to a function, do the inferior call in two inferiors, and GDB has two dummy frames of the same frame_id. When the inferior call is finished, GDB will look up a dummy frame from its stack/list and restore the inferior's regcache. Two inferiors are finished in different orders, the inferiors' states are restored differently, which is wrong. Running dummy-frame-restore.exp under un-patched GDB, we'll get two fails: FAIL: gdb.multi/dummy-frame-restore.exp: inf 2 first: after infcall: bt in inferior 2 FAIL: gdb.multi/dummy-frame-restore.exp: inf 2 first: after infcall: bt in inferior 1 With this patch applied, GDB will choose the correct dummy_frame to restore for a given inferior, because ptid is considered when looking up dummy frames. Two fails above are fixed. Regression tested on x86_64-linux, both native and gdbserver. gdb: 2014-06-27 Yao Qi <yao@codesourcery.com> * breakpoint.c (check_longjmp_breakpoint_for_call_dummy): Change parameter type to 'struct thread_info *'. Caller updated. * breakpoint.h (check_longjmp_breakpoint_for_call_dummy): Update declaration. * dummy-frame.c (struct dummy_frame_id): New. (dummy_frame_id_eq): New function. (struct dummy_frame) <id>: Change its type to 'struct dummy_frame_id'. (dummy_frame_push): Add parameter ptid and save it in dummy_frame_id. (pop_dummy_frame_bpt): Use ptid of dummy_frame instead of inferior_ptid. (pop_dummy_frame): Assert that the ptid of dummy_frame equals to inferior_ptid. (lookup_dummy_frame): Change parameter type to 'struct dummy_frame_id *'. Callers updated. Call dummy_frame_id_eq instead of frame_id_eq. (dummy_frame_pop): Add parameter ptid. Callers updated. Update comments. Compose dummy_frame_id and pass it to lookup_dummy_frame. (dummy_frame_discard): Add parameter ptid. (dummy_frame_sniffer): Compose dummy_frame_id and call dummy_frame_id_eq instead of frame_id_eq. (fprint_dummy_frames): Print ptid. * dummy-frame.h: Remove comments. (dummy_frame_push): Add ptid in declaration. (dummy_frame_pop, dummy_frame_discard): Likewise. gdb/testsuite: 2014-06-27 Yao Qi <yao@codesourcery.com> * gdb.multi/dummy-frame-restore.exp: New. * gdb.multi/dummy-frame-restore.c: New. gdb/doc: 2014-06-27 Yao Qi <yao@codesourcery.com> * gdb.texinfo (Maintenance Commands): Update the output of 'maint print dummy-frames' command.
This commit is contained in:
@ -31,6 +31,25 @@
|
||||
#include "observer.h"
|
||||
#include "gdbthread.h"
|
||||
|
||||
struct dummy_frame_id
|
||||
{
|
||||
/* This frame's ID. Must match the value returned by
|
||||
gdbarch_dummy_id. */
|
||||
struct frame_id id;
|
||||
|
||||
/* The thread this dummy_frame relates to. */
|
||||
ptid_t ptid;
|
||||
};
|
||||
|
||||
/* Return whether dummy_frame_id *ID1 and *ID2 are equal. */
|
||||
|
||||
static int
|
||||
dummy_frame_id_eq (struct dummy_frame_id *id1,
|
||||
struct dummy_frame_id *id2)
|
||||
{
|
||||
return frame_id_eq (id1->id, id2->id) && ptid_equal (id1->ptid, id2->ptid);
|
||||
}
|
||||
|
||||
/* Dummy frame. This saves the processor state just prior to setting
|
||||
up the inferior function call. Older targets save the registers
|
||||
on the target stack (but that really slows down function calls). */
|
||||
@ -38,9 +57,10 @@
|
||||
struct dummy_frame
|
||||
{
|
||||
struct dummy_frame *next;
|
||||
/* This frame's ID. Must match the value returned by
|
||||
gdbarch_dummy_id. */
|
||||
struct frame_id id;
|
||||
|
||||
/* An id represents a dummy frame. */
|
||||
struct dummy_frame_id id;
|
||||
|
||||
/* The caller's state prior to the call. */
|
||||
struct infcall_suspend_state *caller_state;
|
||||
};
|
||||
@ -52,13 +72,14 @@ static struct dummy_frame *dummy_frame_stack = NULL;
|
||||
|
||||
void
|
||||
dummy_frame_push (struct infcall_suspend_state *caller_state,
|
||||
const struct frame_id *dummy_id)
|
||||
const struct frame_id *dummy_id, ptid_t ptid)
|
||||
{
|
||||
struct dummy_frame *dummy_frame;
|
||||
|
||||
dummy_frame = XCNEW (struct dummy_frame);
|
||||
dummy_frame->caller_state = caller_state;
|
||||
dummy_frame->id = (*dummy_id);
|
||||
dummy_frame->id.id = (*dummy_id);
|
||||
dummy_frame->id.ptid = ptid;
|
||||
dummy_frame->next = dummy_frame_stack;
|
||||
dummy_frame_stack = dummy_frame;
|
||||
}
|
||||
@ -83,8 +104,8 @@ pop_dummy_frame_bpt (struct breakpoint *b, void *dummy_voidp)
|
||||
{
|
||||
struct dummy_frame *dummy = dummy_voidp;
|
||||
|
||||
if (b->thread == pid_to_thread_id (inferior_ptid)
|
||||
&& b->disposition == disp_del && frame_id_eq (b->frame_id, dummy->id))
|
||||
if (b->thread == pid_to_thread_id (dummy->id.ptid)
|
||||
&& b->disposition == disp_del && frame_id_eq (b->frame_id, dummy->id.id))
|
||||
{
|
||||
while (b->related_breakpoint != b)
|
||||
delete_breakpoint (b->related_breakpoint);
|
||||
@ -107,6 +128,7 @@ pop_dummy_frame (struct dummy_frame **dummy_ptr)
|
||||
{
|
||||
struct dummy_frame *dummy = *dummy_ptr;
|
||||
|
||||
gdb_assert (ptid_equal (dummy->id.ptid, inferior_ptid));
|
||||
restore_infcall_suspend_state (dummy->caller_state);
|
||||
|
||||
iterate_over_breakpoints (pop_dummy_frame_bpt, dummy);
|
||||
@ -125,48 +147,47 @@ pop_dummy_frame (struct dummy_frame **dummy_ptr)
|
||||
Return NULL if not found. */
|
||||
|
||||
static struct dummy_frame **
|
||||
lookup_dummy_frame (struct frame_id dummy_id)
|
||||
lookup_dummy_frame (struct dummy_frame_id *dummy_id)
|
||||
{
|
||||
struct dummy_frame **dp;
|
||||
|
||||
for (dp = &dummy_frame_stack; *dp != NULL; dp = &(*dp)->next)
|
||||
{
|
||||
if (frame_id_eq ((*dp)->id, dummy_id))
|
||||
if (dummy_frame_id_eq (&(*dp)->id, dummy_id))
|
||||
return dp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pop the dummy frame DUMMY_ID, restoring program state to that before the
|
||||
frame was created.
|
||||
/* Find the dummy frame by DUMMY_ID and PTID, and pop it, restoring
|
||||
program state to that before the frame was created.
|
||||
On return reinit_frame_cache has been called.
|
||||
If the frame isn't found, flag an internal error.
|
||||
|
||||
NOTE: This can only pop the one frame, even if it is in the middle of the
|
||||
stack, because the other frames may be for different threads, and there's
|
||||
currently no way to tell which stack frame is for which thread. */
|
||||
If the frame isn't found, flag an internal error. */
|
||||
|
||||
void
|
||||
dummy_frame_pop (struct frame_id dummy_id)
|
||||
dummy_frame_pop (struct frame_id dummy_id, ptid_t ptid)
|
||||
{
|
||||
struct dummy_frame **dp;
|
||||
struct dummy_frame_id id = { dummy_id, ptid };
|
||||
|
||||
dp = lookup_dummy_frame (dummy_id);
|
||||
dp = lookup_dummy_frame (&id);
|
||||
gdb_assert (dp != NULL);
|
||||
|
||||
pop_dummy_frame (dp);
|
||||
}
|
||||
|
||||
/* Drop dummy frame DUMMY_ID. Do nothing if it is not found. Do not restore
|
||||
its state into inferior, just free its memory. */
|
||||
/* Find the dummy frame by DUMMY_ID and PTID and drop it. Do nothing
|
||||
if it is not found. Do not restore its state into inferior, just
|
||||
free its memory. */
|
||||
|
||||
void
|
||||
dummy_frame_discard (struct frame_id dummy_id)
|
||||
dummy_frame_discard (struct frame_id dummy_id, ptid_t ptid)
|
||||
{
|
||||
struct dummy_frame **dp;
|
||||
struct dummy_frame_id id = { dummy_id, ptid };
|
||||
|
||||
dp = lookup_dummy_frame (dummy_id);
|
||||
dp = lookup_dummy_frame (&id);
|
||||
if (dp)
|
||||
remove_dummy_frame (dp);
|
||||
}
|
||||
@ -211,13 +232,14 @@ dummy_frame_sniffer (const struct frame_unwind *self,
|
||||
dummy ID, assuming it is a dummy frame. */
|
||||
struct frame_id this_id
|
||||
= gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);
|
||||
struct dummy_frame_id dummy_id = { this_id, inferior_ptid };
|
||||
|
||||
/* Use that ID to find the corresponding cache entry. */
|
||||
for (dummyframe = dummy_frame_stack;
|
||||
dummyframe != NULL;
|
||||
dummyframe = dummyframe->next)
|
||||
{
|
||||
if (frame_id_eq (dummyframe->id, this_id))
|
||||
if (dummy_frame_id_eq (&dummyframe->id, &dummy_id))
|
||||
{
|
||||
struct dummy_frame_cache *cache;
|
||||
|
||||
@ -297,7 +319,9 @@ fprint_dummy_frames (struct ui_file *file)
|
||||
gdb_print_host_address (s, file);
|
||||
fprintf_unfiltered (file, ":");
|
||||
fprintf_unfiltered (file, " id=");
|
||||
fprint_frame_id (file, s->id);
|
||||
fprint_frame_id (file, s->id.id);
|
||||
fprintf_unfiltered (file, ", ptid=%s",
|
||||
target_pid_to_str (s->id.ptid));
|
||||
fprintf_unfiltered (file, "\n");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user