+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.
+
2014-06-26 Tom Tromey <tromey@redhat.com>
* cli/cli-cmds.c (error_no_arg): Make "why" const.
}
/* Verify all existing dummy frames and their associated breakpoints for
- THREAD. Remove those which can no longer be found in the current frame
+ TP. Remove those which can no longer be found in the current frame
stack.
You should call this function only at places where it is safe to currently
frames. */
void
-check_longjmp_breakpoint_for_call_dummy (int thread)
+check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp)
{
struct breakpoint *b, *b_tmp;
ALL_BREAKPOINTS_SAFE (b, b_tmp)
- if (b->type == bp_longjmp_call_dummy && b->thread == thread)
+ if (b->type == bp_longjmp_call_dummy && b->thread == tp->num)
{
struct breakpoint *dummy_b = b->related_breakpoint;
|| frame_find_by_id (dummy_b->frame_id) != NULL)
continue;
- dummy_frame_discard (dummy_b->frame_id);
+ dummy_frame_discard (dummy_b->frame_id, tp->ptid);
while (b->related_breakpoint != b)
{
extern void delete_longjmp_breakpoint_at_next_stop (int thread);
extern struct breakpoint *set_longjmp_breakpoint_for_call_dummy (void);
-extern void check_longjmp_breakpoint_for_call_dummy (int thread);
+extern void check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp);
extern void enable_overlay_breakpoints (void);
extern void disable_overlay_breakpoints (void);
+2014-06-27 Yao Qi <yao@codesourcery.com>
+
+ * gdb.texinfo (Maintenance Commands): Update the output of
+ 'maint print dummy-frames' command.
+
2014-06-24 Eli Zaretskii <eliz@gnu.org>
* gdb.texinfo (Screen Size): Improve indexing.
The program being debugged stopped while in a function called from GDB.
@dots{}
(@value{GDBP}) @kbd{maint print dummy-frames}
-0x1a57c80: pc=0x01014068 fp=0x0200bddc sp=0x0200bdd6
- top=0x0200bdd4 id=@{stack=0x200bddc,code=0x101405c@}
- call_lo=0x01014000 call_hi=0x01014001
+0xa8206d8: id=@{stack=0xbfffe734,code=0xbfffe73f,!special@}, ptid=process 9353
(@value{GDBP})
@end smallexample
#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). */
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;
};
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;
}
{
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);
{
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);
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);
}
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;
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");
}
}
/* Push the information needed to identify, and unwind from, a dummy
frame onto the dummy frame stack. */
-/* NOTE: cagney/2004-08-02: This interface will eventually need to be
- parameterized with the caller's thread - that will allow per-thread
- dummy-frame stacks and, hence, per-thread inferior function
- calls. */
-
/* NOTE: cagney/2004-08-02: In the case of ABIs using push_dummy_code
containing more than one instruction, this interface many need to
be expanded so that it knowns the lower/upper extent of the dummy
frame's code. */
extern 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);
/* Pop the dummy frame DUMMY_ID, restoring program state to that before the
frame was created.
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. */
-extern void dummy_frame_pop (struct frame_id dummy_id);
+extern void dummy_frame_pop (struct frame_id dummy_id, ptid_t ptid);
-extern void dummy_frame_discard (struct frame_id dummy_id);
+extern void dummy_frame_discard (struct frame_id dummy_id, ptid_t ptid);
/* If the PC falls in a dummy frame, return a dummy frame
unwinder. */
{
/* Popping a dummy frame involves restoring more than just registers.
dummy_frame_pop does all the work. */
- dummy_frame_pop (get_frame_id (this_frame));
+ dummy_frame_pop (get_frame_id (this_frame), inferior_ptid);
return;
}
/* Everything's ready, push all the info needed to restore the
caller (and identify the dummy-frame) onto the dummy-frame
stack. */
- dummy_frame_push (caller_state, &dummy_id);
+ dummy_frame_push (caller_state, &dummy_id, inferior_ptid);
/* Discard both inf_status and caller_state cleanups.
From this point on we explicitly restore the associated state
/* We must get back to the frame we were before the
dummy call. */
- dummy_frame_pop (dummy_id);
+ dummy_frame_pop (dummy_id, call_thread_ptid);
/* We also need to restore inferior status to that before the
dummy call. */
{
/* We must get back to the frame we were before the dummy
call. */
- dummy_frame_pop (dummy_id);
+ dummy_frame_pop (dummy_id, call_thread_ptid);
/* We also need to restore inferior status to that before
the dummy call. */
if (what.is_longjmp)
{
- check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
+ check_longjmp_breakpoint_for_call_dummy (ecs->event_thread);
if (!frame_id_p (ecs->event_thread->initiating_frame))
{
+2014-06-27 Yao Qi <yao@codesourcery.com>
+
+ * gdb.multi/dummy-frame-restore.exp: New.
+ * gdb.multi/dummy-frame-restore.c: New.
+
2014-06-25 Markus Metzger <markus.t.metzger@intel.com>
* gdb.btrace/gcore.exp: New.
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+static void
+f1 (void)
+{}
+
+static void
+f2 (void)
+{}
+
+void
+commonfun (void)
+{}
+
+int
+main (void)
+{
+ f1 ();
+ f2 ();
+ return 0;
+}
--- /dev/null
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile .c
+set executable ${testfile}
+
+# The plain remote target can't do multiple inferiors.
+if [target_info exists use_gdb_stub] {
+ return
+}
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug}]} {
+ return -1
+}
+
+# Inferior 1 stops at f1.
+
+if ![runto f1] then {
+ fail "Can't run to f1"
+ return 0
+}
+
+gdb_test "add-inferior -exec ${binfile}" \
+ "Added inferior 2.*" \
+ "add inferior 2 with -exec ${executable}"
+gdb_test "inferior 2" "witching to inferior 2 .*" "switch to inferior 2"
+
+delete_breakpoints
+
+# Inferior 2 stops at f2.
+
+if ![runto f2] then {
+ fail "Can't run to f2"
+ return 0
+}
+
+gdb_breakpoint commonfun
+
+# Check the stack bactrace in inferior INF. PREFIX is the test
+# message prefix.
+
+proc check_bt { inf prefix } {
+ with_test_prefix "$prefix" {
+ gdb_test "bt 1" "#0 f$inf .*" "bt in inferior $inf"
+ }
+}
+
+# Do inferior call commonfun () in inferior 2 and inferior 1, but
+# finish it in inferior INF1 first and then inferior INF2. Check
+# the stack backtrace in each inferior is still correct after
+# inferior call.
+
+proc test { inf1 inf2 } {
+
+ with_test_prefix "inf $inf1 first" {
+ gdb_test "inferior 2" "witching to inferior 2 .*" \
+ "switch to inferior 2 (1)"
+ check_bt 2 "before infcall"
+ gdb_test "p commonfun()" "Breakpoint .*The program being debugged stopped while in a function called from GDB.*" "infcall in inferior 2"
+
+ gdb_test "inferior 1" "witching to inferior 1 .*" \
+ "switch to inferior 1 (1)"
+ check_bt 1 "before infcall"
+ gdb_test "p commonfun()" "Breakpoint .*The program being debugged stopped while in a function called from GDB.*" "infcall in inferior 1"
+
+ gdb_test "maintenance print dummy-frames" ": id={stack=.*}.*: id=.*" \
+ "two dummy frames"
+
+ gdb_test "inferior $inf1" "witching to inferior $inf1 .*" \
+ "switch to inferior $inf1 (2)"
+ gdb_test "finish" "Run till exit from #0 commonfun .*" \
+ "finish in inferior $inf1"
+ check_bt $inf1 "after infcall"
+
+ gdb_test "inferior $inf2" "witching to inferior $inf2 .*" \
+ "switch to inferior $inf2 (2)"
+ gdb_test "finish" "Run till exit from #0 commonfun .*" \
+ "finish in inferior $inf2"
+ check_bt $inf2 "after infcall"
+ }
+}
+
+# Do the test in different orders.
+test 1 2
+test 2 1