/* Memory-access and commands for "inferior" process, for GDB.
- 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, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "arch-utils.h"
#include <signal.h>
-#include "gdb_string.h"
+#include <string.h>
#include "symtab.h"
#include "gdbtypes.h"
#include "frame.h"
#include "gdbcore.h"
#include "target.h"
#include "language.h"
-#include "symfile.h"
#include "objfiles.h"
#include "completer.h"
#include "ui-out.h"
#include "inline-frame.h"
#include "tracepoint.h"
#include "inf-loop.h"
-
-/* Functions exported for general use, in inferior.h: */
-
-void all_registers_info (char *, int);
-
-void registers_info (char *, int);
-
-void nexti_command (char *, int);
-
-void stepi_command (char *, int);
-
-void continue_command (char *, int);
-
-void interrupt_target_command (char *args, int from_tty);
+#include "continuations.h"
+#include "linespec.h"
+#include "cli/cli-utils.h"
/* Local functions: */
static void nofp_registers_info (char *, int);
-static void print_return_value (struct type *func_type,
+static void print_return_value (struct value *function,
struct type *value_type);
static void until_next_command (int);
CORE_ADDR stop_pc;
-/* Flag indicating that a command has proceeded the inferior past the
- current breakpoint. */
-
-int breakpoint_proceeded;
-
/* Nonzero if stopped due to completion of a stack dummy routine. */
enum stop_stack_kind stop_stack_dummy;
int stopped_by_random_signal;
+/* See inferior.h. */
+
+int startup_with_shell = 1;
+
\f
/* Accessor routines. */
{
char *result;
- if (STARTUP_WITH_SHELL)
+ if (startup_with_shell)
{
+#ifdef __MINGW32__
+ /* This holds all the characters considered special to the
+ Windows shells. */
+ char *special = "\"!&*|[]{}<>?`~^=;, \t\n";
+ const char quote = '"';
+#else
/* This holds all the characters considered special to the
typical Unix shells. We include `^' because the SunOS
/bin/sh treats it as a synonym for `|'. */
- char *special = "\"!#$&*()\\|[]{}<>?'\"`~^; \t\n";
+ char *special = "\"!#$&*()\\|[]{}<>?'`~^; \t\n";
+ const char quote = '\'';
+#endif
int i;
int length = 0;
char *out, *cp;
/* Need to handle empty arguments specially. */
if (argv[i][0] == '\0')
{
- *out++ = '\'';
- *out++ = '\'';
+ *out++ = quote;
+ *out++ = quote;
}
else
{
+#ifdef __MINGW32__
+ int quoted = 0;
+
+ if (strpbrk (argv[i], special))
+ {
+ quoted = 1;
+ *out++ = quote;
+ }
+#endif
for (cp = argv[i]; *cp; ++cp)
{
if (*cp == '\n')
/* A newline cannot be quoted with a backslash (it
just disappears), only by putting it inside
quotes. */
- *out++ = '\'';
+ *out++ = quote;
*out++ = '\n';
- *out++ = '\'';
+ *out++ = quote;
}
else
{
+#ifdef __MINGW32__
+ if (*cp == quote)
+#else
if (strchr (special, *cp) != NULL)
+#endif
*out++ = '\\';
*out++ = *cp;
}
}
+#ifdef __MINGW32__
+ if (quoted)
+ *out++ = quote;
+#endif
}
}
*out = '\0';
if (exec_bfd)
{
+ const unsigned solib_add_generation
+ = current_program_space->solib_add_generation;
+
/* Create the hooks to handle shared library load and unload
events. */
-#ifdef SOLIB_CREATE_INFERIOR_HOOK
- SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
-#else
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 (current_program_space->solib_add_generation == solib_add_generation)
+ {
+ /* The platform-specific hook should load initial shared libraries,
+ but didn't. FROM_TTY will be incorrectly 0 but such solib
+ targets should be fixed anyway. Call it only after the solib
+ target has been initialized by solib_create_inferior_hook. */
+
+ if (info_verbose)
+ warning (_("platform-specific solib_create_inferior_hook did "
+ "not load initial shared libraries."));
+
+ /* If the solist is global across processes, there's no need to
+ refetch it here. */
+ if (!gdbarch_has_global_solist (target_gdbarch ()))
+ solib_add (NULL, 0, target, auto_solib_add);
+ }
}
/* If the user sets watchpoints before execution having started,
char *exec_file;
struct cleanup *old_chain;
ptid_t ptid;
+ struct ui_out *uiout = current_uiout;
dont_repeat ();
/* 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);
+ proceed (regcache_read_pc (get_current_regcache ()), GDB_SIGNAL_0, 0);
/* Since there was no error, there's no need to finish the thread
states here. */
switch_to_thread (thread->ptid);
clear_proceed_status ();
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
return 0;
}
-void
+static void
ensure_valid_thread (void)
{
if (ptid_equal (inferior_ptid, null_ptid)
is likely to mix up recorded and live target data. So simply
disallow those commands. */
-void
+static void
ensure_not_tfind_mode (void)
{
if (get_traceframe_number () >= 0)
error (_("Cannot execute this command while looking at trace frames."));
}
+/* Throw an error indicating the current thread is running. */
+
+static void
+error_is_running (void)
+{
+ error (_("Cannot execute this command while "
+ "the selected thread is running."));
+}
+
+/* Calls error_is_running if the current thread is running. */
+
+static void
+ensure_not_running (void)
+{
+ if (is_running (inferior_ptid))
+ error_is_running ();
+}
+
void
continue_1 (int all_threads)
{
ensure_valid_thread ();
ensure_not_running ();
clear_proceed_status ();
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
}
}
/* continue [-a] [proceed-count] [&] */
-void
+static void
continue_command (char *args, int from_tty)
{
int async_exec = 0;
/* Likewise, but step only one instruction. */
-void
+static void
stepi_command (char *count_string, int from_tty)
{
step_1 (0, 1, count_string);
}
-void
+static void
nexti_command (char *count_string, int from_tty)
{
step_1 (1, 1, count_string);
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->control.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);
}
CORE_ADDR pc;
/* Step at an inlined function behaves like "down". */
- if (!skip_subroutines && !single_inst
+ if (!skip_subroutines
&& inline_skipped_frames (inferior_ptid))
{
ptid_t resume_ptid;
&tp->control.step_range_start,
&tp->control.step_range_end);
+ tp->control.may_range_step = 1;
+
/* If we have no line info, switch to stepi mode. */
if (tp->control.step_range_end == 0 && step_stop_if_no_debug)
- tp->control.step_range_start = tp->control.step_range_end = 1;
+ {
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+ tp->control.may_range_step = 0;
+ }
else if (tp->control.step_range_end == 0)
{
- char *name;
+ const char *name;
if (find_pc_partial_function (pc, &name,
&tp->control.step_range_start,
tp->control.step_over_calls = STEP_OVER_ALL;
tp->step_multi = (count > 1);
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1);
/* For async targets, register a continuation to do any
additional steps. For sync targets, the caller will handle
if (!arg)
error_no_arg (_("starting address"));
- sals = decode_line_spec_1 (arg, 1);
+ sals = decode_line_with_last_displayed (arg, DECODE_LINE_FUNFIRSTLINE);
if (sals.nelts != 1)
{
error (_("Unreasonable jump request"));
if (sfn != NULL)
{
fixup_symbol_section (sfn, 0);
- if (section_is_overlay (SYMBOL_OBJ_SECTION (sfn)) &&
- !section_is_mapped (SYMBOL_OBJ_SECTION (sfn)))
+ if (section_is_overlay (SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sfn), sfn)) &&
+ !section_is_mapped (SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sfn), sfn)))
{
if (!query (_("WARNING!!! Destination is in "
"unmapped overlay! Jump anyway? ")))
}
clear_proceed_status ();
- proceed (addr, TARGET_SIGNAL_0, 0);
+ proceed (addr, GDB_SIGNAL_0, 0);
}
\f
static void
signal_command (char *signum_exp, int from_tty)
{
- enum target_signal oursig;
+ enum gdb_signal oursig;
int async_exec = 0;
dont_repeat (); /* Too dangerous. */
/* It would be even slicker to make signal names be valid expressions,
(the type could be "enum $signal" or some such), then the user could
assign them to convenience variables. */
- oursig = target_signal_from_name (signum_exp);
+ oursig = gdb_signal_from_name (signum_exp);
- if (oursig == TARGET_SIGNAL_UNKNOWN)
+ if (oursig == GDB_SIGNAL_UNKNOWN)
{
/* No, try numeric. */
int num = parse_and_eval_long (signum_exp);
if (num == 0)
- oursig = TARGET_SIGNAL_0;
+ oursig = GDB_SIGNAL_0;
else
- oursig = target_signal_from_command (num);
+ oursig = gdb_signal_from_command (num);
}
if (from_tty)
{
- if (oursig == TARGET_SIGNAL_0)
+ if (oursig == GDB_SIGNAL_0)
printf_filtered (_("Continuing with no signal.\n"));
else
printf_filtered (_("Continuing with signal %s.\n"),
- target_signal_to_name (oursig));
+ gdb_signal_to_name (oursig));
}
clear_proceed_status ();
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)
+until_next_continuation (void *arg, int err)
{
- struct thread_info *tp = arg;
+ struct until_next_continuation_args *a = arg;
- delete_longjmp_breakpoint (tp->num);
+ delete_longjmp_breakpoint (a->thread);
}
/* Proceed until we reach a different source line with pc greater than
if (!func)
{
- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (pc);
- if (msymbol == NULL)
+ if (msymbol.minsym == NULL)
error (_("Execution is not within a known function."));
- tp->control.step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
+ tp->control.step_range_start = SYMBOL_VALUE_ADDRESS (msymbol.minsym);
tp->control.step_range_end = pc;
}
else
tp->control.step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
tp->control.step_range_end = sal.end;
}
+ tp->control.may_range_step = 1;
tp->control.step_over_calls = STEP_OVER_ALL;
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);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1);
if (target_can_async_p () && is_running (inferior_ptid))
{
+ struct until_next_continuation_args *cont_args;
+
discard_cleanups (old_chain);
- add_continuation (tp, until_next_continuation, tp, NULL);
+ 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);
until_break_command (arg, from_tty, 1);
}
\f
-/* Print the result of a function at the end of a 'finish' command. */
+/* Return the value of the result of a function at the end of a 'finish'
+ command/BP. */
-static void
-print_return_value (struct type *func_type, struct type *value_type)
+struct value *
+get_return_value (struct value *function, struct type *value_type)
{
- struct gdbarch *gdbarch = get_regcache_arch (stop_registers);
- struct cleanup *old_chain;
- struct ui_stream *stb;
+ struct regcache *stop_regs = stop_registers;
+ struct gdbarch *gdbarch;
struct value *value;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
+ /* If stop_registers were not saved, use the current registers. */
+ if (!stop_regs)
+ {
+ stop_regs = regcache_dup (get_current_regcache ());
+ make_cleanup_regcache_xfree (stop_regs);
+ }
+
+ gdbarch = get_regcache_arch (stop_regs);
CHECK_TYPEDEF (value_type);
gdb_assert (TYPE_CODE (value_type) != TYPE_CODE_VOID);
inferior function call code. In fact, when inferior function
calls are made async, this will likely be made the norm. */
- switch (gdbarch_return_value (gdbarch, func_type, value_type,
+ switch (gdbarch_return_value (gdbarch, function, value_type,
NULL, NULL, NULL))
{
case RETURN_VALUE_REGISTER_CONVENTION:
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
value = allocate_value (value_type);
- gdbarch_return_value (gdbarch, func_type, value_type, stop_registers,
+ gdbarch_return_value (gdbarch, function, value_type, stop_regs,
value_contents_raw (value), NULL);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
+ do_cleanups (cleanup);
+
+ return value;
+}
+
+/* Print the result of a function at the end of a 'finish' command. */
+
+static void
+print_return_value (struct value *function, struct type *value_type)
+{
+ struct value *value = get_return_value (function, value_type);
+ struct ui_out *uiout = current_uiout;
+
if (value)
{
struct value_print_options opts;
+ struct ui_file *stb;
+ struct cleanup *old_chain;
/* Print it. */
- stb = ui_out_stream_new (uiout);
- old_chain = make_cleanup_ui_out_stream_delete (stb);
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
ui_out_text (uiout, "Value returned is ");
ui_out_field_fmt (uiout, "gdb-result-var", "$%d",
record_latest_value (value));
ui_out_text (uiout, " = ");
- get_raw_print_options (&opts);
- value_print (value, stb->stream, &opts);
+ get_no_prettyformat_print_options (&opts);
+ value_print (value, stb, &opts);
ui_out_field_stream (uiout, "return-value", stb);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
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))
- {
- tp = inferior_thread ();
- bs = tp->control.stop_bpstat;
- }
- if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
- && a->function != NULL)
+ if (!err)
{
- struct type *value_type;
+ struct thread_info *tp = NULL;
+ bpstat bs = NULL;
- value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
- if (!value_type)
- internal_error (__FILE__, __LINE__,
- _("finish_command: function has no target type"));
+ if (!ptid_equal (inferior_ptid, null_ptid)
+ && target_has_execution
+ && is_stopped (inferior_ptid))
+ {
+ tp = inferior_thread ();
+ bs = tp->control.stop_bpstat;
+ }
- if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
+ if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
+ && a->function != NULL)
{
- volatile struct gdb_exception ex;
+ 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"));
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
{
- /* 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);
+ volatile struct gdb_exception ex;
+ struct value *func;
+
+ func = read_var_value (a->function, get_current_frame ());
+ 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 (func, value_type);
+ }
+ if (ex.reason < 0)
+ exception_print (gdb_stdout, ex);
}
- if (ex.reason < 0)
- exception_print (gdb_stdout, ex);
}
+
+ /* 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->control.proceed_to_finish)
- observer_notify_normal_stop (bs, 1 /* print frame */);
delete_breakpoint (a->breakpoint);
- delete_longjmp_breakpoint (inferior_thread ()->num);
+ 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->control.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
{
struct frame_info *frame = get_selected_frame (NULL);
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct symtab_and_line sr_sal;
- /* Set breakpoint and continue. */
- breakpoint =
- set_momentary_breakpoint (gdbarch, sal,
- get_stack_frame_id (frame),
- bp_breakpoint);
- /* Tell the breakpoint to keep quiet. We won't be done
- until we've done another reverse single-step. */
- breakpoint_set_silent (breakpoint, 1);
- old_chain = make_cleanup_delete_breakpoint (breakpoint);
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
- /* We will be stopped when proceed returns. */
- back_up = (bpstat_find_breakpoint (tp->control.stop_bpstat, breakpoint)
- != NULL);
- do_cleanups (old_chain);
+ /* 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, GDB_SIGNAL_DEFAULT, 0);
}
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. */
+ /* 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);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1);
}
- return;
}
/* finish_forward -- helper function for finish_command. */
static void
finish_forward (struct symbol *function, struct frame_info *frame)
{
+ struct frame_id frame_id = get_frame_id (frame);
struct gdbarch *gdbarch = get_frame_arch (frame);
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
get_stack_frame_id (frame),
bp_finish);
+ /* set_momentary_breakpoint invalidates FRAME. */
+ frame = NULL;
+
old_chain = make_cleanup_delete_breakpoint (breakpoint);
- set_longjmp_breakpoint (tp, get_frame_id (frame));
+ set_longjmp_breakpoint (tp, frame_id);
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);
+ proceed ((CORE_ADDR) -1, GDB_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
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 (from_tty)
{
printf_filtered (_("Run till exit from "));
- print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
+ print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
}
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 1);
return;
}
+ /* Ignore TAILCALL_FRAME type frames, they were executed already before
+ entering THISFRAME. */
+ while (get_frame_type (frame) == TAILCALL_FRAME)
+ frame = get_prev_frame (frame);
+
/* Find the function we will return from. */
function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
else
printf_filtered (_("Run till exit from "));
- print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
+ print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
}
if (execution_direction == EXEC_REVERSE)
target_files_info ();
printf_filtered (_("Program stopped at %s.\n"),
- paddress (target_gdbarch, stop_pc));
+ paddress (target_gdbarch (), stop_pc));
if (tp->control.stop_step)
printf_filtered (_("It stopped after being stepped.\n"));
else if (stat != 0)
stat = bpstat_num (&bs, &num);
}
}
- else if (tp->suspend.stop_signal != TARGET_SIGNAL_0)
+ else if (tp->suspend.stop_signal != GDB_SIGNAL_0)
{
printf_filtered (_("It stopped with signal %s, %s.\n"),
- target_signal_to_name (tp->suspend.stop_signal),
- target_signal_to_string (tp->suspend.stop_signal));
+ gdb_signal_to_name (tp->suspend.stop_signal),
+ gdb_signal_to_string (tp->suspend.stop_signal));
}
if (!from_tty)
}
\f
+/* Print out the register NAME with value VAL, to FILE, in the default
+ fashion. */
+
+static void
+default_print_one_register_info (struct ui_file *file,
+ const char *name,
+ struct value *val)
+{
+ struct type *regtype = value_type (val);
+ int print_raw_format;
+
+ fputs_filtered (name, file);
+ print_spaces_filtered (15 - strlen (name), file);
+
+ print_raw_format = (value_entirely_available (val)
+ && !value_optimized_out (val));
+
+ /* If virtual format is floating, print it that way, and in raw
+ hex. */
+ 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);
+ enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype));
+
+ get_user_print_options (&opts);
+ opts.deref_ref = 1;
+
+ val_print (regtype,
+ value_contents_for_printing (val),
+ value_embedded_offset (val), 0,
+ file, 0, val, &opts, current_language);
+
+ if (print_raw_format)
+ {
+ fprintf_filtered (file, "\t(raw ");
+ print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order);
+ fprintf_filtered (file, ")");
+ }
+ }
+ else
+ {
+ struct value_print_options opts;
+
+ /* Print the register in hex. */
+ get_formatted_print_options (&opts, 'x');
+ opts.deref_ref = 1;
+ 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 (print_raw_format && TYPE_VECTOR (regtype) == 0)
+ {
+ get_user_print_options (&opts);
+ opts.deref_ref = 1;
+ fprintf_filtered (file, "\t");
+ val_print (regtype,
+ value_contents_for_printing (val),
+ value_embedded_offset (val), 0,
+ file, 0, val, &opts, current_language);
+ }
+ }
+
+ fprintf_filtered (file, "\n");
+}
+
/* 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).
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)
|| *(gdbarch_register_name (gdbarch, i)) == '\0')
continue;
- fputs_filtered (gdbarch_register_name (gdbarch, i), file);
- 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, 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 (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 (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) valaddr[idx]);
- }
- fprintf_filtered (file, ")");
- }
- else
- {
- struct value_print_options opts;
-
- /* Print the register in hex. */
- get_formatted_print_options (&opts, 'x');
- opts.deref_ref = 1;
- 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 (regtype) == 0)
- {
- get_user_print_options (&opts);
- opts.deref_ref = 1;
- fprintf_filtered (file, "\t");
- val_print (regtype,
- value_contents_for_printing (val),
- value_embedded_offset (val), 0,
- file, 0, val, &opts, current_language);
- }
- }
-
- fprintf_filtered (file, "\n");
+ default_print_one_register_info (file,
+ gdbarch_register_name (gdbarch, i),
+ value_of_register (i, frame));
}
}
char *start;
const char *end;
- /* Keep skipping leading white space. */
- if (isspace ((*addr_exp)))
- {
- addr_exp++;
- continue;
- }
+ /* Skip leading white space. */
+ addr_exp = skip_spaces (addr_exp);
/* Discard any leading ``$''. Check that there is something
resembling a register following it. */
if (regnum >= gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch))
{
- struct value_print_options opts;
- struct value *val = value_of_user_reg (regnum, frame);
-
- printf_filtered ("%s: ", start);
- get_formatted_print_options (&opts, 'x');
- 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");
+ struct value *regval = value_of_user_reg (regnum, frame);
+ const char *regname = user_reg_map_regnum_to_name (gdbarch,
+ regnum);
+
+ /* Print in the same fashion
+ gdbarch_print_registers_info's default
+ implementation prints. */
+ default_print_one_register_info (gdb_stdout,
+ regname,
+ regval);
}
else
gdbarch_print_registers_info (gdbarch, gdb_stdout,
}
}
-void
+static void
all_registers_info (char *addr_exp, int from_tty)
{
registers_info (addr_exp, 1);
if (target_has_stack)
{
printf_filtered (_("In %s,\n"), target_longname);
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
}
}
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
they stopped due to debugger request, and when they did, they
- reported a clean stop (TARGET_SIGNAL_0). Do not proceed threads
+ reported a clean stop (GDB_SIGNAL_0). Do not proceed threads
that have been explicitly been told to stop. */
static int
&& !is_exited (thread->ptid)
&& !is_executing (thread->ptid)
&& !thread->stop_requested
- && thread->suspend.stop_signal == TARGET_SIGNAL_0)
+ && thread->suspend.stop_signal == GDB_SIGNAL_0)
{
switch_to_thread (thread->ptid);
clear_proceed_status ();
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0);
}
return 0;
exec_file = (char *) get_exec_file (0);
if (!exec_file)
{
- exec_file = target_pid_to_exec_file (PIDGET (inferior_ptid));
+ exec_file = target_pid_to_exec_file (ptid_get_pid (inferior_ptid));
if (exec_file)
{
/* It's possible we don't have a full path, but rather just a
}
/* Take any necessary post-attaching actions for this platform. */
- target_post_attach (PIDGET (inferior_ptid));
+ target_post_attach (ptid_get_pid (inferior_ptid));
post_create_inferior (¤t_target, from_tty);
proceed_after_attach (inferior->pid);
else
{
- if (inferior_thread ()->suspend.stop_signal == TARGET_SIGNAL_0)
+ if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
{
clear_proceed_status ();
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed ((CORE_ADDR) -1, GDB_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);
}
dont_repeat (); /* Not for the faint of heart */
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_solist (target_gdbarch ()))
/* Don't complain if all processes share the same symbol
space. */
;
/* If in non-stop, leave threads as running as they were. If
they're stopped for some reason other than us telling it to, the
- target reports a signal != TARGET_SIGNAL_0. We don't try to
+ target reports a signal != GDB_SIGNAL_0. We don't try to
resume threads with such a stop signal. */
async_exec = non_stop;
if (ptid_equal (inferior_ptid, null_ptid))
error (_("The program is not being run."));
- disconnect_tracing (from_tty);
+ query_if_trace_running (from_tty);
+
+ disconnect_tracing ();
target_detach (args, from_tty);
/* If the solist is global across inferiors, don't clear it when we
detach from a single inferior. */
- if (!gdbarch_has_global_solist (target_gdbarch))
+ if (!gdbarch_has_global_solist (target_gdbarch ()))
no_shared_libraries (NULL, from_tty);
/* If we still have inferiors to debug, then don't mess with their
disconnect_command (char *args, int from_tty)
{
dont_repeat (); /* Not for the faint of heart. */
+ query_if_trace_running (from_tty);
+ disconnect_tracing ();
target_disconnect (args, from_tty);
no_shared_libraries (NULL, from_tty);
init_thread_list ();
if the `-a' switch is used. */
/* interrupt [-a] */
-void
+static void
interrupt_target_command (char *args, int from_tty)
{
if (target_can_async_p ())
help_list (unsetlist, "unset ", -1, gdb_stdout);
}
+/* Implement `info proc' family of commands. */
+
+static void
+info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
+{
+ struct gdbarch *gdbarch = get_current_arch ();
+
+ if (!target_info_proc (args, what))
+ {
+ if (gdbarch_info_proc_p (gdbarch))
+ gdbarch_info_proc (gdbarch, args, what);
+ else
+ error (_("Not supported on this target."));
+ }
+}
+
+/* Implement `info proc' when given without any futher parameters. */
+
+static void
+info_proc_cmd (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
+}
+
+/* Implement `info proc mappings'. */
+
+static void
+info_proc_cmd_mappings (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
+}
+
+/* Implement `info proc stat'. */
+
+static void
+info_proc_cmd_stat (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_STAT, from_tty);
+}
+
+/* Implement `info proc status'. */
+
+static void
+info_proc_cmd_status (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_STATUS, from_tty);
+}
+
+/* Implement `info proc cwd'. */
+
+static void
+info_proc_cmd_cwd (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_CWD, from_tty);
+}
+
+/* Implement `info proc cmdline'. */
+
+static void
+info_proc_cmd_cmdline (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
+}
+
+/* Implement `info proc exe'. */
+
+static void
+info_proc_cmd_exe (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_EXE, from_tty);
+}
+
+/* Implement `info proc all'. */
+
+static void
+info_proc_cmd_all (char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_ALL, from_tty);
+}
+
void
_initialize_infcmd (void)
{
+ static struct cmd_list_element *info_proc_cmdlist;
struct cmd_list_element *c = NULL;
+ const char *cmd_name;
/* Add the filename of the terminal connected to inferior I/O. */
add_setshow_filename_cmd ("inferior-tty", class_run,
&setlist, &showlist);
add_com_alias ("tty", "set inferior-tty", class_alias, 0);
- add_setshow_optional_filename_cmd ("args", class_run,
- &inferior_args_scratch, _("\
+ cmd_name = "args";
+ add_setshow_string_noescape_cmd (cmd_name, class_run,
+ &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."),
- set_args_command,
- show_args_command,
- &setlist, &showlist);
+ set_args_command,
+ show_args_command,
+ &setlist, &showlist);
+ c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+ gdb_assert (c != NULL);
+ set_cmd_completer (c, filename_completer);
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
The target will wait for another debugger to connect. Not available for\n\
all targets."));
- add_com ("signal", class_run, signal_command, _("\
-Continue program giving it signal specified by the argument.\n\
-An argument of \"0\" means continue program without giving it a signal."));
+ c = add_com ("signal", class_run, signal_command, _("\
+Continue program with the specified signal.\n\
+Usage: signal SIGNAL\n\
+The SIGNAL argument is processed the same as the handle command.\n\
+\n\
+An argument of \"0\" means continue the program without sending it a signal.\n\
+This is useful in cases where the program stopped because of a signal,\n\
+and you want to resume the program while discarding the signal."));
+ set_cmd_completer (c, signal_completer);
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 \
+Usage: stepi [N]\n\
+Argument N means step 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 \
+Usage: nexti [N]\n\
+Argument N means step N times (or till program stops for another \
reason)."));
add_com_alias ("ni", "nexti", class_alias, 0);
add_com ("finish", class_run, finish_command, _("\
Execute until selected stack frame returns.\n\
+Usage: finish\n\
Upon return, the value returned is printed and put in the value history."));
add_com_alias ("fin", "finish", class_run, 1);
add_com ("next", class_run, next_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)."));
+Usage: next [N]\n\
+Unlike \"step\", if the current source line calls a subroutine,\n\
+this command does not enter the subroutine, but instead steps over\n\
+the call, in effect treating it as a single source line."));
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 \
+Usage: step [N]\n\
+Argument N means step N times (or till program stops for another \
reason)."));
add_com_alias ("s", "step", class_run, 1);
c = add_com ("jump", class_run, jump_command, _("\
Continue program being debugged at specified line or address.\n\
+Usage: jump <location>\n\
Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
for an address to start at."));
set_cmd_completer (c, location_completer);
+ add_com_alias ("j", "jump", class_run, 1);
if (xdb_commands)
{
add_com ("continue", class_run, continue_command, _("\
Continue program being debugged, after signal or breakpoint.\n\
+Usage: continue [N]\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\
the breakpoint won't break until the Nth time it is reached).\n\
add_info ("vector", vector_info,
_("Print the status of the vector unit\n"));
+
+ add_prefix_cmd ("proc", class_info, info_proc_cmd,
+ _("\
+Show /proc process information about any running process.\n\
+Specify any process id, or use the program being debugged by default."),
+ &info_proc_cmdlist, "info proc ",
+ 1/*allow-unknown*/, &infolist);
+
+ add_cmd ("mappings", class_info, info_proc_cmd_mappings, _("\
+List of mapped memory regions."),
+ &info_proc_cmdlist);
+
+ add_cmd ("stat", class_info, info_proc_cmd_stat, _("\
+List process info from /proc/PID/stat."),
+ &info_proc_cmdlist);
+
+ add_cmd ("status", class_info, info_proc_cmd_status, _("\
+List process info from /proc/PID/status."),
+ &info_proc_cmdlist);
+
+ add_cmd ("cwd", class_info, info_proc_cmd_cwd, _("\
+List current working directory of the process."),
+ &info_proc_cmdlist);
+
+ add_cmd ("cmdline", class_info, info_proc_cmd_cmdline, _("\
+List command line arguments of the process."),
+ &info_proc_cmdlist);
+
+ add_cmd ("exe", class_info, info_proc_cmd_exe, _("\
+List absolute filename for executable of the process."),
+ &info_proc_cmdlist);
+
+ add_cmd ("all", class_info, info_proc_cmd_all, _("\
+List all available /proc info."),
+ &info_proc_cmdlist);
}