/* Memory-access and commands for "inferior" process, for GDB.
- Copyright (C) 1986-2017 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "frame.h"
#include "inferior.h"
#include "infrun.h"
-#include "environ.h"
+#include "common/environ.h"
#include "value.h"
#include "gdbcmd.h"
#include "symfile.h"
#include "block.h"
#include "solib.h"
#include <ctype.h>
-#include "observer.h"
+#include "observable.h"
#include "target-descriptions.h"
#include "user-regs.h"
#include "cli/cli-decode.h"
#include "top.h"
#include "interps.h"
#include "common/gdb_optional.h"
+#include "source.h"
/* Local functions: */
-static void info_registers_command (char *, int);
-
static void until_next_command (int);
-static void until_command (char *, int);
-
-static void path_command (char *, int);
-
-static void unset_command (char *, int);
-
-static void info_float_command (char *, int);
-
-static void disconnect_command (char *, int);
-
-static void info_program_command (char *, int);
-
-static void finish_command (char *, int);
-
-static void signal_command (char *, int);
-
-static void jump_command (char *, int);
-
-static void step_1 (int, int, char *);
-
-static void next_command (char *, int);
-
-static void step_command (char *, int);
-
-static void run_command (char *, int);
+static void step_1 (int, int, const char *);
#define ERROR_NO_INFERIOR \
if (!target_has_execution) error (_("The program is not being run."));
ptid_t inferior_ptid;
-/* Address at which inferior stopped. */
-
-CORE_ADDR stop_pc;
-
/* Nonzero if stopped due to completion of a stack dummy routine. */
enum stop_stack_kind stop_stack_dummy;
}
static void
-set_inferior_tty_command (char *args, int from_tty,
+set_inferior_tty_command (const char *args, int from_tty,
struct cmd_list_element *c)
{
/* CLI has assigned the user-provided value to inferior_io_terminal_scratch.
"is \"%s\".\n"), inferior_io_terminal);
}
-char *
+const char *
get_inferior_args (void)
{
if (current_inferior ()->argc != 0)
NEWARGS is not transferred. */
void
-set_inferior_args (char *newargs)
+set_inferior_args (const char *newargs)
{
xfree (current_inferior ()->args);
current_inferior ()->args = newargs ? xstrdup (newargs) : NULL;
/* Notice when `set args' is run. */
static void
-set_args_command (char *args, int from_tty, struct cmd_list_element *c)
+set_args_command (const char *args, int from_tty, struct cmd_list_element *c)
{
/* CLI has assigned the user-provided value to inferior_args_scratch.
Now route it to current inferior. */
/* Handle the 'set cwd' command. */
static void
-set_cwd_command (char *args, int from_tty, struct cmd_list_element *c)
+set_cwd_command (const char *args, int from_tty, struct cmd_list_element *c)
{
if (*inferior_cwd_scratch == '\0')
set_inferior_cwd (NULL);
NULL is returned. *BG_CHAR_P is an output boolean that indicates
whether the '&' character was found. */
-static char *
+static gdb::unique_xmalloc_ptr<char>
strip_bg_char (const char *args, int *bg_char_p)
{
const char *p;
*bg_char_p = 1;
if (p != args)
- return savestring (args, p - args);
+ return gdb::unique_xmalloc_ptr<char>
+ (savestring (args, p - args));
else
- return NULL;
+ return gdb::unique_xmalloc_ptr<char> (nullptr);
}
*bg_char_p = 0;
- return xstrdup (args);
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (args));
}
/* Common actions to take after creating any sort of inferior, by any
/* 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
+ thread_info *thr = inferior_thread ();
+
+ thr->suspend.stop_pc = 0;
+ try
{
- stop_pc = regcache_read_pc (get_current_regcache ());
+ thr->suspend.stop_pc = regcache_read_pc (get_current_regcache ());
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_RETURN_MASK_ERROR &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
throw_exception (ex);
}
- END_CATCH
if (exec_bfd)
{
if the now pushed target supports hardware watchpoints. */
breakpoint_re_set ();
- observer_notify_inferior_created (target, from_tty);
+ gdb::observers::inferior_created.notify (target, from_tty);
}
/* Kill the inferior if already running. This function is designed
static void
kill_if_already_running (int from_tty)
{
- if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
+ if (inferior_ptid != null_ptid && target_has_execution)
{
/* Bail out before killing the program if we will not be able to
restart it. */
{
/* If we get a request for running in the bg but the target
doesn't support it, error out. */
- if (background && !target->to_can_async_p (target))
+ if (background && !target->can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!background)
requested by RUN_HOW. */
static void
-run_command_1 (char *args, int from_tty, enum run_how run_how)
+run_command_1 (const char *args, int from_tty, enum run_how run_how)
{
const char *exec_file;
- struct cleanup *old_chain;
- ptid_t ptid;
struct ui_out *uiout = current_uiout;
struct target_ops *run_target;
int async_exec;
- struct cleanup *args_chain;
- CORE_ADDR pc;
dont_repeat ();
reopen_exec_file ();
reread_symbols ();
- args = strip_bg_char (args, &async_exec);
- args_chain = make_cleanup (xfree, args);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (args, &async_exec);
+ args = stripped.get ();
/* Do validation and preparation before possibly changing anything
in the inferior. */
prepare_execution_command (run_target, async_exec);
- if (non_stop && !run_target->to_supports_non_stop (run_target))
+ if (non_stop && !run_target->supports_non_stop ())
error (_("The target does not support running in non-stop mode."));
/* Done. Can now set breakpoints, change inferior args, etc. */
uiout->flush ();
}
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
/* We call get_inferior_args() because we might need to compute
the value now. */
- run_target->to_create_inferior (run_target, exec_file,
- std::string (get_inferior_args ()),
- current_inferior ()->environment.envp (),
- from_tty);
+ run_target->create_inferior (exec_file,
+ std::string (get_inferior_args ()),
+ current_inferior ()->environment.envp (),
+ from_tty);
/* to_create_inferior should push the target, so after this point we
shouldn't refer to run_target again. */
run_target = NULL;
events --- the frontend shouldn't see them as stopped. In
all-stop, always finish the state of all threads, as we may be
resuming more than just the new process. */
- if (non_stop)
- ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
- else
- ptid = minus_one_ptid;
- old_chain = make_cleanup (finish_thread_state_cleanup, &ptid);
+ ptid_t finish_ptid = (non_stop
+ ? ptid_t (current_inferior ()->pid)
+ : minus_one_ptid);
+ scoped_finish_thread_state finish_state (finish_ptid);
/* Pass zero for FROM_TTY, because at this point the "run" command
has done its thing; now we are setting up the running program. */
- post_create_inferior (¤t_target, 0);
+ post_create_inferior (current_top_target (), 0);
/* Queue a pending event so that the program stops immediately. */
if (run_how == RUN_STOP_AT_FIRST_INSN)
/* Since there was no error, there's no need to finish the thread
states here. */
- discard_cleanups (old_chain);
+ finish_state.release ();
}
static void
-run_command (char *args, int from_tty)
+run_command (const char *args, int from_tty)
{
run_command_1 (args, from_tty, RUN_NORMAL);
}
program. */
static void
-start_command (char *args, int from_tty)
+start_command (const char *args, int from_tty)
{
/* Some languages such as Ada need to search inside the program
minimal symbols for the location where to put the temporary
instruction. */
static void
-starti_command (char *args, int from_tty)
+starti_command (const char *args, int from_tty)
{
run_command_1 (args, from_tty, RUN_STOP_AT_FIRST_INSN);
}
much. If/when GDB gains a way to tell the target `hold this
thread stopped until I say otherwise', then we can optimize
this. */
- if (!is_stopped (thread->ptid))
+ if (thread->state != THREAD_STOPPED)
return 0;
- switch_to_thread (thread->ptid);
+ switch_to_thread (thread);
clear_proceed_status (0);
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
return 0;
static void
ensure_valid_thread (void)
{
- if (ptid_equal (inferior_ptid, null_ptid)
- || is_exited (inferior_ptid))
+ if (inferior_ptid == null_ptid
+ || inferior_thread ()->state == THREAD_EXITED)
error (_("Cannot execute this command without a live selected thread."));
}
static void
ensure_not_running (void)
{
- if (is_running (inferior_ptid))
+ if (inferior_thread ()->state == THREAD_RUNNING)
error_is_running ();
}
/* continue [-a] [proceed-count] [&] */
static void
-continue_command (char *args, int from_tty)
+continue_command (const char *args, int from_tty)
{
int async_exec;
int all_threads = 0;
- struct cleanup *args_chain;
ERROR_NO_INFERIOR;
/* Find out whether we must run in the background. */
- args = strip_bg_char (args, &async_exec);
- args_chain = make_cleanup (xfree, args);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (args, &async_exec);
+ args = stripped.get ();
if (args != NULL)
{
struct thread_info *tp;
if (non_stop)
- tp = find_thread_ptid (inferior_ptid);
+ tp = inferior_thread ();
else
{
ptid_t last_ptid;
}
}
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
ensure_not_running ();
}
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
if (from_tty)
printf_filtered (_("Continuing.\n"));
/* Step until outside of current statement. */
static void
-step_command (char *count_string, int from_tty)
+step_command (const char *count_string, int from_tty)
{
step_1 (0, 0, count_string);
}
/* Likewise, but skip over subroutine calls as if single instructions. */
static void
-next_command (char *count_string, int from_tty)
+next_command (const char *count_string, int from_tty)
{
step_1 (1, 0, count_string);
}
/* Likewise, but step only one instruction. */
static void
-stepi_command (char *count_string, int from_tty)
+stepi_command (const char *count_string, int from_tty)
{
step_1 (0, 1, count_string);
}
static void
-nexti_command (char *count_string, int from_tty)
+nexti_command (const char *count_string, int from_tty)
{
step_1 (1, 1, count_string);
}
-void
-delete_longjmp_breakpoint_cleanup (void *arg)
-{
- int thread = * (int *) arg;
- delete_longjmp_breakpoint (thread);
-}
-
/* Data for the FSM that manages the step/next/stepi/nexti
commands. */
-struct step_command_fsm
+struct step_command_fsm : public thread_fsm
{
- /* The base class. */
- struct thread_fsm thread_fsm;
-
/* How many steps left in a "step N"-like command. */
int count;
/* If true, this is a stepi/nexti, otherwise a step/step. */
int single_inst;
-};
-static void step_command_fsm_clean_up (struct thread_fsm *self,
- struct thread_info *thread);
-static int step_command_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *thread);
-static enum async_reply_reason
- step_command_fsm_async_reply_reason (struct thread_fsm *self);
-
-/* step_command_fsm's vtable. */
+ explicit step_command_fsm (struct interp *cmd_interp)
+ : thread_fsm (cmd_interp)
+ {
+ }
-static struct thread_fsm_ops step_command_fsm_ops =
-{
- NULL,
- step_command_fsm_clean_up,
- step_command_fsm_should_stop,
- NULL, /* return_value */
- step_command_fsm_async_reply_reason,
+ void clean_up (struct thread_info *thread) override;
+ bool should_stop (struct thread_info *thread) override;
+ enum async_reply_reason do_async_reply_reason () override;
};
-/* Allocate a new step_command_fsm. */
-
-static struct step_command_fsm *
-new_step_command_fsm (struct interp *cmd_interp)
-{
- struct step_command_fsm *sm;
-
- sm = XCNEW (struct step_command_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops, cmd_interp);
-
- return sm;
-}
-
/* Prepare for a step/next/etc. command. Any target resource
allocated here is undone in the FSM's clean_up method. */
static int prepare_one_step (struct step_command_fsm *sm);
static void
-step_1 (int skip_subroutines, int single_inst, char *count_string)
+step_1 (int skip_subroutines, int single_inst, const char *count_string)
{
int count;
int async_exec;
- struct cleanup *args_chain;
struct thread_info *thr;
struct step_command_fsm *step_sm;
ensure_valid_thread ();
ensure_not_running ();
- count_string = strip_bg_char (count_string, &async_exec);
- args_chain = make_cleanup (xfree, count_string);
+ gdb::unique_xmalloc_ptr<char> stripped
+ = strip_bg_char (count_string, &async_exec);
+ count_string = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
count = count_string ? parse_and_eval_long (count_string) : 1;
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
clear_proceed_status (1);
/* Setup the execution command state machine to handle all the COUNT
steps. */
thr = inferior_thread ();
- step_sm = new_step_command_fsm (command_interp ());
- thr->thread_fsm = &step_sm->thread_fsm;
+ step_sm = new step_command_fsm (command_interp ());
+ thr->thread_fsm = step_sm;
step_command_fsm_prepare (step_sm, skip_subroutines,
single_inst, count, thr);
/* Stepped into an inline frame. Pretend that we've
stopped. */
- thread_fsm_clean_up (thr->thread_fsm, thr);
+ thr->thread_fsm->clean_up (thr);
proceeded = normal_stop ();
if (!proceeded)
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
return control to the user. If count is > 1, returns false, as we
will need to keep going. */
-static int
-step_command_fsm_should_stop (struct thread_fsm *self, struct thread_info *tp)
+bool
+step_command_fsm::should_stop (struct thread_info *tp)
{
- struct step_command_fsm *sm = (struct step_command_fsm *) self;
-
if (tp->control.stop_step)
{
/* There are more steps to make, and we did stop due to
ending a stepping range. Do another step. */
- if (--sm->count > 0)
- return prepare_one_step (sm);
+ if (--count > 0)
+ return prepare_one_step (this);
- thread_fsm_set_finished (self);
+ set_finished ();
}
- return 1;
+ return true;
}
/* Implementation of the 'clean_up' FSM method for stepping commands. */
-static void
-step_command_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
+void
+step_command_fsm::clean_up (struct thread_info *thread)
{
- struct step_command_fsm *sm = (struct step_command_fsm *) self;
-
- if (!sm->single_inst || sm->skip_subroutines)
+ if (!single_inst || skip_subroutines)
delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'async_reply_reason' FSM method for stepping
commands. */
-static enum async_reply_reason
-step_command_fsm_async_reply_reason (struct thread_fsm *self)
+enum async_reply_reason
+step_command_fsm::do_async_reply_reason ()
{
return EXEC_ASYNC_END_STEPPING_RANGE;
}
/* Step at an inlined function behaves like "down". */
if (!sm->skip_subroutines
- && inline_skipped_frames (inferior_ptid))
+ && inline_skipped_frames (tp))
{
ptid_t resume_ptid;
resume_ptid = user_visible_resume_ptid (1);
set_running (resume_ptid, 1);
- step_into_inline_frame (inferior_ptid);
+ step_into_inline_frame (tp);
sm->count--;
return prepare_one_step (sm);
}
}
/* Done. */
- thread_fsm_set_finished (&sm->thread_fsm);
+ sm->set_finished ();
return 1;
}
/* Continue program at specified address. */
static void
-jump_command (char *arg, int from_tty)
+jump_command (const char *arg, int from_tty)
{
struct gdbarch *gdbarch = get_current_arch ();
CORE_ADDR addr;
struct symbol *fn;
struct symbol *sfn;
int async_exec;
- struct cleanup *args_chain;
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
ensure_not_running ();
/* Find out whether we must run in the background. */
- arg = strip_bg_char (arg, &async_exec);
- args_chain = make_cleanup (xfree, arg);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (arg, &async_exec);
+ arg = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
if (!arg)
error_no_arg (_("starting address"));
if (sals.size () != 1)
error (_("Unreasonable jump request"));
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
symtab_and_line &sal = sals[0];
if (sal.symtab == 0 && sal.pc == 0)
/* Continue program giving it specified signal. */
static void
-signal_command (char *signum_exp, int from_tty)
+signal_command (const char *signum_exp, int from_tty)
{
enum gdb_signal oursig;
int async_exec;
- struct cleanup *args_chain;
dont_repeat (); /* Too dangerous. */
ERROR_NO_INFERIOR;
ensure_not_running ();
/* Find out whether we must run in the background. */
- signum_exp = strip_bg_char (signum_exp, &async_exec);
- args_chain = make_cleanup (xfree, signum_exp);
+ gdb::unique_xmalloc_ptr<char> stripped
+ = strip_bg_char (signum_exp, &async_exec);
+ signum_exp = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
if (!signum_exp)
error_no_arg (_("signal number"));
oursig = gdb_signal_from_command (num);
}
- do_cleanups (args_chain);
-
/* Look for threads other than the current that this command ends up
resuming too (due to schedlock off), and warn if they'll get a
signal delivered. "signal 0" is used to suppress a previous
of the wrong thread. */
if (!non_stop)
{
- struct thread_info *tp;
- ptid_t resume_ptid;
int must_confirm = 0;
/* This indicates what will be resumed. Either a single thread,
a whole process, or all threads of all processes. */
- resume_ptid = user_visible_resume_ptid (0);
+ ptid_t resume_ptid = user_visible_resume_ptid (0);
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : all_non_exited_threads (resume_ptid))
{
- if (ptid_equal (tp->ptid, inferior_ptid))
- continue;
- if (!ptid_match (tp->ptid, resume_ptid))
+ if (tp->ptid == inferior_ptid)
continue;
if (tp->suspend.stop_signal != GDB_SIGNAL_0
/* Queue a signal to be delivered to the current thread. */
static void
-queue_signal_command (char *signum_exp, int from_tty)
+queue_signal_command (const char *signum_exp, int from_tty)
{
enum gdb_signal oursig;
struct thread_info *tp;
/* Data for the FSM that manages the until (with no argument)
command. */
-struct until_next_fsm
+struct until_next_fsm : public thread_fsm
{
- /* The base class. */
- struct thread_fsm thread_fsm;
-
/* The thread that as current when the command was executed. */
int thread;
-};
-static int until_next_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *thread);
-static void until_next_fsm_clean_up (struct thread_fsm *self,
- struct thread_info *thread);
-static enum async_reply_reason
- until_next_fsm_async_reply_reason (struct thread_fsm *self);
-
-/* until_next_fsm's vtable. */
+ until_next_fsm (struct interp *cmd_interp, int thread)
+ : thread_fsm (cmd_interp),
+ thread (thread)
+ {
+ }
-static struct thread_fsm_ops until_next_fsm_ops =
-{
- NULL, /* dtor */
- until_next_fsm_clean_up,
- until_next_fsm_should_stop,
- NULL, /* return_value */
- until_next_fsm_async_reply_reason,
+ bool should_stop (struct thread_info *thread) override;
+ void clean_up (struct thread_info *thread) override;
+ enum async_reply_reason do_async_reply_reason () override;
};
-/* Allocate a new until_next_fsm. */
-
-static struct until_next_fsm *
-new_until_next_fsm (struct interp *cmd_interp, int thread)
-{
- struct until_next_fsm *sm;
-
- sm = XCNEW (struct until_next_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops, cmd_interp);
-
- sm->thread = thread;
-
- return sm;
-}
-
/* Implementation of the 'should_stop' FSM method for the until (with
no arg) command. */
-static int
-until_next_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *tp)
+bool
+until_next_fsm::should_stop (struct thread_info *tp)
{
if (tp->control.stop_step)
- thread_fsm_set_finished (self);
+ set_finished ();
- return 1;
+ return true;
}
/* Implementation of the 'clean_up' FSM method for the until (with no
arg) command. */
-static void
-until_next_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
+void
+until_next_fsm::clean_up (struct thread_info *thread)
{
- struct until_next_fsm *sm = (struct until_next_fsm *) self;
-
delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'async_reply_reason' FSM method for the until
(with no arg) command. */
-static enum async_reply_reason
-until_next_fsm_async_reply_reason (struct thread_fsm *self)
+enum async_reply_reason
+until_next_fsm::do_async_reply_reason ()
{
return EXEC_ASYNC_END_STEPPING_RANGE;
}
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
int thread = tp->global_num;
- struct cleanup *old_chain;
struct until_next_fsm *sm;
clear_proceed_status (0);
{
sal = find_pc_line (pc, 0);
- tp->control.step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
+ tp->control.step_range_start = BLOCK_ENTRY_PC (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);
+ delete_longjmp_breakpoint_cleanup lj_deleter (thread);
- sm = new_until_next_fsm (command_interp (), tp->global_num);
- tp->thread_fsm = &sm->thread_fsm;
- discard_cleanups (old_chain);
+ sm = new until_next_fsm (command_interp (), tp->global_num);
+ tp->thread_fsm = sm;
+ lj_deleter.release ();
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
static void
-until_command (char *arg, int from_tty)
+until_command (const char *arg, int from_tty)
{
int async_exec;
- struct cleanup *args_chain;
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
ensure_not_running ();
/* Find out whether we must run in the background. */
- arg = strip_bg_char (arg, &async_exec);
- args_chain = make_cleanup (xfree, arg);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (arg, &async_exec);
+ arg = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
if (arg)
until_break_command (arg, from_tty, 0);
else
until_next_command (from_tty);
-
- /* Done with ARGS. */
- do_cleanups (args_chain);
}
static void
-advance_command (char *arg, int from_tty)
+advance_command (const char *arg, int from_tty)
{
int async_exec;
- struct cleanup *args_chain;
ERROR_NO_INFERIOR;
ensure_not_tfind_mode ();
error_no_arg (_("a location"));
/* Find out whether we must run in the background. */
- arg = strip_bg_char (arg, &async_exec);
- args_chain = make_cleanup (xfree, arg);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (arg, &async_exec);
+ arg = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
until_break_command (arg, from_tty, 1);
-
- /* Done with ARGS. */
- do_cleanups (args_chain);
}
\f
/* Return the value of the result of a function at the end of a 'finish'
struct value *
get_return_value (struct value *function, struct type *value_type)
{
- regcache stop_regs (regcache::readonly, *get_current_regcache ());
- struct gdbarch *gdbarch = stop_regs.arch ();
+ regcache *stop_regs = get_current_regcache ();
+ struct gdbarch *gdbarch = stop_regs->arch ();
struct value *value;
value_type = check_typedef (value_type);
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
value = allocate_value (value_type);
- gdbarch_return_value (gdbarch, function, value_type, &stop_regs,
+ gdbarch_return_value (gdbarch, function, value_type, stop_regs,
value_contents_raw (value), NULL);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
uiout->field_fmt ("gdb-result-var", "$%d",
rv->value_history_index);
uiout->text (" = ");
- get_no_prettyformat_print_options (&opts);
+ get_user_print_options (&opts);
string_file stb;
void
print_return_value (struct ui_out *uiout, struct return_value_info *rv)
{
- if (rv->type == NULL || TYPE_CODE (rv->type) == TYPE_CODE_VOID)
+ if (rv->type == NULL
+ || TYPE_CODE (check_typedef (rv->type)) == TYPE_CODE_VOID)
return;
- TRY
+ try
{
/* print_return_value_1 can throw an exception in some
circumstances. We need to catch this so that we still
delete the breakpoint. */
print_return_value_1 (uiout, rv);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception_RETURN_MASK_ALL &ex)
{
exception_print (gdb_stdout, ex);
}
- END_CATCH
}
/* Data for the FSM that manages the finish command. */
-struct finish_command_fsm
+struct finish_command_fsm : public thread_fsm
{
- /* The base class. */
- struct thread_fsm thread_fsm;
-
/* The momentary breakpoint set at the function's return address in
the caller. */
- struct breakpoint *breakpoint;
+ breakpoint_up breakpoint;
/* The function that we're stepping out of. */
- struct symbol *function;
+ struct symbol *function = nullptr;
/* If the FSM finishes successfully, this stores the function's
return value. */
- struct return_value_info return_value;
-};
+ struct return_value_info return_value_info {};
-static int finish_command_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *thread);
-static void finish_command_fsm_clean_up (struct thread_fsm *self,
- struct thread_info *thread);
-static struct return_value_info *
- finish_command_fsm_return_value (struct thread_fsm *self);
-static enum async_reply_reason
- finish_command_fsm_async_reply_reason (struct thread_fsm *self);
-
-/* finish_command_fsm's vtable. */
-
-static struct thread_fsm_ops finish_command_fsm_ops =
-{
- NULL, /* dtor */
- finish_command_fsm_clean_up,
- finish_command_fsm_should_stop,
- finish_command_fsm_return_value,
- finish_command_fsm_async_reply_reason,
- NULL, /* should_notify_stop */
-};
-
-/* Allocate a new finish_command_fsm. */
-
-static struct finish_command_fsm *
-new_finish_command_fsm (struct interp *cmd_interp)
-{
- struct finish_command_fsm *sm;
-
- sm = XCNEW (struct finish_command_fsm);
- thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);
+ explicit finish_command_fsm (struct interp *cmd_interp)
+ : thread_fsm (cmd_interp)
+ {
+ }
- return sm;
-}
+ bool should_stop (struct thread_info *thread) override;
+ void clean_up (struct thread_info *thread) override;
+ struct return_value_info *return_value () override;
+ enum async_reply_reason do_async_reply_reason () override;
+};
/* Implementation of the 'should_stop' FSM method for the finish
commands. Detects whether the thread stepped out of the function
successfully, and if so, captures the function's return value and
marks the FSM finished. */
-static int
-finish_command_fsm_should_stop (struct thread_fsm *self,
- struct thread_info *tp)
+bool
+finish_command_fsm::should_stop (struct thread_info *tp)
{
- struct finish_command_fsm *f = (struct finish_command_fsm *) self;
- struct return_value_info *rv = &f->return_value;
+ struct return_value_info *rv = &return_value_info;
- if (f->function != NULL
+ if (function != NULL
&& bpstat_find_breakpoint (tp->control.stop_bpstat,
- f->breakpoint) != NULL)
+ breakpoint.get ()) != NULL)
{
/* We're done. */
- thread_fsm_set_finished (self);
+ set_finished ();
- rv->type = TYPE_TARGET_TYPE (SYMBOL_TYPE (f->function));
+ rv->type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
if (rv->type == NULL)
internal_error (__FILE__, __LINE__,
_("finish_command: function has no target type"));
- if (TYPE_CODE (rv->type) != TYPE_CODE_VOID)
+ if (TYPE_CODE (check_typedef (rv->type)) != TYPE_CODE_VOID)
{
struct value *func;
- func = read_var_value (f->function, NULL, get_current_frame ());
+ func = read_var_value (function, NULL, get_current_frame ());
rv->value = get_return_value (func, rv->type);
if (rv->value != NULL)
rv->value_history_index = record_latest_value (rv->value);
{
/* Finishing from an inline frame, or reverse finishing. In
either case, there's no way to retrieve the return value. */
- thread_fsm_set_finished (self);
+ set_finished ();
}
- return 1;
+ return true;
}
/* Implementation of the 'clean_up' FSM method for the finish
commands. */
-static void
-finish_command_fsm_clean_up (struct thread_fsm *self,
- struct thread_info *thread)
+void
+finish_command_fsm::clean_up (struct thread_info *thread)
{
- struct finish_command_fsm *f = (struct finish_command_fsm *) self;
-
- if (f->breakpoint != NULL)
- {
- delete_breakpoint (f->breakpoint);
- f->breakpoint = NULL;
- }
+ breakpoint.reset ();
delete_longjmp_breakpoint (thread->global_num);
}
/* Implementation of the 'return_value' FSM method for the finish
commands. */
-static struct return_value_info *
-finish_command_fsm_return_value (struct thread_fsm *self)
+struct return_value_info *
+finish_command_fsm::return_value ()
{
- struct finish_command_fsm *f = (struct finish_command_fsm *) self;
-
- return &f->return_value;
+ return &return_value_info;
}
/* Implementation of the 'async_reply_reason' FSM method for the
finish commands. */
-static enum async_reply_reason
-finish_command_fsm_async_reply_reason (struct thread_fsm *self)
+enum async_reply_reason
+finish_command_fsm::do_async_reply_reason ()
{
if (execution_direction == EXEC_REVERSE)
return EXEC_ASYNC_END_STEPPING_RANGE;
frame will return to, then continue. */
static void
-finish_command (char *arg, int from_tty)
+finish_command (const char *arg, int from_tty)
{
struct frame_info *frame;
int async_exec;
- struct cleanup *args_chain;
struct finish_command_fsm *sm;
struct thread_info *tp;
ensure_not_running ();
/* Find out whether we must run in the background. */
- arg = strip_bg_char (arg, &async_exec);
- args_chain = make_cleanup (xfree, arg);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (arg, &async_exec);
+ arg = stripped.get ();
- prepare_execution_command (¤t_target, async_exec);
+ prepare_execution_command (current_top_target (), async_exec);
if (arg)
error (_("The \"finish\" command does not take any arguments."));
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
frame = get_prev_frame (get_selected_frame (_("No selected frame.")));
if (frame == 0)
error (_("\"finish\" not meaningful in the outermost frame."));
tp = inferior_thread ();
- sm = new_finish_command_fsm (command_interp ());
+ sm = new finish_command_fsm (command_interp ());
- tp->thread_fsm = &sm->thread_fsm;
+ tp->thread_fsm = sm;
/* Finishing from an inline frame is completely different. We don't
try to show the "return value" - no way to locate it. */
\f
static void
-info_program_command (char *args, int from_tty)
+info_program_command (const char *args, int from_tty)
{
bpstat bs;
int num, stat;
- struct thread_info *tp;
ptid_t ptid;
if (!target_has_execution)
get_last_target_status (&ptid, &ws);
}
- if (ptid_equal (ptid, null_ptid) || is_exited (ptid))
+ if (ptid == null_ptid || ptid == minus_one_ptid)
+ error (_("No selected thread."));
+
+ thread_info *tp = find_thread_ptid (ptid);
+
+ if (tp->state == THREAD_EXITED)
error (_("Invalid selected thread."));
- else if (is_running (ptid))
+ else if (tp->state == THREAD_RUNNING)
error (_("Selected thread is running."));
- 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 (target_gdbarch (), stop_pc));
+ paddress (target_gdbarch (), tp->suspend.stop_pc));
if (tp->control.stop_step)
printf_filtered (_("It stopped after being stepped.\n"));
else if (stat != 0)
/* Add zero or more directories to the front of the execution path. */
static void
-path_command (char *dirname, int from_tty)
+path_command (const char *dirname, int from_tty)
{
char *exec_path;
const char *env;
}
\f
+static void
+pad_to_column (string_file &stream, int col)
+{
+ /* At least one space must be printed to separate columns. */
+ stream.putc (' ');
+ const int size = stream.size ();
+ if (size < col)
+ stream.puts (n_spaces (col - size));
+}
+
/* Print out the register NAME with value VAL, to FILE, in the default
fashion. */
{
struct type *regtype = value_type (val);
int print_raw_format;
+ string_file format_stream;
+ enum tab_stops
+ {
+ value_column_1 = 15,
+ /* Give enough room for "0x", 16 hex digits and two spaces in
+ preceding column. */
+ value_column_2 = value_column_1 + 2 + 16 + 2,
+ };
- fputs_filtered (name, file);
- print_spaces_filtered (15 - strlen (name), file);
+ format_stream.puts (name);
+ pad_to_column (format_stream, value_column_1);
print_raw_format = (value_entirely_available (val)
&& !value_optimized_out (val));
val_print (regtype,
value_embedded_offset (val), 0,
- file, 0, val, &opts, current_language);
+ &format_stream, 0, val, &opts, current_language);
if (print_raw_format)
{
- fprintf_filtered (file, "\t(raw ");
- print_hex_chars (file, valaddr, TYPE_LENGTH (regtype), byte_order,
- true);
- fprintf_filtered (file, ")");
+ pad_to_column (format_stream, value_column_2);
+ format_stream.puts ("(raw ");
+ print_hex_chars (&format_stream, valaddr, TYPE_LENGTH (regtype),
+ byte_order, true);
+ format_stream.putc (')');
}
}
else
opts.deref_ref = 1;
val_print (regtype,
value_embedded_offset (val), 0,
- file, 0, val, &opts, current_language);
+ &format_stream, 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)
{
+ pad_to_column (format_stream, value_column_2);
get_user_print_options (&opts);
opts.deref_ref = 1;
- fprintf_filtered (file, "\t");
val_print (regtype,
value_embedded_offset (val), 0,
- file, 0, val, &opts, current_language);
+ &format_stream, 0, val, &opts, current_language);
}
}
+ fputs_filtered (format_stream.c_str (), file);
fprintf_filtered (file, "\n");
}
int regnum, int print_all)
{
int i;
- const int numregs = gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
+ const int numregs = gdbarch_num_cooked_regs (gdbarch);
for (i = 0; i < numregs; i++)
{
}
void
-registers_info (char *addr_exp, int fpregs)
+registers_info (const char *addr_exp, int fpregs)
{
struct frame_info *frame;
struct gdbarch *gdbarch;
while (*addr_exp != '\0')
{
- char *start;
+ const char *start;
const char *end;
/* Skip leading white space. */
/* User registers lie completely outside of the range of
normal registers. Catch them early so that the target
never sees them. */
- if (regnum >= gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch))
+ if (regnum >= gdbarch_num_cooked_regs (gdbarch))
{
struct value *regval = value_of_user_reg (regnum, frame);
const char *regname = user_reg_map_regnum_to_name (gdbarch,
int regnum;
for (regnum = 0;
- regnum < gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
+ regnum < gdbarch_num_cooked_regs (gdbarch);
regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, group))
}
static void
-info_all_registers_command (char *addr_exp, int from_tty)
+info_all_registers_command (const char *addr_exp, int from_tty)
{
registers_info (addr_exp, 1);
}
static void
-info_registers_command (char *addr_exp, int from_tty)
+info_registers_command (const char *addr_exp, int from_tty)
{
registers_info (addr_exp, 0);
}
int regnum;
int printed_something = 0;
- for (regnum = 0;
- regnum < gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
- regnum++)
+ for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, vector_reggroup))
{
}
static void
-info_vector_command (char *args, int from_tty)
+info_vector_command (const char *args, int from_tty)
{
if (!target_has_registers)
error (_("The program has no registers now."));
/* Kill the inferior process. Make us have no inferior. */
static void
-kill_command (char *arg, int from_tty)
+kill_command (const 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))
+ if (inferior_ptid == null_ptid)
error (_("The program is not being run."));
if (!query (_("Kill the program being debugged? ")))
error (_("Not confirmed."));
+
+ int pid = current_inferior ()->pid;
+ /* Save the pid as a string before killing the inferior, since that
+ may unpush the current target, and we need the string after. */
+ std::string pid_str = target_pid_to_str (ptid_t (pid));
+ int infnum = current_inferior ()->num;
+
target_kill ();
+ if (print_inferior_events)
+ printf_unfiltered (_("[Inferior %d (%s) killed]\n"),
+ infnum, pid_str.c_str ());
+
/* If we still have other inferiors to debug, then don't mess with
with their threads. */
if (!have_inferiors ())
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
+/* Used in `attach&' command. Proceed threads of inferior INF iff
they stopped due to debugger request, and when they did, they
- reported a clean stop (GDB_SIGNAL_0). Do not proceed threads
- that have been explicitly been told to stop. */
-
-static int
-proceed_after_attach_callback (struct thread_info *thread,
- void *arg)
-{
- int pid = * (int *) arg;
-
- if (ptid_get_pid (thread->ptid) == pid
- && !is_exited (thread->ptid)
- && !is_executing (thread->ptid)
- && !thread->stop_requested
- && thread->suspend.stop_signal == GDB_SIGNAL_0)
- {
- switch_to_thread (thread->ptid);
- clear_proceed_status (0);
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
- }
-
- return 0;
-}
+ reported a clean stop (GDB_SIGNAL_0). Do not proceed threads that
+ have been explicitly been told to stop. */
static void
-proceed_after_attach (int pid)
+proceed_after_attach (inferior *inf)
{
/* Don't error out if the current thread is running, because
there may be other stopped threads. */
/* Backup current thread and selected frame. */
scoped_restore_current_thread restore_thread;
- iterate_over_threads (proceed_after_attach_callback, &pid);
+ for (thread_info *thread : inf->non_exited_threads ())
+ if (!thread->executing
+ && !thread->stop_requested
+ && thread->suspend.stop_signal == GDB_SIGNAL_0)
+ {
+ switch_to_thread (thread);
+ clear_proceed_status (0);
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
+ }
}
/* See inferior.h. */
/* If no exec file is yet known, try to determine it from the
process itself. */
if (get_exec_file (0) == NULL)
- exec_file_locate_attach (ptid_get_pid (inferior_ptid), 1, from_tty);
+ exec_file_locate_attach (inferior_ptid.pid (), 1, from_tty);
else
{
reopen_exec_file ();
}
/* Take any necessary post-attaching actions for this platform. */
- target_post_attach (ptid_get_pid (inferior_ptid));
+ target_post_attach (inferior_ptid.pid ());
- post_create_inferior (¤t_target, from_tty);
+ post_create_inferior (current_top_target (), from_tty);
}
/* What to do after the first program stops after attaching. */
already running threads. If a thread has been stopped with a
signal, leave it be. */
if (non_stop)
- proceed_after_attach (inferior->pid);
+ proceed_after_attach (inferior);
else
{
if (inferior_thread ()->suspend.stop_signal == GDB_SIGNAL_0)
Be sure to explicitly stop all threads of the process. This
should have no effect on already stopped threads. */
if (non_stop)
- target_stop (pid_to_ptid (inferior->pid));
+ target_stop (ptid_t (inferior->pid));
else if (target_is_non_stop_p ())
{
- struct thread_info *thread;
struct thread_info *lowest = inferior_thread ();
- int pid = current_inferior ()->pid;
stop_all_threads ();
stop. For consistency, always select the thread with
lowest GDB number, which should be the main thread, if it
still exists. */
- ALL_NON_EXITED_THREADS (thread)
- {
- if (ptid_get_pid (thread->ptid) == pid)
- {
- if (thread->inf->num < lowest->inf->num
- || thread->per_inf_num < lowest->per_inf_num)
- lowest = thread;
- }
- }
+ for (thread_info *thread : current_inferior ()->non_exited_threads ())
+ if (thread->inf->num < lowest->inf->num
+ || thread->per_inf_num < lowest->per_inf_num)
+ lowest = thread;
- switch_to_thread (lowest->ptid);
+ switch_to_thread (lowest);
}
/* Tell the user/frontend where we're stopped. */
and allows us to start debugging it. */
void
-attach_command (char *args, int from_tty)
+attach_command (const char *args, int from_tty)
{
int async_exec;
- struct cleanup *args_chain;
struct target_ops *attach_target;
struct inferior *inferior = current_inferior ();
enum attach_post_wait_mode mode;
this function should probably be moved into target_pre_inferior. */
target_pre_inferior (from_tty);
- args = strip_bg_char (args, &async_exec);
- args_chain = make_cleanup (xfree, args);
+ gdb::unique_xmalloc_ptr<char> stripped = strip_bg_char (args, &async_exec);
+ args = stripped.get ();
attach_target = find_attach_target ();
prepare_execution_command (attach_target, async_exec);
- if (non_stop && !attach_target->to_supports_non_stop (attach_target))
+ if (non_stop && !attach_target->supports_non_stop ())
error (_("Cannot attach to this target in non-stop mode"));
- attach_target->to_attach (attach_target, args, from_tty);
+ attach_target->attach (args, from_tty);
/* to_attach should push the target, so after this point we
shouldn't refer to attach_target again. */
attach_target = NULL;
else
/* The user requested an `attach', so stop all threads of this
inferior. */
- target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid)));
+ target_stop (ptid_t (inferior_ptid.pid ()));
}
mode = async_exec ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_STOP;
/* Some system don't generate traps when attaching to inferior.
E.g. Mach 3 or GNU hurd. */
- if (!target_attach_no_wait)
+ if (!target_attach_no_wait ())
{
struct attach_command_continuation_args *a;
a->mode = mode;
add_inferior_continuation (attach_command_continuation, a,
attach_command_continuation_free_args);
- /* Done with ARGS. */
- do_cleanups (args_chain);
if (!target_is_async_p ())
mark_infrun_async_event_handler ();
return;
}
- /* Done with ARGS. */
- do_cleanups (args_chain);
-
attach_post_wait (args, from_tty, mode);
}
as stopped. */
void
-notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
+notice_new_inferior (thread_info *thr, int leave_running, int from_tty)
{
enum attach_post_wait_mode mode
= leave_running ? ATTACH_POST_WAIT_RESUME : ATTACH_POST_WAIT_NOTHING;
/* Avoid reading registers -- we haven't fetched the target
description yet. */
- switch_to_thread_no_regs (find_thread_ptid (ptid));
+ switch_to_thread_no_regs (thr);
/* When we "notice" a new inferior we need to do all the things we
would normally do if we had just attached to it. */
- if (is_executing (inferior_ptid))
+ if (thr->executing)
{
struct attach_command_continuation_args *a;
struct inferior *inferior = current_inferior ();
*/
void
-detach_command (char *args, int from_tty)
+detach_command (const char *args, int from_tty)
{
dont_repeat (); /* Not for the faint of heart. */
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
error (_("The program is not being run."));
query_if_trace_running (from_tty);
disconnect_tracing ();
- target_detach (args, from_tty);
+ target_detach (current_inferior (), from_tty);
/* The current inferior process was just detached successfully. Get
rid of breakpoints that no longer make sense. Note we don't do
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
- threads. */
- if (!have_inferiors ())
- init_thread_list ();
-
if (deprecated_detach_hook)
deprecated_detach_hook ();
}
stopped processes on some native platforms (e.g. GNU/Linux). */
static void
-disconnect_command (char *args, int from_tty)
+disconnect_command (const char *args, int from_tty)
{
dont_repeat (); /* Not for the faint of heart. */
query_if_trace_running (from_tty);
if (non_stop)
target_stop (ptid);
else
- target_interrupt (ptid);
+ target_interrupt ();
/* Tag the thread as having been explicitly requested to stop, so
other parts of gdb know not to resume this thread automatically,
if the `-a' switch is used. */
static void
-interrupt_command (char *args, int from_tty)
+interrupt_command (const char *args, int from_tty)
{
if (target_can_async_p ())
{
int regnum;
int printed_something = 0;
- for (regnum = 0;
- regnum < gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_regs (gdbarch);
- regnum++)
+ for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, float_reggroup))
{
}
static void
-info_float_command (char *args, int from_tty)
+info_float_command (const char *args, int from_tty)
{
struct frame_info *frame;
}
\f
static void
-unset_command (char *args, int from_tty)
+unset_command (const char *args, int from_tty)
{
printf_filtered (_("\"unset\" must be followed by the "
"name of an unset subcommand.\n"));
/* Implement `info proc' when given without any futher parameters. */
static void
-info_proc_cmd (char *args, int from_tty)
+info_proc_cmd (const char *args, int from_tty)
{
info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
}
info_proc_cmd_1 (args, IP_EXE, from_tty);
}
+/* Implement `info proc files'. */
+
+static void
+info_proc_cmd_files (const char *args, int from_tty)
+{
+ info_proc_cmd_1 (args, IP_FILES, from_tty);
+}
+
/* Implement `info proc all'. */
static void
c = add_com ("jump", class_run, jump_command, _("\
Continue program being debugged at specified line or address.\n\
-Usage: jump <location>\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);
c = add_info ("registers", info_registers_command, _("\
List of integer registers and their contents, for selected stack frame.\n\
-Register name as argument means describe only that register."));
+One or more register names as argument means describe the given registers.\n\
+One or more register group names as argument means describe the registers\n\
+in the named register groups."));
add_info_alias ("r", "registers", 1);
set_cmd_completer (c, reg_or_group_completer);
c = add_info ("all-registers", info_all_registers_command, _("\
List of all registers and their contents, for selected stack frame.\n\
-Register name as argument means describe only that register."));
+One or more register names as argument means describe the given registers.\n\
+One or more register group names as argument means describe the registers\n\
+in the named register groups."));
set_cmd_completer (c, reg_or_group_completer);
add_info ("program", info_program_command,
add_prefix_cmd ("proc", class_info, info_proc_cmd,
_("\
-Show /proc process information about any running process.\n\
+Show additional information about a 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."),
+List memory regions mapped by the specified process."),
&info_proc_cmdlist);
add_cmd ("stat", class_info, info_proc_cmd_stat, _("\
&info_proc_cmdlist);
add_cmd ("cwd", class_info, info_proc_cmd_cwd, _("\
-List current working directory of the process."),
+List current working directory of the specified process."),
&info_proc_cmdlist);
add_cmd ("cmdline", class_info, info_proc_cmd_cmdline, _("\
-List command line arguments of the process."),
+List command line arguments of the specified process."),
&info_proc_cmdlist);
add_cmd ("exe", class_info, info_proc_cmd_exe, _("\
-List absolute filename for executable of the process."),
+List absolute filename for executable of the specified process."),
+ &info_proc_cmdlist);
+
+ add_cmd ("files", class_info, info_proc_cmd_files, _("\
+List files opened by the specified process."),
&info_proc_cmdlist);
add_cmd ("all", class_info, info_proc_cmd_all, _("\
-List all available /proc info."),
+List all available info about the specified process."),
&info_proc_cmdlist);
}