Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "arch-utils.h"
#include <signal.h>
#include "gdb_string.h"
#include "symtab.h"
#include "cli/cli-decode.h"
#include "gdbthread.h"
#include "valprint.h"
+#include "inline-frame.h"
+#include "tracepoint.h"
+#include "inf-loop.h"
+#include "continuations.h"
/* Functions exported for general use, in inferior.h: */
static void jump_command (char *, int);
static void step_1 (int, int, char *);
-static void step_once (int skip_subroutines, int single_inst, int count, int thread);
+static void step_once (int skip_subroutines, int single_inst,
+ int count, int thread);
static void next_command (char *, int);
#define ERROR_NO_INFERIOR \
if (!target_has_execution) error (_("The program is not being run."));
-/* String containing arguments to give to the program, separated by spaces.
- Empty string (pointer to '\0') means no args. */
+/* Scratch area where string containing arguments to give to the
+ program will be stored by 'set args'. As soon as anything is
+ stored, notice_args_set will move it into per-inferior storage.
+ Arguments are separated by spaces. Empty string (pointer to '\0')
+ means no args. */
-static char *inferior_args;
+static char *inferior_args_scratch;
-/* The inferior arguments as a vector. If INFERIOR_ARGC is nonzero,
- then we must compute INFERIOR_ARGS from this (via the target). */
+/* Scratch area where 'set inferior-tty' will store user-provided value.
+ We'll immediate copy it into per-inferior storage. */
-static int inferior_argc;
-static char **inferior_argv;
-
-/* File name for default use for standard in/out in the inferior. */
-
-static char *inferior_io_terminal;
+static char *inferior_io_terminal_scratch;
/* Pid of our debugged inferior, or 0 if no inferior now.
Since various parts of infrun.c test this to see whether there is a program
/* Nonzero if stopped due to completion of a stack dummy routine. */
-int stop_stack_dummy;
+enum stop_stack_kind stop_stack_dummy;
/* Nonzero if stopped due to a random (unexpected) signal in inferior
process. */
int stopped_by_random_signal;
-/* Environment to use for running inferior,
- in format described in environ.h. */
-
-struct gdb_environ *inferior_environ;
\f
-/* Accessor routines. */
+/* Accessor routines. */
+
+/* Set the io terminal for the current inferior. Ownership of
+ TERMINAL_NAME is not transferred. */
void
set_inferior_io_terminal (const char *terminal_name)
{
- if (inferior_io_terminal)
- xfree (inferior_io_terminal);
-
- if (!terminal_name)
- inferior_io_terminal = NULL;
- else
- inferior_io_terminal = savestring (terminal_name, strlen (terminal_name));
+ xfree (current_inferior ()->terminal);
+ current_inferior ()->terminal = terminal_name ? xstrdup (terminal_name) : 0;
}
const char *
get_inferior_io_terminal (void)
{
- return inferior_io_terminal;
+ return current_inferior ()->terminal;
+}
+
+static void
+set_inferior_tty_command (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ /* CLI has assigned the user-provided value to inferior_io_terminal_scratch.
+ Now route it to current inferior. */
+ set_inferior_io_terminal (inferior_io_terminal_scratch);
+}
+
+static void
+show_inferior_tty_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ /* Note that we ignore the passed-in value in favor of computing it
+ directly. */
+ const char *inferior_io_terminal = get_inferior_io_terminal ();
+
+ if (inferior_io_terminal == NULL)
+ inferior_io_terminal = "";
+ fprintf_filtered (gdb_stdout,
+ _("Terminal for future runs of program being debugged "
+ "is \"%s\".\n"), inferior_io_terminal);
}
char *
get_inferior_args (void)
{
- if (inferior_argc != 0)
+ if (current_inferior ()->argc != 0)
{
- char *n, *old;
+ char *n;
- n = gdbarch_construct_inferior_arguments (current_gdbarch,
- inferior_argc, inferior_argv);
- old = set_inferior_args (n);
- xfree (old);
+ n = construct_inferior_arguments (current_inferior ()->argc,
+ current_inferior ()->argv);
+ set_inferior_args (n);
+ xfree (n);
}
- if (inferior_args == NULL)
- inferior_args = xstrdup ("");
+ if (current_inferior ()->args == NULL)
+ current_inferior ()->args = xstrdup ("");
- return inferior_args;
+ return current_inferior ()->args;
}
-char *
+/* Set the arguments for the current inferior. Ownership of
+ NEWARGS is not transferred. */
+
+void
set_inferior_args (char *newargs)
{
- char *saved_args = inferior_args;
-
- inferior_args = newargs;
- inferior_argc = 0;
- inferior_argv = 0;
-
- return saved_args;
+ xfree (current_inferior ()->args);
+ current_inferior ()->args = newargs ? xstrdup (newargs) : NULL;
+ current_inferior ()->argc = 0;
+ current_inferior ()->argv = 0;
}
void
set_inferior_args_vector (int argc, char **argv)
{
- inferior_argc = argc;
- inferior_argv = argv;
+ current_inferior ()->argc = argc;
+ current_inferior ()->argv = argv;
}
/* Notice when `set args' is run. */
static void
-notice_args_set (char *args, int from_tty, struct cmd_list_element *c)
+set_args_command (char *args, int from_tty, struct cmd_list_element *c)
{
- inferior_argc = 0;
- inferior_argv = 0;
+ /* CLI has assigned the user-provided value to inferior_args_scratch.
+ Now route it to current inferior. */
+ set_inferior_args (inferior_args_scratch);
}
/* Notice when `show args' is run. */
static void
-notice_args_read (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
+show_args_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
/* Note that we ignore the passed-in value in favor of computing it
directly. */
/* Compute command-line string given argument vector. This does the
same shell processing as fork_inferior. */
char *
-construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
+construct_inferior_arguments (int argc, char **argv)
{
char *result;
if (cp == NULL)
cp = strchr (argv[i], '\n');
if (cp != NULL)
- error (_("can't handle command-line argument containing whitespace"));
+ error (_("can't handle command-line "
+ "argument containing whitespace"));
length += strlen (argv[i]) + 1;
}
/* This function detects whether or not a '&' character (indicating
background execution) has been added as *the last* of the arguments ARGS
- of a command. If it has, it removes it and returns 1. Otherwise it
- does nothing and returns 0. */
+ of a command. If it has, it removes it and returns 1. Otherwise it
+ does nothing and returns 0. */
static int
strip_bg_char (char **args)
{
return 0;
}
-void
-tty_command (char *file, int from_tty)
-{
- if (file == 0)
- error_no_arg (_("terminal name for running target process"));
-
- set_inferior_io_terminal (file);
-}
-
/* Common actions to take after creating any sort of inferior, by any
means (running, attaching, connecting, et cetera). The target
should be stopped. */
void
post_create_inferior (struct target_ops *target, int from_tty)
{
+ volatile struct gdb_exception ex;
+
/* Be sure we own the terminal in case write operations are performed. */
target_terminal_ours ();
don't need to. */
target_find_description ();
- /* Now that we know the register layout, retrieve current PC. */
- stop_pc = regcache_read_pc (get_current_regcache ());
-
- /* If the solist is global across processes, there's no need to
- refetch it here. */
- if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
+ /* Now that we know the register layout, retrieve current PC. But
+ if the PC is unavailable (e.g., we're opening a core file with
+ missing registers info), ignore it. */
+ stop_pc = 0;
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
{
- /* Sometimes the platform-specific hook loads initial shared
- libraries, and sometimes it doesn't. Try to do so first, so
- that we can add them with the correct value for FROM_TTY.
- If we made all the inferior hook methods consistent,
- this call could be removed. */
-#ifdef SOLIB_ADD
- SOLIB_ADD (NULL, from_tty, target, auto_solib_add);
-#else
- solib_add (NULL, from_tty, target, auto_solib_add);
-#endif
+ stop_pc = regcache_read_pc (get_current_regcache ());
}
+ if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
if (exec_bfd)
{
#ifdef SOLIB_CREATE_INFERIOR_HOOK
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
#else
- solib_create_inferior_hook ();
+ solib_create_inferior_hook (from_tty);
+#endif
+ }
+
+ /* If the solist is global across processes, there's no need to
+ refetch it here. */
+ if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
+ {
+ /* Sometimes the platform-specific hook loads initial shared
+ libraries, and sometimes it doesn't. If it doesn't FROM_TTY will be
+ incorrectly 0 but such solib targets should be fixed anyway. If we
+ made all the inferior hook methods consistent, this call could be
+ removed. Call it only after the solib target has been initialized by
+ solib_create_inferior_hook. */
+
+#ifdef SOLIB_ADD
+ SOLIB_ADD (NULL, 0, target, auto_solib_add);
+#else
+ solib_add (NULL, 0, target, auto_solib_add);
#endif
}
+ /* If the user sets watchpoints before execution having started,
+ then she gets software watchpoints, because GDB can't know which
+ target will end up being pushed, or if it supports hardware
+ watchpoints or not. breakpoint_re_set takes care of promoting
+ watchpoints to hardware watchpoints if possible, however, if this
+ new inferior doesn't load shared libraries or we don't pull in
+ symbols from any other source on this target/arch,
+ breakpoint_re_set is never called. Call it now so that software
+ watchpoints get a chance to be promoted to hardware watchpoints
+ if the now pushed target supports hardware watchpoints. */
+ breakpoint_re_set ();
+
observer_notify_inferior_created (target, from_tty);
}
}
}
-/* Implement the "run" command. If TBREAK_AT_MAIN is set, then insert
+/* Implement the "run" command. If TBREAK_AT_MAIN is set, then insert
a temporary breakpoint at the begining of the main program before
running the program. */
int async_exec = strip_bg_char (&args);
/* If we get a request for running in the bg but the target
- doesn't support it, error out. */
+ doesn't support it, error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
/* If we don't get a request of running in the bg, then we need
- to simulate synchronous (fg) execution. */
+ to simulate synchronous (fg) execution. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
}
- /* If there were other args, beside '&', process them. */
+ /* If there were other args, beside '&', process them. */
if (args)
- {
- char *old_args = set_inferior_args (xstrdup (args));
- xfree (old_args);
- }
+ set_inferior_args (args);
}
if (from_tty)
/* We call get_inferior_args() because we might need to compute
the value now. */
target_create_inferior (exec_file, get_inferior_args (),
- environ_vector (inferior_environ), from_tty);
+ environ_vector (current_inferior ()->environment),
+ from_tty);
/* We're starting off a new process. When we get out of here, in
non-stop mode, finish the state of all threads of that process,
has done its thing; now we are setting up the running program. */
post_create_inferior (¤t_target, 0);
- /* Start the target running. */
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+ /* Start the target running. Do not use -1 continuation as it would skip
+ breakpoint right at the entry point. */
+ proceed (regcache_read_pc (get_current_regcache ()), TARGET_SIGNAL_0, 0);
/* Since there was no error, there's no need to finish the thread
states here. */
static void
run_no_args_command (char *args, int from_tty)
{
- char *old_args = set_inferior_args (xstrdup (""));
- xfree (old_args);
+ set_inferior_args ("");
}
\f
{
if (ptid_equal (inferior_ptid, null_ptid)
|| is_exited (inferior_ptid))
- error (_("\
-Cannot execute this command without a live selected thread."));
+ error (_("Cannot execute this command without a live selected thread."));
+}
+
+/* If the user is looking at trace frames, any resumption of execution
+ is likely to mix up recorded and live target data. So simply
+ disallow those commands. */
+
+void
+ensure_not_tfind_mode (void)
+{
+ if (get_traceframe_number () >= 0)
+ error (_("Cannot execute this command while looking at trace frames."));
}
void
continue_1 (int all_threads)
{
ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
if (non_stop && all_threads)
{
/* Don't error out if the current thread is running, because
- there may be other stopped threads. */
+ there may be other stopped threads. */
struct cleanup *old_chain;
/* Backup current thread and selected frame. */
int all_threads = 0;
ERROR_NO_INFERIOR;
- /* Find out whether we must run in the background. */
+ /* Find out whether we must run in the background. */
if (args != NULL)
async_exec = strip_bg_char (&args);
/* If we must run in the background, but the target can't do it,
- error out. */
+ error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
/* If we are not asked to run in the bg, then prepare to run in the
- foreground, synchronously. */
+ foreground, synchronously. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
}
error (_("`-a' is meaningless in all-stop mode."));
if (args != NULL && all_threads)
- error (_("\
-Can't resume all threads and specify proceed count simultaneously."));
+ error (_("Can't resume all threads and specify "
+ "proceed count simultaneously."));
/* If we have an argument left, set proceed count of breakpoint we
stopped at. */
struct thread_info *tp;
if (non_stop)
- tp = find_thread_pid (inferior_ptid);
+ tp = find_thread_ptid (inferior_ptid);
else
{
ptid_t last_ptid;
struct target_waitstatus ws;
get_last_target_status (&last_ptid, &ws);
- tp = find_thread_pid (last_ptid);
+ tp = find_thread_ptid (last_ptid);
}
if (tp != NULL)
- bs = tp->stop_bpstat;
+ bs = tp->control.stop_bpstat;
while ((stat = bpstat_num (&bs, &num)) != 0)
if (stat > 0)
continue_1 (all_threads);
}
\f
+/* Record the starting point of a "step" or "next" command. */
+
+static void
+set_step_frame (void)
+{
+ struct symtab_and_line sal;
+
+ find_frame_sal (get_current_frame (), &sal);
+ set_step_info (get_current_frame (), sal);
+}
+
/* Step until outside of current statement. */
static void
step_1 (1, 1, count_string);
}
-static void
+void
delete_longjmp_breakpoint_cleanup (void *arg)
{
int thread = * (int *) arg;
step_1 (int skip_subroutines, int single_inst, char *count_string)
{
int count = 1;
- struct frame_info *frame;
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
int async_exec = 0;
int thread = -1;
ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
ensure_valid_thread ();
ensure_not_running ();
async_exec = strip_bg_char (&count_string);
/* If we get a request for running in the bg but the target
- doesn't support it, error out. */
+ doesn't support it, error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
/* If we don't get a request of running in the bg, then we need
- to simulate synchronous (fg) execution. */
+ to simulate synchronous (fg) execution. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
}
count = count_string ? parse_and_eval_long (count_string) : 1;
- if (!single_inst || skip_subroutines) /* leave si command alone */
+ if (!single_inst || skip_subroutines) /* Leave si command alone. */
{
+ struct thread_info *tp = inferior_thread ();
+
if (in_thread_list (inferior_ptid))
thread = pid_to_thread_id (inferior_ptid);
- set_longjmp_breakpoint ();
+ set_longjmp_breakpoint (tp, get_frame_id (get_current_frame ()));
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
{
for (; count > 0; count--)
{
- struct thread_info *tp;
step_once (skip_subroutines, single_inst, count, thread);
- if (target_has_execution
- && !ptid_equal (inferior_ptid, null_ptid))
- tp = inferior_thread ();
+ if (!target_has_execution)
+ break;
else
- tp = NULL;
-
- if (!tp || !tp->stop_step || !tp->step_multi)
{
- /* If we stopped for some reason that is not stepping
- there are no further steps to make. */
- if (tp)
- tp->step_multi = 0;
- break;
+ struct thread_info *tp = inferior_thread ();
+
+ if (!tp->control.stop_step || !tp->step_multi)
+ {
+ /* If we stopped for some reason that is not stepping
+ there are no further steps to make. */
+ tp->step_multi = 0;
+ break;
+ }
}
}
/* Called after we are done with one step operation, to check whether
we need to step again, before we print the prompt and return control
- to the user. If count is > 1, we will need to do one more call to
- proceed(), via step_once(). Basically it is like step_once and
- step_1_continuation are co-recursive. */
+ to the user. If count is > 1, we will need to do one more call to
+ proceed(), via step_once(). Basically it is like step_once and
+ step_1_continuation are co-recursive. */
static void
-step_1_continuation (void *args)
+step_1_continuation (void *args, int err)
{
struct step_1_continuation_args *a = args;
struct thread_info *tp;
tp = inferior_thread ();
- if (tp->step_multi && tp->stop_step)
+ if (!err
+ && tp->step_multi && tp->control.stop_step)
{
/* There are more steps to make, and we did stop due to
ending a stepping range. Do another step. */
tp->step_multi = 0;
}
- /* We either stopped for some reason that is not stepping, or there
- are no further steps to make. Cleanup. */
+ /* We either hit an error, or stopped for some reason that is
+ not stepping, or there are no further steps to make.
+ Cleanup. */
if (!a->single_inst || a->skip_subroutines)
delete_longjmp_breakpoint (a->thread);
}
static void
step_once (int skip_subroutines, int single_inst, int count, int thread)
{
- struct frame_info *frame;
+ struct frame_info *frame = get_current_frame ();
if (count > 0)
{
INFERIOR_PTID thread instead, which is the same thread when
THREAD is set. */
struct thread_info *tp = inferior_thread ();
- clear_proceed_status ();
- frame = get_current_frame ();
- tp->step_frame_id = get_frame_id (frame);
+ clear_proceed_status ();
+ set_step_frame ();
if (!single_inst)
{
CORE_ADDR pc;
+ /* Step at an inlined function behaves like "down". */
+ if (!skip_subroutines && !single_inst
+ && inline_skipped_frames (inferior_ptid))
+ {
+ ptid_t resume_ptid;
+
+ /* Pretend that we've ran. */
+ resume_ptid = user_visible_resume_ptid (1);
+ set_running (resume_ptid, 1);
+
+ step_into_inline_frame (inferior_ptid);
+ if (count > 1)
+ step_once (skip_subroutines, single_inst, count - 1, thread);
+ else
+ {
+ /* Pretend that we've stopped. */
+ normal_stop ();
+
+ if (target_can_async_p ())
+ inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+ }
+ return;
+ }
+
pc = get_frame_pc (frame);
find_pc_line_pc_range (pc,
- &tp->step_range_start, &tp->step_range_end);
+ &tp->control.step_range_start,
+ &tp->control.step_range_end);
/* If we have no line info, switch to stepi mode. */
- if (tp->step_range_end == 0 && step_stop_if_no_debug)
- {
- tp->step_range_start = tp->step_range_end = 1;
- }
- else if (tp->step_range_end == 0)
+ if (tp->control.step_range_end == 0 && step_stop_if_no_debug)
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+ else if (tp->control.step_range_end == 0)
{
char *name;
+
if (find_pc_partial_function (pc, &name,
- &tp->step_range_start,
- &tp->step_range_end) == 0)
+ &tp->control.step_range_start,
+ &tp->control.step_range_end) == 0)
error (_("Cannot find bounds of current function"));
target_terminal_ours ();
- printf_filtered (_("\
-Single stepping until exit from function %s, \n\
-which has no line number information.\n"), name);
+ printf_filtered (_("Single stepping until exit from function %s,"
+ "\nwhich has no line number information.\n"),
+ name);
}
}
else
{
/* Say we are stepping, but stop after one insn whatever it does. */
- tp->step_range_start = tp->step_range_end = 1;
+ tp->control.step_range_start = tp->control.step_range_end = 1;
if (!skip_subroutines)
/* It is stepi.
Don't step over function calls, not even to functions lacking
line numbers. */
- tp->step_over_calls = STEP_OVER_NONE;
+ tp->control.step_over_calls = STEP_OVER_NONE;
}
if (skip_subroutines)
- tp->step_over_calls = STEP_OVER_ALL;
+ tp->control.step_over_calls = STEP_OVER_ALL;
tp->step_multi = (count > 1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
static void
jump_command (char *arg, int from_tty)
{
+ struct gdbarch *gdbarch = get_current_arch ();
CORE_ADDR addr;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
int async_exec = 0;
ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
ensure_valid_thread ();
ensure_not_running ();
- /* Find out whether we must run in the background. */
+ /* Find out whether we must run in the background. */
if (arg != NULL)
async_exec = strip_bg_char (&arg);
/* If we must run in the background, but the target can't do it,
- error out. */
+ error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (sal.symtab == 0 && sal.pc == 0)
error (_("No source file has been specified."));
- resolve_sal_pc (&sal); /* May error out */
+ resolve_sal_pc (&sal); /* May error out. */
- /* See if we are trying to jump to another function. */
+ /* See if we are trying to jump to another function. */
fn = get_frame_function (get_current_frame ());
sfn = find_pc_function (sal.pc);
if (fn != NULL && sfn != fn)
if (section_is_overlay (SYMBOL_OBJ_SECTION (sfn)) &&
!section_is_mapped (SYMBOL_OBJ_SECTION (sfn)))
{
- if (!query (_("WARNING!!! Destination is in unmapped overlay! Jump anyway? ")))
+ if (!query (_("WARNING!!! Destination is in "
+ "unmapped overlay! Jump anyway? ")))
{
error (_("Not confirmed."));
/* NOTREACHED */
if (from_tty)
{
printf_filtered (_("Continuing at "));
- fputs_filtered (paddress (addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, addr), gdb_stdout);
printf_filtered (".\n");
}
/* If we are not asked to run in the bg, then prepare to run in the
- foreground, synchronously. */
+ foreground, synchronously. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
}
}
\f
-/* Go to line or address in current procedure */
+/* Go to line or address in current procedure. */
static void
go_command (char *line_no, int from_tty)
{
dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
ensure_valid_thread ();
ensure_not_running ();
proceed ((CORE_ADDR) -1, oursig, 0);
}
+/* Continuation args to be passed to the "until" command
+ continuation. */
+struct until_next_continuation_args
+{
+ /* The thread that was current when the command was executed. */
+ int thread;
+};
+
+/* A continuation callback for until_next_command. */
+
+static void
+until_next_continuation (void *arg, int err)
+{
+ struct until_next_continuation_args *a = arg;
+
+ delete_longjmp_breakpoint (a->thread);
+}
+
/* Proceed until we reach a different source line with pc greater than
our current one or exit the function. We skip calls in both cases.
struct symbol *func;
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
+ int thread = tp->num;
+ struct cleanup *old_chain;
clear_proceed_status ();
+ set_step_frame ();
frame = get_current_frame ();
/* Step until either exited from this function or greater
than the current line (if in symbolic section) or pc (if
- not). */
+ not). */
pc = get_frame_pc (frame);
func = find_pc_function (pc);
if (msymbol == NULL)
error (_("Execution is not within a known function."));
- tp->step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
- tp->step_range_end = pc;
+ tp->control.step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
+ tp->control.step_range_end = pc;
}
else
{
sal = find_pc_line (pc, 0);
- tp->step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
- tp->step_range_end = sal.end;
+ tp->control.step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
+ tp->control.step_range_end = sal.end;
}
- tp->step_over_calls = STEP_OVER_ALL;
- tp->step_frame_id = get_frame_id (frame);
+ tp->control.step_over_calls = STEP_OVER_ALL;
tp->step_multi = 0; /* Only one call to proceed */
+ set_longjmp_breakpoint (tp, get_frame_id (frame));
+ old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+
+ if (target_can_async_p () && is_running (inferior_ptid))
+ {
+ struct until_next_continuation_args *cont_args;
+
+ discard_cleanups (old_chain);
+ cont_args = XNEW (struct until_next_continuation_args);
+ cont_args->thread = inferior_thread ()->num;
+
+ add_continuation (tp, until_next_continuation, cont_args, xfree);
+ }
+ else
+ do_cleanups (old_chain);
}
static void
{
int async_exec = 0;
- if (!target_has_execution)
- error (_("The program is not running."));
+ ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
+ ensure_valid_thread ();
+ ensure_not_running ();
- /* Find out whether we must run in the background. */
+ /* Find out whether we must run in the background. */
if (arg != NULL)
async_exec = strip_bg_char (&arg);
/* If we must run in the background, but the target can't do it,
- error out. */
+ error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
/* If we are not asked to run in the bg, then prepare to run in the
- foreground, synchronously. */
+ foreground, synchronously. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
}
{
int async_exec = 0;
- if (!target_has_execution)
- error (_("The program is not running."));
+ ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
+ ensure_valid_thread ();
+ ensure_not_running ();
if (arg == NULL)
error_no_arg (_("a location"));
static void
print_return_value (struct type *func_type, struct type *value_type)
{
- struct gdbarch *gdbarch = current_gdbarch;
+ struct gdbarch *gdbarch = get_regcache_arch (stop_registers);
struct cleanup *old_chain;
struct ui_stream *stb;
struct value *value;
/* FIXME: 2003-09-27: When returning from a nested inferior function
call, it's possible (with no help from the architecture vector)
to locate and return/print a "struct return" value. This is just
- a more complicated case of what is already being done in in the
+ a more complicated case of what is already being done in the
inferior function call code. In fact, when inferior function
calls are made async, this will likely be made the norm. */
impossible to do all the stuff as part of the finish_command
function itself. The only chance we have to complete this command
is in fetch_inferior_event, which is called by the event loop as
- soon as it detects that the target has stopped. This function is
- called via the cmd_continuation pointer. */
+ soon as it detects that the target has stopped. */
struct finish_command_continuation_args
{
+ /* The thread that as current when the command was executed. */
+ int thread;
struct breakpoint *breakpoint;
struct symbol *function;
};
static void
-finish_command_continuation (void *arg)
+finish_command_continuation (void *arg, int err)
{
struct finish_command_continuation_args *a = arg;
- struct thread_info *tp = NULL;
- bpstat bs = NULL;
- if (!ptid_equal (inferior_ptid, null_ptid)
- && target_has_execution
- && is_stopped (inferior_ptid))
+ if (!err)
{
- tp = inferior_thread ();
- bs = tp->stop_bpstat;
- }
+ struct thread_info *tp = NULL;
+ bpstat bs = NULL;
- if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
- && a->function != NULL)
- {
- struct type *value_type;
+ if (!ptid_equal (inferior_ptid, null_ptid)
+ && target_has_execution
+ && is_stopped (inferior_ptid))
+ {
+ tp = inferior_thread ();
+ bs = tp->control.stop_bpstat;
+ }
+
+ if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
+ && a->function != NULL)
+ {
+ struct type *value_type;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
+ if (!value_type)
+ internal_error (__FILE__, __LINE__,
+ _("finish_command: function has no target type"));
- value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
- if (!value_type)
- internal_error (__FILE__, __LINE__,
- _("finish_command: function has no target type"));
+ if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
+ {
+ volatile struct gdb_exception ex;
+
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ /* print_return_value can throw an exception in some
+ circumstances. We need to catch this so that we still
+ delete the breakpoint. */
+ print_return_value (SYMBOL_TYPE (a->function), value_type);
+ }
+ if (ex.reason < 0)
+ exception_print (gdb_stdout, ex);
+ }
+ }
- if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
- print_return_value (SYMBOL_TYPE (a->function), value_type);
+ /* We suppress normal call of normal_stop observer and do it
+ here so that the *stopped notification includes the return
+ value. */
+ if (bs != NULL && tp->control.proceed_to_finish)
+ observer_notify_normal_stop (bs, 1 /* print frame */);
}
- /* We suppress normal call of normal_stop observer and do it here so
- that the *stopped notification includes the return value. */
- if (bs != NULL && tp->proceed_to_finish)
- observer_notify_normal_stop (bs, 1 /* print frame */);
delete_breakpoint (a->breakpoint);
+ delete_longjmp_breakpoint (a->thread);
}
static void
{
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
- struct breakpoint *breakpoint;
- struct cleanup *old_chain;
CORE_ADDR pc;
CORE_ADDR func_addr;
- int back_up;
pc = get_frame_pc (get_current_frame ());
sal = find_pc_line (func_addr, 0);
- /* We don't need a return value. */
- tp->proceed_to_finish = 0;
+ tp->control.proceed_to_finish = 1;
/* Special case: if we're sitting at the function entry point,
then all we need to do is take a reverse singlestep. We
don't need to set a breakpoint, and indeed it would do us
if (sal.pc != pc)
{
- /* Set breakpoint and continue. */
- breakpoint =
- set_momentary_breakpoint (sal,
- get_frame_id (get_selected_frame (NULL)),
- bp_breakpoint);
- /* Tell the breakpoint to keep quiet. We won't be done
- until we've done another reverse single-step. */
- make_breakpoint_silent (breakpoint);
- old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ struct frame_info *frame = get_selected_frame (NULL);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct symtab_and_line sr_sal;
+
+ /* Set a step-resume at the function's entry point. Once that's
+ hit, we'll do one more step backwards. */
+ init_sal (&sr_sal);
+ sr_sal.pc = sal.pc;
+ sr_sal.pspace = get_frame_program_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
+
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
- /* We will be stopped when proceed returns. */
- back_up = bpstat_find_breakpoint (tp->stop_bpstat, breakpoint) != NULL;
- do_cleanups (old_chain);
}
else
- back_up = 1;
- if (back_up)
{
- /* If in fact we hit the step-resume breakpoint (and not
- some other breakpoint), then we're almost there --
- we just need to back up by one more single-step. */
- tp->step_range_start = tp->step_range_end = 1;
+ /* We're almost there -- we just need to back up by one more
+ single-step. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
}
- return;
}
/* finish_forward -- helper function for finish_command. */
static void
finish_forward (struct symbol *function, struct frame_info *frame)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
struct breakpoint *breakpoint;
struct cleanup *old_chain;
struct finish_command_continuation_args *cargs;
+ int thread = tp->num;
sal = find_pc_line (get_frame_pc (frame), 0);
sal.pc = get_frame_pc (frame);
- breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame),
+ breakpoint = set_momentary_breakpoint (gdbarch, sal,
+ get_stack_frame_id (frame),
bp_finish);
old_chain = make_cleanup_delete_breakpoint (breakpoint);
- tp->proceed_to_finish = 1; /* We want stop_registers, please... */
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ set_longjmp_breakpoint (tp, get_frame_id (frame));
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+ /* We want stop_registers, please... */
+ tp->control.proceed_to_finish = 1;
cargs = xmalloc (sizeof (*cargs));
+ cargs->thread = thread;
cargs->breakpoint = breakpoint;
cargs->function = function;
add_continuation (tp, finish_command_continuation, cargs,
finish_command_continuation_free_arg);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
discard_cleanups (old_chain);
if (!target_can_async_p ())
- do_all_continuations ();
+ do_all_continuations (0);
}
/* "finish": Set a temporary breakpoint at the place the selected
int async_exec = 0;
+ ERROR_NO_INFERIOR;
+ ensure_not_tfind_mode ();
+ ensure_valid_thread ();
+ ensure_not_running ();
+
/* Find out whether we must run in the background. */
if (arg != NULL)
async_exec = strip_bg_char (&arg);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
- /* Don't try to async in reverse. */
- if (async_exec && execution_direction == EXEC_REVERSE)
- error (_("Asynchronous 'finish' not supported in reverse."));
-
/* If we are not asked to run in the bg, then prepare to run in the
foreground, synchronously. */
if (!async_exec && target_can_async_p ())
if (arg)
error (_("The \"finish\" command does not take any arguments."));
- if (!target_has_execution)
- error (_("The program is not running."));
frame = get_prev_frame (get_selected_frame (_("No selected frame.")));
if (frame == 0)
clear_proceed_status ();
+ /* Finishing from an inline frame is completely different. We don't
+ try to show the "return value" - no way to locate it. So we do
+ not need a completion. */
+ if (get_frame_type (get_selected_frame (_("No selected frame.")))
+ == INLINE_FRAME)
+ {
+ /* Claim we are stepping in the calling frame. An empty step
+ range means that we will stop once we aren't in a function
+ called by that frame. We don't use the magic "1" value for
+ step_range_end, because then infrun will think this is nexti,
+ and not step over the rest of this inlined function call. */
+ struct thread_info *tp = inferior_thread ();
+ struct symtab_and_line empty_sal;
+
+ init_sal (&empty_sal);
+ set_step_info (frame, empty_sal);
+ tp->control.step_range_start = get_frame_pc (frame);
+ tp->control.step_range_end = tp->control.step_range_start;
+ tp->control.step_over_calls = STEP_OVER_ALL;
+
+ /* Print info on the selected frame, including level number but not
+ source. */
+ if (from_tty)
+ {
+ printf_filtered (_("Run till exit from "));
+ print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
+ }
+
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ return;
+ }
+
/* Find the function we will return from. */
function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
else
{
struct target_waitstatus ws;
+
get_last_target_status (&ptid, &ws);
}
else if (is_running (ptid))
error (_("Selected thread is running."));
- tp = find_thread_pid (ptid);
- bs = tp->stop_bpstat;
+ tp = find_thread_ptid (ptid);
+ bs = tp->control.stop_bpstat;
stat = bpstat_num (&bs, &num);
target_files_info ();
- printf_filtered (_("Program stopped at %s.\n"), paddress (stop_pc));
- if (tp->stop_step)
+ printf_filtered (_("Program stopped at %s.\n"),
+ paddress (target_gdbarch, stop_pc));
+ if (tp->control.stop_step)
printf_filtered (_("It stopped after being stepped.\n"));
else if (stat != 0)
{
{
if (stat < 0)
{
- printf_filtered (_("\
-It stopped at a breakpoint that has since been deleted.\n"));
+ printf_filtered (_("It stopped at a breakpoint "
+ "that has since been deleted.\n"));
}
else
printf_filtered (_("It stopped at breakpoint %d.\n"), num);
stat = bpstat_num (&bs, &num);
}
}
- else if (tp->stop_signal != TARGET_SIGNAL_0)
+ else if (tp->suspend.stop_signal != TARGET_SIGNAL_0)
{
printf_filtered (_("It stopped with signal %s, %s.\n"),
- target_signal_to_name (tp->stop_signal),
- target_signal_to_string (tp->stop_signal));
+ target_signal_to_name (tp->suspend.stop_signal),
+ target_signal_to_string (tp->suspend.stop_signal));
}
if (!from_tty)
{
- printf_filtered (_("\
-Type \"info stack\" or \"info registers\" for more information.\n"));
+ printf_filtered (_("Type \"info stack\" or \"info "
+ "registers\" for more information.\n"));
}
}
\f
{
if (var)
{
- char *val = get_in_environ (inferior_environ, var);
+ char *val = get_in_environ (current_inferior ()->environment, var);
+
if (val)
{
puts_filtered (var);
}
else
{
- char **vector = environ_vector (inferior_environ);
+ char **vector = environ_vector (current_inferior ()->environment);
+
while (*vector)
{
puts_filtered (*vector++);
if (arg == 0)
error_no_arg (_("environment variable and value"));
- /* Find seperation between variable name and value */
+ /* Find seperation between variable name and value. */
p = (char *) strchr (arg, '=');
val = (char *) strchr (arg, ' ');
{
/* We have both a space and an equals. If the space is before the
equals, walk forward over the spaces til we see a nonspace
- (possibly the equals). */
+ (possibly the equals). */
if (p > val)
while (*val == ' ')
val++;
{
nullset = 1;
if (p == 0)
- p = arg + strlen (arg); /* So that savestring below will work */
+ p = arg + strlen (arg); /* So that savestring below will work. */
}
else
{
- /* Not setting variable value to null */
+ /* Not setting variable value to null. */
val = p + 1;
while (*val == ' ' || *val == '\t')
val++;
var = savestring (arg, p - arg);
if (nullset)
{
- printf_filtered (_("\
-Setting environment variable \"%s\" to null value.\n"),
+ printf_filtered (_("Setting environment variable "
+ "\"%s\" to null value.\n"),
var);
- set_in_environ (inferior_environ, var, "");
+ set_in_environ (current_inferior ()->environment, var, "");
}
else
- set_in_environ (inferior_environ, var, val);
+ set_in_environ (current_inferior ()->environment, var, val);
xfree (var);
}
Ask for confirmation if reading from the terminal. */
if (!from_tty || query (_("Delete all environment variables? ")))
{
- free_environ (inferior_environ);
- inferior_environ = make_environ ();
+ free_environ (current_inferior ()->environment);
+ current_inferior ()->environment = make_environ ();
}
}
else
- unset_in_environ (inferior_environ, var);
+ unset_in_environ (current_inferior ()->environment, var);
}
-/* Handle the execution path (PATH variable) */
+/* Handle the execution path (PATH variable). */
static const char path_var_name[] = "PATH";
path_info (char *args, int from_tty)
{
puts_filtered ("Executable and object file path: ");
- puts_filtered (get_in_environ (inferior_environ, path_var_name));
+ puts_filtered (get_in_environ (current_inferior ()->environment,
+ path_var_name));
puts_filtered ("\n");
}
{
char *exec_path;
char *env;
+
dont_repeat ();
- env = get_in_environ (inferior_environ, path_var_name);
- /* Can be null if path is not set */
+ env = get_in_environ (current_inferior ()->environment, path_var_name);
+ /* Can be null if path is not set. */
if (!env)
env = "";
exec_path = xstrdup (env);
mod_path (dirname, &exec_path);
- set_in_environ (inferior_environ, path_var_name, exec_path);
+ set_in_environ (current_inferior ()->environment, path_var_name, exec_path);
xfree (exec_path);
if (from_tty)
path_info ((char *) NULL, from_tty);
}
\f
-/* Print out the machine register regnum. If regnum is -1, print all
+/* Print out the machine register regnum. If regnum is -1, print all
registers (print_all == 1) or all non-float and non-vector
registers (print_all == 0).
int i;
const int numregs = gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch);
- gdb_byte buffer[MAX_REGISTER_SIZE];
for (i = 0; i < numregs; i++)
{
+ struct type *regtype;
+ struct value *val;
+
/* Decide between printing all regs, non-float / vector regs, or
specific reg. */
if (regnum == -1)
print_spaces_filtered (15 - strlen (gdbarch_register_name
(gdbarch, i)), file);
+ regtype = register_type (gdbarch, i);
+ val = allocate_value (regtype);
+
/* Get the data in raw format. */
- if (! frame_register_read (frame, i, buffer))
+ if (! frame_register_read (frame, i, value_contents_raw (val)))
{
fprintf_filtered (file, "*value not available*\n");
continue;
/* If virtual format is floating, print it that way, and in raw
hex. */
- if (TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_FLT
- || TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_DECFLOAT)
+ if (TYPE_CODE (regtype) == TYPE_CODE_FLT
+ || TYPE_CODE (regtype) == TYPE_CODE_DECFLOAT)
{
int j;
struct value_print_options opts;
+ const gdb_byte *valaddr = value_contents_for_printing (val);
get_user_print_options (&opts);
opts.deref_ref = 1;
- val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 0, &opts, current_language);
+
+ val_print (regtype,
+ value_contents_for_printing (val),
+ value_embedded_offset (val), 0,
+ file, 0, val, &opts, current_language);
fprintf_filtered (file, "\t(raw 0x");
for (j = 0; j < register_size (gdbarch, i); j++)
{
int idx;
+
if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
idx = j;
else
idx = register_size (gdbarch, i) - 1 - j;
- fprintf_filtered (file, "%02x", (unsigned char) buffer[idx]);
+ fprintf_filtered (file, "%02x", (unsigned char) valaddr[idx]);
}
fprintf_filtered (file, ")");
}
/* Print the register in hex. */
get_formatted_print_options (&opts, 'x');
opts.deref_ref = 1;
- val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 0, &opts,
- current_language);
+ val_print (regtype,
+ value_contents_for_printing (val),
+ value_embedded_offset (val), 0,
+ file, 0, val, &opts, current_language);
/* If not a vector register, print it also according to its
natural format. */
- if (TYPE_VECTOR (register_type (gdbarch, i)) == 0)
+ if (TYPE_VECTOR (regtype) == 0)
{
get_user_print_options (&opts);
opts.deref_ref = 1;
fprintf_filtered (file, "\t");
- val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 0, &opts, current_language);
+ val_print (regtype,
+ value_contents_for_printing (val),
+ value_embedded_offset (val), 0,
+ file, 0, val, &opts, current_language);
}
}
{
struct frame_info *frame;
struct gdbarch *gdbarch;
- int regnum, numregs;
- char *end;
if (!target_has_registers)
error (_("The program has no registers now."));
/* A register name? */
{
int regnum = user_reg_map_name_to_regnum (gdbarch, start, end - start);
+
if (regnum >= 0)
{
/* User registers lie completely outside of the range of
printf_filtered ("%s: ", start);
get_formatted_print_options (&opts, 'x');
- print_scalar_formatted (value_contents (val),
- check_typedef (value_type (val)),
- &opts, 0, gdb_stdout);
+ val_print_scalar_formatted (check_typedef (value_type (val)),
+ value_contents_for_printing (val),
+ value_embedded_offset (val),
+ val,
+ &opts, 0, gdb_stdout);
printf_filtered ("\n");
}
else
/* A register group? */
{
struct reggroup *group;
+
for (group = reggroup_next (gdbarch, NULL);
group != NULL;
group = reggroup_next (gdbarch, group))
if (group != NULL)
{
int regnum;
+
for (regnum = 0;
regnum < gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch);
}
static void
-print_vector_info (struct gdbarch *gdbarch, struct ui_file *file,
+print_vector_info (struct ui_file *file,
struct frame_info *frame, const char *args)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
if (gdbarch_print_vector_info_p (gdbarch))
gdbarch_print_vector_info (gdbarch, file, frame, args);
else
if (!target_has_registers)
error (_("The program has no registers now."));
- print_vector_info (current_gdbarch, gdb_stdout,
- get_selected_frame (NULL), args);
+ print_vector_info (gdb_stdout, get_selected_frame (NULL), args);
}
\f
+/* Kill the inferior process. Make us have no inferior. */
+
+static void
+kill_command (char *arg, int from_tty)
+{
+ /* FIXME: This should not really be inferior_ptid (or target_has_execution).
+ It should be a distinct flag that indicates that a target is active, cuz
+ some targets don't have processes! */
+
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("The program is not being run."));
+ if (!query (_("Kill the program being debugged? ")))
+ error (_("Not confirmed."));
+ target_kill ();
+
+ /* If we still have other inferiors to debug, then don't mess with
+ with their threads. */
+ if (!have_inferiors ())
+ {
+ init_thread_list (); /* Destroy thread info. */
+
+ /* Killing off the inferior can leave us with a core file. If
+ so, print the state we are left in. */
+ if (target_has_stack)
+ {
+ printf_filtered (_("In %s,\n"), target_longname);
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ }
+ }
+ bfd_cache_close_all ();
+}
/* Used in `attach&' command. ARG is a point to an integer
representing a process id. Proceed threads of this process iff
&& !is_exited (thread->ptid)
&& !is_executing (thread->ptid)
&& !thread->stop_requested
- && thread->stop_signal == TARGET_SIGNAL_0)
+ && thread->suspend.stop_signal == TARGET_SIGNAL_0)
{
switch_to_thread (thread->ptid);
clear_proceed_status ();
* This only needs to be done if we are attaching to a process.
*/
-/*
- attach_command --
+/* attach_command --
takes a program started up outside of gdb and ``attaches'' to it.
This stops it cold in its tracks and allows us to start debugging it.
and wait for the trace-trap that results from attaching. */
struct inferior *inferior;
inferior = current_inferior ();
- inferior->stop_soon = NO_STOP_QUIETLY;
+ inferior->control.stop_soon = NO_STOP_QUIETLY;
/* If no exec file is yet known, try to determine it from the
process itself. */
Attempt to qualify the filename against the source path.
(If that fails, we'll just fall back on the original
- filename. Not much more we can do...)
- */
+ filename. Not much more we can do...) */
+
if (!source_full_path_of (exec_file, &full_exec_path))
- full_exec_path = savestring (exec_file, strlen (exec_file));
+ full_exec_path = xstrdup (exec_file);
exec_file_attach (full_exec_path, from_tty);
symbol_file_add_main (full_exec_path, from_tty);
proceed_after_attach (inferior->pid);
else
{
- if (inferior_thread ()->stop_signal == TARGET_SIGNAL_0)
+ if (inferior_thread ()->suspend.stop_signal == TARGET_SIGNAL_0)
{
clear_proceed_status ();
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
};
static void
-attach_command_continuation (void *args)
+attach_command_continuation (void *args, int err)
{
struct attach_command_continuation_args *a = args;
+
+ if (err)
+ return;
+
attach_command_post_wait (a->args, a->from_tty, a->async_exec);
}
attach_command_continuation_free_args (void *args)
{
struct attach_command_continuation_args *a = args;
+
xfree (a->args);
xfree (a);
}
void
attach_command (char *args, int from_tty)
{
- char *exec_file;
- char *full_exec_path = NULL;
int async_exec = 0;
struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
dont_repeat (); /* Not for the faint of heart */
- if (target_supports_multi_process ())
- /* Don't complain if we can be attached to multiple processes. */
+ if (gdbarch_has_global_solist (target_gdbarch))
+ /* Don't complain if all processes share the same symbol
+ space. */
;
else if (target_has_execution)
{
async_exec = strip_bg_char (&args);
/* If we get a request for running in the bg but the target
- doesn't support it, error out. */
+ doesn't support it, error out. */
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
}
to simulate synchronous (fg) execution. */
if (!async_exec && target_can_async_p ())
{
- /* Simulate synchronous execution */
+ /* Simulate synchronous execution. */
async_disable_stdin ();
make_cleanup ((make_cleanup_ftype *)async_enable_stdin, NULL);
}
{
struct inferior *inferior = current_inferior ();
- /* Careful here. See comments in inferior.h. Basically some
+ /* Careful here. See comments in inferior.h. Basically some
OSes don't ignore SIGSTOPs on continue requests anymore. We
need a way for handle_inferior_event to reset the stop_signal
variable after an attach, and this is what
STOP_QUIETLY_NO_SIGSTOP is for. */
- inferior->stop_soon = STOP_QUIETLY_NO_SIGSTOP;
+ inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP;
if (target_can_async_p ())
{
return;
}
- wait_for_inferior (0);
+ wait_for_inferior ();
}
attach_command_post_wait (args, from_tty, async_exec);
that. */
target_stop (inferior_ptid);
- inferior->stop_soon = STOP_QUIETLY_REMOTE;
+ inferior->control.stop_soon = STOP_QUIETLY_REMOTE;
/* Wait for stop before proceeding. */
if (target_can_async_p ())
return;
}
else
- wait_for_inferior (0);
+ wait_for_inferior ();
}
async_exec = leave_running;
if (ptid_equal (inferior_ptid, null_ptid))
error (_("The program is not being run."));
+ disconnect_tracing (from_tty);
+
target_detach (args, from_tty);
/* If the solist is global across inferiors, don't clear it when we
if (!gdbarch_has_global_solist (target_gdbarch))
no_shared_libraries (NULL, from_tty);
- /* If the current target interface claims there's still execution,
- then don't mess with threads of other processes. */
- if (!target_has_execution)
+ /* If we still have inferiors to debug, then don't mess with their
+ threads. */
+ if (!have_inferiors ())
init_thread_list ();
if (deprecated_detach_hook)
static void
disconnect_command (char *args, int from_tty)
{
- dont_repeat (); /* Not for the faint of heart */
+ dont_repeat (); /* Not for the faint of heart. */
target_disconnect (args, from_tty);
no_shared_libraries (NULL, from_tty);
init_thread_list ();
interrupt_target_1 (int all_threads)
{
ptid_t ptid;
+
if (all_threads)
ptid = minus_one_ptid;
else
{
int all_threads = 0;
- dont_repeat (); /* Not for the faint of heart */
+ dont_repeat (); /* Not for the faint of heart. */
if (args != NULL
&& strncmp (args, "-a", sizeof ("-a") - 1) == 0)
}
static void
-print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+print_float_info (struct ui_file *file,
struct frame_info *frame, const char *args)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
if (gdbarch_print_float_info_p (gdbarch))
gdbarch_print_float_info (gdbarch, file, frame, args);
else
}
}
if (!printed_something)
- fprintf_filtered (file, "\
-No floating-point info available for this processor.\n");
+ fprintf_filtered (file, "No floating-point info "
+ "available for this processor.\n");
}
}
if (!target_has_registers)
error (_("The program has no registers now."));
- print_float_info (current_gdbarch, gdb_stdout,
- get_selected_frame (NULL), args);
+ print_float_info (gdb_stdout, get_selected_frame (NULL), args);
}
\f
static void
unset_command (char *args, int from_tty)
{
- printf_filtered (_("\
-\"unset\" must be followed by the name of an unset subcommand.\n"));
+ printf_filtered (_("\"unset\" must be followed by the "
+ "name of an unset subcommand.\n"));
help_list (unsetlist, "unset ", -1, gdb_stdout);
}
{
struct cmd_list_element *c = NULL;
- /* add the filename of the terminal connected to inferior I/O */
+ /* Add the filename of the terminal connected to inferior I/O. */
add_setshow_filename_cmd ("inferior-tty", class_run,
- &inferior_io_terminal, _("\
+ &inferior_io_terminal_scratch, _("\
Set terminal for future runs of program being debugged."), _("\
Show terminal for future runs of program being debugged."), _("\
-Usage: set inferior-tty /dev/pts/1"), NULL, NULL, &setlist, &showlist);
+Usage: set inferior-tty /dev/pts/1"),
+ set_inferior_tty_command,
+ show_inferior_tty_command,
+ &setlist, &showlist);
add_com_alias ("tty", "set inferior-tty", class_alias, 0);
add_setshow_optional_filename_cmd ("args", class_run,
- &inferior_args, _("\
+ &inferior_args_scratch, _("\
Set argument list to give program being debugged when it is started."), _("\
Show argument list to give program being debugged when it is started."), _("\
Follow this command with any number of args, to be passed to the program."),
- notice_args_set,
- notice_args_read,
+ set_args_command,
+ show_args_command,
&setlist, &showlist);
c = add_cmd ("environment", no_class, environment_info, _("\
$cwd in the path means the current working directory.\n\
This path is equivalent to the $PATH shell variable. It is a list of\n\
directories, separated by colons. These directories are searched to find\n\
-fully linked executable files and separately compiled object files as needed."));
+fully linked executable files and separately compiled object files as \
+needed."));
set_cmd_completer (c, filename_completer);
c = add_cmd ("paths", no_class, path_info, _("\
$cwd in the path means the current working directory.\n\
This path is equivalent to the $PATH shell variable. It is a list of\n\
directories, separated by colons. These directories are searched to find\n\
-fully linked executable files and separately compiled object files as needed."),
+fully linked executable files and separately compiled object files as \
+needed."),
&showlist);
set_cmd_completer (c, noop_completer);
+ add_prefix_cmd ("kill", class_run, kill_command,
+ _("Kill execution of program being debugged."),
+ &killlist, "kill ", 0, &cmdlist);
+
add_com ("attach", class_run, attach_command, _("\
Attach to a process or file outside of GDB.\n\
This command attaches to another target, of the same type as your last\n\
add_com ("stepi", class_run, stepi_command, _("\
Step one instruction exactly.\n\
-Argument N means do this N times (or till program stops for another reason)."));
+Argument N means do this N times (or till program stops for another \
+reason)."));
add_com_alias ("si", "stepi", class_alias, 0);
add_com ("nexti", class_run, nexti_command, _("\
Step one instruction, but proceed through subroutine calls.\n\
-Argument N means do this N times (or till program stops for another reason)."));
+Argument N means do this N times (or till program stops for another \
+reason)."));
add_com_alias ("ni", "nexti", class_alias, 0);
add_com ("finish", class_run, finish_command, _("\
Step program, proceeding through subroutine calls.\n\
Like the \"step\" command as long as subroutine calls do not happen;\n\
when they do, the call is treated as one instruction.\n\
-Argument N means do this N times (or till program stops for another reason)."));
+Argument N means do this N times (or till program stops for another \
+reason)."));
add_com_alias ("n", "next", class_run, 1);
if (xdb_commands)
add_com_alias ("S", "next", class_run, 1);
add_com ("step", class_run, step_command, _("\
Step program until it reaches a different source line.\n\
-Argument N means do this N times (or till program stops for another reason)."));
+Argument N means do this N times (or till program stops for another \
+reason)."));
add_com_alias ("s", "step", class_run, 1);
c = add_com ("until", class_run, until_command, _("\
Execute until the program reaches a source line greater than the current\n\
-or a specified location (same args as break command) within the current frame."));
+or a specified location (same args as break command) within the current \
+frame."));
set_cmd_completer (c, location_completer);
add_com_alias ("u", "until", class_run, 1);
c = add_com ("advance", class_run, advance_command, _("\
-Continue the program up to the given location (same form as args for break command).\n\
+Continue the program up to the given location (same form as args for break \
+command).\n\
Execution will also stop upon exit from the current stack frame."));
set_cmd_completer (c, location_completer);
if (xdb_commands)
add_com_alias ("g", "go", class_run, 1);
- c = add_com ("continue", class_run, continue_command, _("\
+ add_com ("continue", class_run, continue_command, _("\
Continue program being debugged, after signal or breakpoint.\n\
If proceeding from breakpoint, a number N may be used as an argument,\n\
which means to set the ignore count of that breakpoint to N - 1 (so that\n\
c = add_com ("run", class_run, run_command, _("\
Start debugged program. You may specify arguments to give it.\n\
Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\
-Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\
-With no arguments, uses arguments last specified (with \"run\" or \"set args\").\n\
+Input and output redirection with \">\", \"<\", or \">>\" are also \
+allowed.\n\n\
+With no arguments, uses arguments last specified (with \"run\" \
+or \"set args\").\n\
To cancel previous arguments and run with no arguments,\n\
use \"set args\" without arguments."));
set_cmd_completer (c, filename_completer);
\"run\" command."));
set_cmd_completer (c, filename_completer);
- c = add_com ("interrupt", class_run, interrupt_target_command,
- _("Interrupt the execution of the debugged program.\n\
+ add_com ("interrupt", class_run, interrupt_target_command,
+ _("Interrupt the execution of the debugged program.\n\
If non-stop mode is enabled, interrupt only the current thread,\n\
otherwise all the threads in the program are stopped. To \n\
interrupt all running threads in non-stop mode, use the -a option."));
add_info ("vector", vector_info,
_("Print the status of the vector unit\n"));
-
- inferior_environ = make_environ ();
- init_environ (inferior_environ);
}