/* Multi-process/thread control for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "symtab.h"
#include <signal.h>
#include "ui-out.h"
-/*#include "lynxos-core.h" */
-
/* Definition of struct thread_info exported to gdbthread.h */
/* Prototypes for exported functions. */
static void info_threads_command (char *, int);
static void thread_apply_command (char *, int);
static void restore_current_thread (ptid_t);
-static void switch_to_thread (ptid_t ptid);
static void prune_threads (void);
+static struct cleanup *make_cleanup_restore_current_thread (ptid_t,
+ struct frame_id);
void
delete_step_resume_breakpoint (void *arg)
free_thread (struct thread_info *tp)
{
/* NOTE: this will take care of any left-over step_resume breakpoints,
- but not any user-specified thread-specific breakpoints. */
+ but not any user-specified thread-specific breakpoints. We can not
+ delete the breakpoint straight-off, because the inferior might not
+ be stopped at the moment. */
if (tp->step_resume_breakpoint)
- delete_breakpoint (tp->step_resume_breakpoint);
+ tp->step_resume_breakpoint->disposition = disp_del_at_next_stop;
/* FIXME: do I ever need to call the back-end to give it a
chance at this private data before deleting the thread? */
enum gdb_rc
gdb_list_thread_ids (struct ui_out *uiout, char **error_message)
{
- return catch_exceptions_with_msg (uiout, do_captured_list_thread_ids, NULL,
- error_message, RETURN_MASK_ALL);
+ if (catch_exceptions_with_msg (uiout, do_captured_list_thread_ids, NULL,
+ error_message, RETURN_MASK_ALL) < 0)
+ return GDB_RC_FAIL;
+ return GDB_RC_OK;
}
/* Load infrun state for the thread PID. */
CORE_ADDR *step_range_end,
struct frame_id *step_frame_id,
int *handling_longjmp,
- int *another_trap,
+ int *stepping_over_breakpoint,
int *stepping_through_solib_after_catch,
bpstat *stepping_through_solib_catchpoints,
int *current_line,
*step_range_end = tp->step_range_end;
*step_frame_id = tp->step_frame_id;
*handling_longjmp = tp->handling_longjmp;
- *another_trap = tp->another_trap;
+ *stepping_over_breakpoint = tp->stepping_over_breakpoint;
*stepping_through_solib_after_catch =
tp->stepping_through_solib_after_catch;
*stepping_through_solib_catchpoints =
CORE_ADDR step_range_end,
const struct frame_id *step_frame_id,
int handling_longjmp,
- int another_trap,
+ int stepping_over_breakpoint,
int stepping_through_solib_after_catch,
bpstat stepping_through_solib_catchpoints,
int current_line,
tp->step_range_end = step_range_end;
tp->step_frame_id = (*step_frame_id);
tp->handling_longjmp = handling_longjmp;
- tp->another_trap = another_trap;
+ tp->stepping_over_breakpoint = stepping_over_breakpoint;
tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
tp->current_line = current_line;
struct thread_info *tp;
ptid_t current_ptid;
struct frame_info *cur_frame;
- struct frame_id saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ struct cleanup *old_chain;
+ struct frame_id saved_frame_id;
char *extra_info;
+ /* Backup current thread and selected frame. */
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
+
prune_threads ();
target_find_new_threads ();
current_ptid = inferior_ptid;
if (extra_info)
printf_filtered (" (%s)", extra_info);
puts_filtered (" ");
-
+ /* That switch put us at the top of the stack (leaf frame). */
switch_to_thread (tp->ptid);
print_stack_frame (get_selected_frame (NULL), 0, LOCATION);
}
- switch_to_thread (current_ptid);
+ /* Restores the current thread and the frame selected before
+ the "info threads" command. */
+ do_cleanups (old_chain);
- /* Restores the frame set by the user before the "info threads"
- command. We have finished the info-threads display by switching
- back to the current thread. That switch has put us at the top of
- the stack (leaf frame). */
- cur_frame = frame_find_by_id (saved_frame_id);
- if (cur_frame == NULL)
+ /* If case we were not able to find the original frame, print the
+ new selected frame. */
+ if (frame_find_by_id (saved_frame_id) == NULL)
{
- /* Ooops, can't restore, tell user where we are. */
warning (_("Couldn't restore frame in current thread, at frame 0"));
print_stack_frame (get_selected_frame (NULL), 0, LOCATION);
}
- else
- {
- select_frame (cur_frame);
- /* re-show current frame. */
- show_stack_frame (cur_frame);
- }
}
/* Switch from one thread to another. */
-static void
+void
switch_to_thread (ptid_t ptid)
{
if (ptid_equal (ptid, inferior_ptid))
return;
inferior_ptid = ptid;
- flush_cached_frames ();
+ reinit_frame_cache ();
registers_changed ();
stop_pc = read_pc ();
- select_frame (get_current_frame ());
}
static void
if (!ptid_equal (ptid, inferior_ptid))
{
switch_to_thread (ptid);
- print_stack_frame (get_current_frame (), 1, SRC_LINE);
+ }
+}
+
+static void
+restore_selected_frame (struct frame_id a_frame_id)
+{
+ struct frame_info *selected_frame_info = NULL;
+
+ if (frame_id_eq (a_frame_id, null_frame_id))
+ return;
+
+ if ((selected_frame_info = frame_find_by_id (a_frame_id)) != NULL)
+ {
+ select_frame (selected_frame_info);
}
}
struct current_thread_cleanup
{
ptid_t inferior_ptid;
+ struct frame_id selected_frame_id;
};
static void
{
struct current_thread_cleanup *old = arg;
restore_current_thread (old->inferior_ptid);
+ restore_selected_frame (old->selected_frame_id);
xfree (old);
}
static struct cleanup *
-make_cleanup_restore_current_thread (ptid_t inferior_ptid)
+make_cleanup_restore_current_thread (ptid_t inferior_ptid,
+ struct frame_id a_frame_id)
{
struct current_thread_cleanup *old
= xmalloc (sizeof (struct current_thread_cleanup));
old->inferior_ptid = inferior_ptid;
+ old->selected_frame_id = a_frame_id;
return make_cleanup (do_restore_current_thread_cleanup, old);
}
struct cleanup *old_chain;
struct cleanup *saved_cmd_cleanup_chain;
char *saved_cmd;
+ struct frame_id saved_frame_id;
+ ptid_t current_ptid;
+ int thread_has_changed = 0;
if (cmd == NULL || *cmd == '\000')
error (_("Please specify a command following the thread ID list"));
-
- old_chain = make_cleanup_restore_current_thread (inferior_ptid);
+
+ current_ptid = inferior_ptid;
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
/* It is safe to update the thread list now, before
traversing it for "thread apply all". MVS */
strcpy (cmd, saved_cmd); /* Restore exact command used previously */
}
+ if (!ptid_equal (current_ptid, inferior_ptid))
+ thread_has_changed = 1;
+
do_cleanups (saved_cmd_cleanup_chain);
do_cleanups (old_chain);
+ /* Print stack frame only if we changed thread. */
+ if (thread_has_changed)
+ print_stack_frame (get_current_frame (), 1, SRC_LINE);
+
}
static void
struct cleanup *old_chain;
struct cleanup *saved_cmd_cleanup_chain;
char *saved_cmd;
+ struct frame_id saved_frame_id;
+ ptid_t current_ptid;
+ int thread_has_changed = 0;
if (tidlist == NULL || *tidlist == '\000')
error (_("Please specify a thread ID list"));
if (*cmd == '\000')
error (_("Please specify a command following the thread ID list"));
- old_chain = make_cleanup_restore_current_thread (inferior_ptid);
+ current_ptid = inferior_ptid;
+ saved_frame_id = get_frame_id (get_selected_frame (NULL));
+ old_chain = make_cleanup_restore_current_thread (inferior_ptid, saved_frame_id);
/* Save a copy of the command in case it is clobbered by
execute_command */
}
}
+ if (!ptid_equal (current_ptid, inferior_ptid))
+ thread_has_changed = 1;
+
do_cleanups (saved_cmd_cleanup_chain);
do_cleanups (old_chain);
+ /* Print stack frame only if we changed thread. */
+ if (thread_has_changed)
+ print_stack_frame (get_current_frame (), 1, SRC_LINE);
}
/* Switch to the specified thread. Will dispatch off to thread_apply_command
enum gdb_rc
gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
{
- return catch_exceptions_with_msg (uiout, do_captured_thread_select, tidstr,
- error_message, RETURN_MASK_ALL);
+ if (catch_exceptions_with_msg (uiout, do_captured_thread_select, tidstr,
+ error_message, RETURN_MASK_ALL) < 0)
+ return GDB_RC_FAIL;
+ return GDB_RC_OK;
}
/* Commands with a prefix of `thread'. */