/* Multi-process/thread control for GDB, the GNU debugger.
- Copyright 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "symtab.h"
#include "value.h"
#include "target.h"
#include "gdbthread.h"
+#include "exceptions.h"
#include "command.h"
#include "gdbcmd.h"
#include "regcache.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? */
/* Official gdblib interface function to get a list of thread ids and
the total number. */
enum gdb_rc
-gdb_list_thread_ids (struct ui_out *uiout)
+gdb_list_thread_ids (struct ui_out *uiout, char **error_message)
{
- return catch_exceptions (uiout, do_captured_list_thread_ids, NULL,
- NULL, 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 *prev_pc,
int *trap_expected,
struct breakpoint **step_resume_breakpoint,
- struct breakpoint **through_sigtramp_breakpoint,
CORE_ADDR *step_range_start,
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 *stepping_through_sigtramp,
int *current_line,
- struct symtab **current_symtab, CORE_ADDR *step_sp)
+ struct symtab **current_symtab)
{
struct thread_info *tp;
*prev_pc = tp->prev_pc;
*trap_expected = tp->trap_expected;
*step_resume_breakpoint = tp->step_resume_breakpoint;
- *through_sigtramp_breakpoint = tp->through_sigtramp_breakpoint;
*step_range_start = tp->step_range_start;
*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 =
tp->stepping_through_solib_catchpoints;
- *stepping_through_sigtramp = tp->stepping_through_sigtramp;
*current_line = tp->current_line;
*current_symtab = tp->current_symtab;
- *step_sp = tp->step_sp;
}
/* Save infrun state for the thread PID. */
CORE_ADDR prev_pc,
int trap_expected,
struct breakpoint *step_resume_breakpoint,
- struct breakpoint *through_sigtramp_breakpoint,
CORE_ADDR step_range_start,
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 stepping_through_sigtramp,
int current_line,
- struct symtab *current_symtab, CORE_ADDR step_sp)
+ struct symtab *current_symtab)
{
struct thread_info *tp;
tp->prev_pc = prev_pc;
tp->trap_expected = trap_expected;
tp->step_resume_breakpoint = step_resume_breakpoint;
- tp->through_sigtramp_breakpoint = through_sigtramp_breakpoint;
tp->step_range_start = step_range_start;
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->stepping_through_sigtramp = stepping_through_sigtramp;
tp->current_line = current_line;
tp->current_symtab = current_symtab;
- tp->step_sp = step_sp;
}
/* Return true if TP is an active thread. */
struct thread_info *tp;
ptid_t current_ptid;
struct frame_info *cur_frame;
- int saved_frame_level = frame_relative_level (deprecated_selected_frame);
- int counter;
+ struct cleanup *old_chain;
+ struct frame_id saved_frame_id;
char *extra_info;
- /* Avoid coredumps which would happen if we tried to access a NULL
- deprecated_selected_frame. */
- if (!target_has_stack)
- error ("No stack.");
+ /* 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 ();
else
printf_filtered (" ");
-#ifdef HPUXHPPA
printf_filtered ("%d %s", tp->num, target_tid_to_str (tp->ptid));
-#else
- printf_filtered ("%d %s", tp->num, target_pid_to_str (tp->ptid));
-#endif
extra_info = target_extra_thread_info (tp);
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);
- if (deprecated_selected_frame)
- print_stack_frame (deprecated_selected_frame, -1, 0);
- else
- printf_filtered ("[No stack.]\n");
+ print_stack_frame (get_selected_frame (NULL), 0, LOCATION);
}
- switch_to_thread (current_ptid);
-
- /* Code below copied from "up_silently_base" in "stack.c".
- * It 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).
- */
- counter = saved_frame_level;
- cur_frame = find_relative_frame (deprecated_selected_frame, &counter);
- if (counter != 0)
- {
- /* Ooops, can't restore, tell user where we are. */
- warning ("Couldn't restore frame in current thread, at frame 0");
- print_stack_frame (deprecated_selected_frame, -1, 0);
- }
- else
+ /* Restores the current thread and the frame selected before
+ the "info threads" command. */
+ do_cleanups (old_chain);
+
+ /* 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)
{
- select_frame (cur_frame);
+ warning (_("Couldn't restore frame in current thread, at frame 0"));
+ print_stack_frame (get_selected_frame (NULL), 0, LOCATION);
}
-
- /* 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 (), 0, -1);
+ }
+}
+
+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);
+ error (_("Please specify a command following the thread ID list"));
+
+ 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 */
if (thread_alive (tp))
{
switch_to_thread (tp->ptid);
-#ifdef HPUXHPPA
- printf_filtered ("\nThread %d (%s):\n",
+ printf_filtered (_("\nThread %d (%s):\n"),
tp->num, target_tid_to_str (inferior_ptid));
-#else
- printf_filtered ("\nThread %d (%s):\n", tp->num,
- target_pid_to_str (inferior_ptid));
-#endif
execute_command (cmd, from_tty);
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");
+ error (_("Please specify a thread ID list"));
for (cmd = tidlist; *cmd != '\000' && !isalpha (*cmd); cmd++);
if (*cmd == '\000')
- error ("Please specify a command following the thread ID list");
+ 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 */
start = strtol (tidlist, &p, 10);
if (p == tidlist)
- error ("Error parsing %s", tidlist);
+ error (_("Error parsing %s"), tidlist);
tidlist = p;
while (*tidlist == ' ' || *tidlist == '\t')
tidlist++; /* Skip the - */
end = strtol (tidlist, &p, 10);
if (p == tidlist)
- error ("Error parsing %s", tidlist);
+ error (_("Error parsing %s"), tidlist);
tidlist = p;
while (*tidlist == ' ' || *tidlist == '\t')
tp = find_thread_id (start);
if (!tp)
- warning ("Unknown thread %d.", start);
+ warning (_("Unknown thread %d."), start);
else if (!thread_alive (tp))
- warning ("Thread %d has terminated.", start);
+ warning (_("Thread %d has terminated."), start);
else
{
switch_to_thread (tp->ptid);
-#ifdef HPUXHPPA
- printf_filtered ("\nThread %d (%s):\n", tp->num,
+ printf_filtered (_("\nThread %d (%s):\n"), tp->num,
target_tid_to_str (inferior_ptid));
-#else
- printf_filtered ("\nThread %d (%s):\n", tp->num,
- target_pid_to_str (inferior_ptid));
-#endif
execute_command (cmd, from_tty);
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);
}
/* Switch to the specified thread. Will dispatch off to thread_apply_command
{
/* Don't generate an error, just say which thread is current. */
if (target_has_stack)
- printf_filtered ("[Current thread is %d (%s)]\n",
+ printf_filtered (_("[Current thread is %d (%s)]\n"),
pid_to_thread_id (inferior_ptid),
-#if defined(HPUXHPPA)
- target_tid_to_str (inferior_ptid)
-#else
- target_pid_to_str (inferior_ptid)
-#endif
- );
+ target_tid_to_str (inferior_ptid));
else
- error ("No stack.");
+ error (_("No stack."));
return;
}
- gdb_thread_select (uiout, tidstr);
+ gdb_thread_select (uiout, tidstr, NULL);
}
static int
tp = find_thread_id (num);
if (!tp)
- error ("Thread ID %d not known.", num);
+ error (_("Thread ID %d not known."), num);
if (!thread_alive (tp))
- error ("Thread ID %d has terminated.\n", num);
+ error (_("Thread ID %d has terminated."), num);
switch_to_thread (tp->ptid);
ui_out_text (uiout, "[Switching to thread ");
ui_out_field_int (uiout, "new-thread-id", pid_to_thread_id (inferior_ptid));
ui_out_text (uiout, " (");
-#if defined(HPUXHPPA)
ui_out_text (uiout, target_tid_to_str (inferior_ptid));
-#else
- ui_out_text (uiout, target_pid_to_str (inferior_ptid));
-#endif
ui_out_text (uiout, ")]");
- print_stack_frame (deprecated_selected_frame,
- frame_relative_level (deprecated_selected_frame), 1);
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
return GDB_RC_OK;
}
enum gdb_rc
-gdb_thread_select (struct ui_out *uiout, char *tidstr)
+gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
{
- return catch_exceptions (uiout, do_captured_thread_select, tidstr,
- NULL, 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'. */
static struct cmd_list_element *thread_apply_list = NULL;
add_info ("threads", info_threads_command,
- "IDs of currently known threads.");
+ _("IDs of currently known threads."));
- add_prefix_cmd ("thread", class_run, thread_command,
- "Use this command to switch between threads.\n\
-The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1, &cmdlist);
+ add_prefix_cmd ("thread", class_run, thread_command, _("\
+Use this command to switch between threads.\n\
+The new thread ID must be currently known."),
+ &thread_cmd_list, "thread ", 1, &cmdlist);
add_prefix_cmd ("apply", class_run, thread_apply_command,
- "Apply a command to a list of threads.",
- &thread_apply_list, "apply ", 1, &thread_cmd_list);
+ _("Apply a command to a list of threads."),
+ &thread_apply_list, "thread apply ", 1, &thread_cmd_list);
add_cmd ("all", class_run, thread_apply_all_command,
- "Apply a command to all threads.", &thread_apply_list);
+ _("Apply a command to all threads."), &thread_apply_list);
if (!xdb_commands)
add_com_alias ("t", "thread", class_run, 1);