#include "defs.h"
#include <signal.h>
#include "gdb_string.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "frame.h"
#include "inferior.h"
#include "environ.h"
#include "value.h"
#include "gdbcmd.h"
#include "symfile.h"
#include "gdbcore.h"
#include "target.h"
#include "language.h"
#include "symfile.h"
#include "objfiles.h"
#include "completer.h"
#include "ui-out.h"
#include "event-top.h"
#include "parser-defs.h"
#include "top.h"
#include "regcache.h"
#include "reggroups.h"
#include "block.h"
#include "solib.h"
#include <ctype.h>
#include "gdb_assert.h"
#include "checkpoint.h"
#ifndef PROCESS_COMPLETER
#define PROCESS_COMPLETER noop_completer
#endif
extern char **process_completer (char *, char *);
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);
static void nofp_registers_info (char *, int);
static void print_return_value (int struct_return, struct type *value_type);
static void finish_command_continuation (struct continuation_arg *);
static void until_next_command (int);
static void until_command (char *, int);
static void path_info (char *, int);
static void path_command (char *, int);
static void unset_command (char *, int);
static void float_info (char *, int);
static void detach_command (char *, int);
static void disconnect_command (char *, int);
static void unset_environment_command (char *, int);
static void set_environment_command (char *, int);
static void environment_info (char *, int);
static void program_info (char *, int);
void pid_info (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 step_1_continuation (struct continuation_arg *arg);
void re_exec_1 ();
void re_exec_1_continuation (struct continuation_arg *arg);
void re_exec_once (int count);
static void next_command (char *, int);
static void step_command (char *, int);
static void run_command (char *, int);
static void run_no_args_command (char *args, int from_tty);
static void go_command (char *line_no, int from_tty);
int strip_bg_char (char **);
void _initialize_infcmd (void);
#define GO_USAGE "Usage: go <location>\n"
#define ERROR_NO_INFERIOR \
if (!target_has_execution) error (_("The program is not being run."));
static char *inferior_args;
static int inferior_argc;
static char **inferior_argv;
int start_with_shell_flag = STARTUP_WITH_SHELL;
static char *inferior_io_terminal;
ptid_t inferior_ptid;
enum target_signal stop_signal;
CORE_ADDR stop_pc;
bpstat stop_bpstat;
int breakpoint_proceeded;
int stop_step;
int stop_stack_dummy;
int stopped_by_random_signal;
CORE_ADDR step_range_start;
CORE_ADDR step_range_end;
struct frame_id step_frame_id;
enum step_over_calls_kind step_over_calls;
int step_multi;
struct gdb_environ *inferior_environ;
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));
}
const char *
get_inferior_io_terminal (void)
{
return inferior_io_terminal;
}
char *
get_inferior_args (void)
{
if (inferior_argc != 0)
{
char *n, *old;
n = gdbarch_construct_inferior_arguments (current_gdbarch,
inferior_argc, inferior_argv);
old = set_inferior_args (n);
xfree (old);
}
if (inferior_args == NULL)
inferior_args = xstrdup ("");
return inferior_args;
}
char *
set_inferior_args (char *newargs)
{
char *saved_args = inferior_args;
inferior_args = newargs;
inferior_argc = 0;
inferior_argv = 0;
return saved_args;
}
void
set_inferior_args_vector (int argc, char **argv)
{
inferior_argc = argc;
inferior_argv = argv;
}
static void
notice_args_set (char *args, int from_tty, struct cmd_list_element *c)
{
inferior_argc = 0;
inferior_argv = 0;
}
static void
notice_args_read (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
deprecated_show_value_hack (file, from_tty, c, value);
get_inferior_args ();
}
char *
construct_inferior_arguments (struct gdbarch *gdbarch, int argc, char **argv)
{
char *result;
if (start_with_shell_flag)
{
char *special = "\"!#$&*()\\|[]{}<>?'\"`~^; \t\n";
int i;
int length = 0;
char *out, *cp;
for (i = 0; i < argc; ++i)
length += 2 * strlen (argv[i]) + 1 + 2 * (argv[i][0] == '\0');
result = (char *) xmalloc (length);
out = result;
for (i = 0; i < argc; ++i)
{
if (i > 0)
*out++ = ' ';
if (argv[i][0] == '\0')
{
*out++ = '\'';
*out++ = '\'';
}
else
{
for (cp = argv[i]; *cp; ++cp)
{
if (strchr (special, *cp) != NULL)
*out++ = '\\';
*out++ = *cp;
}
}
}
*out = '\0';
}
else
{
int i;
int length = 0;
for (i = 0; i < argc; ++i)
{
char *cp = strchr (argv[i], ' ');
if (cp == NULL)
cp = strchr (argv[i], '\t');
if (cp == NULL)
cp = strchr (argv[i], '\n');
if (cp != NULL)
error (_("can't handle command-line argument containing whitespace"));
length += strlen (argv[i]) + 1;
}
result = (char *) xmalloc (length);
result[0] = '\0';
for (i = 0; i < argc; ++i)
{
if (i > 0)
strcat (result, " ");
strcat (result, argv[i]);
}
}
return result;
}
int
strip_bg_char (char **args)
{
char *p = NULL;
p = strchr (*args, '&');
if (p)
{
if (p == (*args + strlen (*args) - 1))
{
if (strlen (*args) > 1)
{
do
p--;
while (*p == ' ' || *p == '\t');
*(p + 1) = '\0';
}
else
*args = 0;
return 1;
}
}
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);
}
void
kill_if_already_running (int from_tty)
{
if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
{
if (from_tty
&& !query ("The program being debugged has been started already.\n\
Start it from the beginning? "))
error (_("Program not restarted."));
target_kill ();
#if defined(SOLIB_RESTART)
SOLIB_RESTART ();
#endif
init_wait_for_inferior ();
}
}
static void
run_command_1 (char *args, int from_tty, int tbreak_at_main)
{
char *exec_file;
dont_repeat ();
kill_if_already_running (from_tty);
clear_breakpoint_hit_counts ();
clear_checkpoints ();
objfile_purge_solibs ();
do_run_cleanups (NULL);
reopen_exec_file ();
reread_symbols ();
if (tbreak_at_main)
tbreak_command (main_name (), 0);
exec_file = (char *) get_exec_file (0);
if (!args)
{
if (target_can_async_p ())
async_disable_stdin ();
}
else
{
int async_exec = strip_bg_char (&args);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
if (args)
{
char *old_args = set_inferior_args (xstrdup (args));
xfree (old_args);
}
}
if (from_tty)
{
ui_out_field_string (uiout, NULL, "Starting program");
ui_out_text (uiout, ": ");
if (exec_file)
ui_out_field_string (uiout, "execfile", exec_file);
ui_out_spaces (uiout, 1);
ui_out_field_string (uiout, "infargs", get_inferior_args ());
ui_out_text (uiout, "\n");
ui_out_flush (uiout);
}
if (state_change_hook)
{
state_change_hook (STATE_INFERIOR_LOGICALLY_RUNNING);
}
if (run_command_hook)
{
if (run_command_hook() == 0)
return;
}
target_create_inferior (exec_file, get_inferior_args (),
environ_vector (inferior_environ), from_tty);
if (ptid_equal (inferior_ptid, null_ptid))
{
target_executing = 0;
if (target_can_async_p ())
{
async_enable_stdin (0);
}
}
}
static void
run_command (char *args, int from_tty)
{
run_command_1 (args, from_tty, 0);
}
static void
run_no_args_command (char *args, int from_tty)
{
char *old_args = set_inferior_args (xstrdup (""));
xfree (old_args);
}
static void
start_command (char *args, int from_tty)
{
if (!have_minimal_symbols ())
error (_("No symbol table loaded. Use the \"file\" command."));
run_command_1 (args, from_tty, 1);
}
void
continue_command (char *proc_count_exp, int from_tty)
{
int async_exec = 0;
ERROR_NO_INFERIOR;
if (proc_count_exp != NULL)
async_exec = strip_bg_char (&proc_count_exp);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
if (proc_count_exp != NULL)
{
bpstat bs = stop_bpstat;
int num = bpstat_num (&bs);
if (num <= 0 && from_tty)
{
printf_filtered
("Not stopped at any breakpoint; argument ignored.\n");
}
while (num != 0)
{
set_ignore_count (num,
parse_and_eval_long (proc_count_exp) - 1,
from_tty);
if (from_tty)
printf_filtered (" ");
num = bpstat_num (&bs);
}
}
if (from_tty)
printf_filtered (_("Continuing.\n"));
clear_proceed_status ();
if (state_change_hook)
state_change_hook (STATE_INFERIOR_LOGICALLY_RUNNING);
if (continue_command_hook)
continue_command_hook();
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
}
static void
step_command (char *count_string, int from_tty)
{
step_1 (0, 0, count_string);
}
static void
next_command (char *count_string, int from_tty)
{
step_1 (1, 0, count_string);
}
void
stepi_command (char *count_string, int from_tty)
{
step_1 (0, 1, count_string);
}
void
nexti_command (char *count_string, int from_tty)
{
step_1 (1, 1, count_string);
}
static void
disable_longjmp_breakpoint_cleanup (void *ignore)
{
disable_longjmp_breakpoint ();
}
static void
step_1 (int skip_subroutines, int single_inst, char *count_string)
{
int count = 1;
struct frame_info *frame;
struct cleanup *cleanups = 0;
int async_exec = 0;
ERROR_NO_INFERIOR;
if (count_string)
async_exec = strip_bg_char (&count_string);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
count = count_string ? parse_and_eval_long (count_string) : 1;
if (!single_inst || skip_subroutines)
{
enable_longjmp_breakpoint ();
if (!target_can_async_p ())
cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 );
else
make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 );
}
if (!target_can_async_p ())
{
for (; count > 0; count--)
{
clear_proceed_status ();
frame = get_current_frame ();
if (!frame)
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
if (step_range_end == 0)
{
char *name;
if (find_pc_partial_function (stop_pc, &name, &step_range_start,
&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);
}
}
else
{
step_range_start = step_range_end = 1;
if (!skip_subroutines)
step_over_calls = STEP_OVER_NONE;
}
if (skip_subroutines)
step_over_calls = STEP_OVER_ALL;
step_multi = (count > 1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
if (!stop_step)
break;
}
if (!single_inst || skip_subroutines)
do_cleanups (cleanups);
return;
}
else
{
if (target_can_async_p ())
{
if (stepping_command_hook)
stepping_command_hook ();
step_once (skip_subroutines, single_inst, count);
}
}
}
static void
step_1_continuation (struct continuation_arg *arg)
{
int count;
int skip_subroutines;
int single_inst;
skip_subroutines = arg->data.integer;
single_inst = arg->next->data.integer;
count = arg->next->next->data.integer;
if (stop_step)
step_once (skip_subroutines, single_inst, count - 1);
else
if (!single_inst || skip_subroutines)
do_exec_cleanups (ALL_CLEANUPS);
}
void
step_once (int skip_subroutines, int single_inst, int count)
{
struct continuation_arg *arg1;
struct continuation_arg *arg2;
struct continuation_arg *arg3;
struct frame_info *frame;
if (count > 0)
{
clear_proceed_status ();
frame = get_current_frame ();
if (!frame)
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
if (step_range_end == 0 && step_stop_if_no_debug)
{
step_range_start = step_range_end = 1;
}
else if (step_range_end == 0)
{
char *name;
if (find_pc_partial_function (stop_pc, &name, &step_range_start,
&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);
}
}
else
{
step_range_start = step_range_end = 1;
if (!skip_subroutines)
step_over_calls = STEP_OVER_NONE;
}
if (skip_subroutines)
step_over_calls = STEP_OVER_ALL;
step_multi = (count > 1);
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg2 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg3 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = arg2;
arg1->data.integer = skip_subroutines;
arg2->next = arg3;
arg2->data.integer = single_inst;
arg3->next = NULL;
arg3->data.integer = count;
add_intermediate_continuation (step_1_continuation, arg1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
}
}
char *rx_cp;
char *active_checkpoint;
int magic_flag = 0;
void
re_execute_command (char *args, int from_tty)
{
int cpn = (args ? parse_and_eval_long (args) : 1);
rx_cp = find_checkpoint (cpn);
if (rx_cp == NULL)
{
printf ("Checkpoint not found\n");
return;
}
printf ("Re-executing to ");
print_checkpoint_info (rx_cp);
re_exec_1 ();
}
void
re_exec_1 ()
{
int count = 1;
struct frame_info *frame;
int async_exec = 0;
magic_flag = 0;
ERROR_NO_INFERIOR;
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
count = 100;
if (!target_can_async_p ())
{
for (; count > 0; count--)
{
clear_proceed_status ();
frame = get_current_frame ();
if (!frame)
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
step_range_start = step_range_end = 1;
step_over_calls = STEP_OVER_NONE;
step_multi = (count > 1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
if (!stop_step)
break;
}
return;
}
else
{
if (target_can_async_p ())
{
if (stepping_command_hook)
stepping_command_hook ();
re_exec_once (count);
}
}
}
void
re_exec_1_continuation (struct continuation_arg *arg)
{
int count;
count = arg->data.integer;
if (stop_step)
re_exec_once (count - 1);
}
void
re_exec_once (int count)
{
struct continuation_arg *arg1;
struct frame_info *frame;
if (count <= 0)
{
printf ("Re-execution failed\n");
rx_cp = NULL;
return;
}
if (magic_flag)
{
magic_flag = 0;
rx_cp = NULL;
return;
}
clear_proceed_status ();
frame = get_current_frame ();
if (!frame)
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
step_range_start = step_range_end = 1;
step_over_calls = STEP_OVER_NONE;
step_multi = (count > 1);
printf("Comparing against ");
print_checkpoint_info (active_checkpoint);
if (checkpoint_compare (rx_cp, active_checkpoint))
{
step_multi = 0;
magic_flag = 1;
rx_cp = NULL;
}
arg1 = (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = NULL;
arg1->data.integer = count;
add_intermediate_continuation (re_exec_1_continuation, arg1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
}
static void
jump_command (char *arg, int from_tty)
{
CORE_ADDR addr;
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct symbol *fn;
struct symbol *sfn;
int async_exec = 0;
ERROR_NO_INFERIOR;
if (arg != NULL)
async_exec = strip_bg_char (&arg);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!arg)
error_no_arg (_("starting address"));
sals = decode_line_spec_1 (arg, 1);
if (sals.nelts != 1)
{
error (_("Unreasonable jump request"));
}
sal = sals.sals[0];
xfree (sals.sals);
if (sal.symtab == 0 && sal.pc == 0)
error (_("No source file has been specified."));
resolve_sal_pc (&sal);
fn = get_frame_function (get_current_frame ());
sfn = find_pc_function (sal.pc);
if (fn != NULL && sfn != fn)
{
if (!query ("Line %d is not in `%s'. Jump anyway? ", sal.line,
SYMBOL_PRINT_NAME (fn)))
{
error (_("Not confirmed."));
}
}
if (sfn != NULL)
{
fixup_symbol_section (sfn, 0);
if (section_is_overlay (SYMBOL_BFD_SECTION (sfn)) &&
!section_is_mapped (SYMBOL_BFD_SECTION (sfn)))
{
if (!query ("WARNING!!! Destination is in unmapped overlay! Jump anyway? "))
{
error (_("Not confirmed."));
}
}
}
addr = sal.pc;
if (from_tty)
{
printf_filtered (_("Continuing at "));
deprecated_print_address_numeric (addr, 1, gdb_stdout);
printf_filtered (".\n");
}
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
clear_proceed_status ();
proceed (addr, TARGET_SIGNAL_0, 0);
}
static void
go_command (char *line_no, int from_tty)
{
if (line_no == (char *) NULL || !*line_no)
printf_filtered (GO_USAGE);
else
{
tbreak_command (line_no, from_tty);
jump_command (line_no, from_tty);
}
}
static void
signal_command (char *signum_exp, int from_tty)
{
enum target_signal oursig;
dont_repeat ();
ERROR_NO_INFERIOR;
if (!signum_exp)
error_no_arg (_("signal number"));
oursig = target_signal_from_name (signum_exp);
if (oursig == TARGET_SIGNAL_UNKNOWN)
{
int num = parse_and_eval_long (signum_exp);
if (num == 0)
oursig = TARGET_SIGNAL_0;
else
oursig = target_signal_from_command (num);
}
if (from_tty)
{
if (oursig == TARGET_SIGNAL_0)
printf_filtered (_("Continuing with no signal.\n"));
else
printf_filtered (_("Continuing with signal %s.\n"),
target_signal_to_name (oursig));
}
clear_proceed_status ();
if (state_change_hook)
{
state_change_hook (STATE_INFERIOR_LOGICALLY_RUNNING);
}
proceed (oursig == TARGET_SIGNAL_0 ? (CORE_ADDR) -1 : stop_pc, oursig, 0);
}
static void
until_next_command (int from_tty)
{
struct frame_info *frame;
CORE_ADDR pc;
struct symbol *func;
struct symtab_and_line sal;
clear_proceed_status ();
frame = get_current_frame ();
pc = read_pc ();
func = find_pc_function (pc);
if (!func)
{
struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
if (msymbol == NULL)
error (_("Execution is not within a known function."));
step_range_start = SYMBOL_VALUE_ADDRESS (msymbol);
step_range_end = pc;
}
else
{
sal = find_pc_line (pc, 0);
step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
step_range_end = sal.end;
}
step_over_calls = STEP_OVER_ALL;
step_frame_id = get_frame_id (frame);
step_multi = 0;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
}
static void
until_command (char *arg, int from_tty)
{
int async_exec = 0;
if (!target_has_execution)
error (_("The program is not running."));
if (arg != NULL)
async_exec = strip_bg_char (&arg);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
if (arg)
until_break_command (arg, from_tty, 0);
else
until_next_command (from_tty);
}
static void
advance_command (char *arg, int from_tty)
{
int async_exec = 0;
if (!target_has_execution)
error (_("The program is not running."));
if (arg == NULL)
error_no_arg (_("a location"));
if (arg != NULL)
async_exec = strip_bg_char (&arg);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
until_break_command (arg, from_tty, 1);
}
static void
print_return_value (int struct_return, struct type *value_type)
{
struct gdbarch *gdbarch = current_gdbarch;
struct cleanup *old_chain;
struct ui_stream *stb;
struct value *value;
gdb_assert (TYPE_CODE (value_type) != TYPE_CODE_VOID);
switch (gdbarch_return_value (gdbarch, value_type, NULL, NULL, NULL))
{
case RETURN_VALUE_REGISTER_CONVENTION:
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
value = allocate_value (value_type);
CHECK_TYPEDEF (value_type);
gdbarch_return_value (current_gdbarch, value_type, stop_registers,
value_contents_raw (value), NULL);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
value = NULL;
break;
default:
internal_error (__FILE__, __LINE__, _("bad switch"));
}
if (value)
{
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_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, " = ");
value_print (value, stb->stream, 0, Val_no_prettyprint);
ui_out_field_stream (uiout, "return-value", stb);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
}
else
{
ui_out_text (uiout, "Value returned has type: ");
ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type));
ui_out_text (uiout, ".");
ui_out_text (uiout, " Cannot determine contents\n");
}
}
static void
finish_command_continuation (struct continuation_arg *arg)
{
struct symbol *function;
struct breakpoint *breakpoint;
struct cleanup *cleanups;
breakpoint = (struct breakpoint *) arg->data.pointer;
function = (struct symbol *) arg->next->data.pointer;
cleanups = (struct cleanup *) arg->next->next->data.pointer;
if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL
&& function != NULL)
{
struct type *value_type;
int struct_return;
int gcc_compiled;
value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
if (!value_type)
internal_error (__FILE__, __LINE__,
_("finish_command: function has no target type"));
if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
{
do_exec_cleanups (cleanups);
return;
}
CHECK_TYPEDEF (value_type);
gcc_compiled = BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function));
struct_return = using_struct_return (value_type, gcc_compiled);
print_return_value (struct_return, value_type);
}
do_exec_cleanups (cleanups);
}
static void
finish_command (char *arg, int from_tty)
{
struct symtab_and_line sal;
struct frame_info *frame;
struct symbol *function;
struct breakpoint *breakpoint;
struct cleanup *old_chain;
struct continuation_arg *arg1, *arg2, *arg3;
int async_exec = 0;
if (arg != NULL)
async_exec = strip_bg_char (&arg);
if (async_exec && !target_can_async_p ())
error (_("Asynchronous execution not supported on this target."));
if (!async_exec && target_can_async_p ())
{
async_disable_stdin ();
}
if (arg)
error (_("The \"finish\" command does not take any arguments."));
if (!target_has_execution)
error (_("The program is not running."));
if (deprecated_selected_frame == NULL)
error (_("No selected frame."));
frame = get_prev_frame (deprecated_selected_frame);
if (frame == 0)
error (_("\"finish\" not meaningful in the outermost frame."));
clear_proceed_status ();
sal = find_pc_line (get_frame_pc (frame), 0);
sal.pc = get_frame_pc (frame);
breakpoint = set_momentary_breakpoint (sal, get_frame_id (frame), bp_finish);
if (!target_can_async_p ())
old_chain = make_cleanup_delete_breakpoint (breakpoint);
else
old_chain = make_exec_cleanup_delete_breakpoint (breakpoint);
function = find_pc_function (get_frame_pc (deprecated_selected_frame));
if (from_tty)
{
printf_filtered (_("Run till exit from "));
print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
}
if (target_can_async_p ())
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg2 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg3 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
arg1->next = arg2;
arg2->next = arg3;
arg3->next = NULL;
arg1->data.pointer = breakpoint;
arg2->data.pointer = function;
arg3->data.pointer = old_chain;
add_continuation (finish_command_continuation, arg1);
}
proceed_to_finish = 1;
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
if (!target_can_async_p ())
{
if (bpstat_find_breakpoint (stop_bpstat, breakpoint) != NULL
&& function != NULL)
{
struct type *value_type;
int struct_return;
int gcc_compiled;
value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
if (!value_type)
internal_error (__FILE__, __LINE__,
_("finish_command: function has no target type"));
if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
return;
CHECK_TYPEDEF (value_type);
gcc_compiled = BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function));
struct_return = using_struct_return (value_type, gcc_compiled);
print_return_value (struct_return, value_type);
}
do_cleanups (old_chain);
}
}
static void
program_info (char *args, int from_tty)
{
bpstat bs = stop_bpstat;
int num = bpstat_num (&bs);
if (!target_has_execution)
{
printf_filtered (_("The program being debugged is not being run.\n"));
return;
}
target_files_info ();
printf_filtered (_("Program stopped at %s.\n"),
hex_string ((unsigned long) stop_pc));
if (stop_step)
printf_filtered (_("It stopped after being stepped.\n"));
else if (num != 0)
{
while (num != 0)
{
if (num < 0)
{
printf_filtered (_("\
It stopped at a breakpoint that has since been deleted.\n"));
}
else
printf_filtered (_("It stopped at breakpoint %d.\n"), num);
num = bpstat_num (&bs);
}
}
else if (stop_signal != TARGET_SIGNAL_0)
{
printf_filtered (_("It stopped with signal %s, %s.\n"),
target_signal_to_name (stop_signal),
target_signal_to_string (stop_signal));
}
if (!from_tty)
{
printf_filtered (_("\
Type \"info stack\" or \"info registers\" for more information.\n"));
}
}
void
pid_info (char *args, int from_tty)
{
if (!target_has_execution)
{
error ("The program being debugged is not being run.");
}
ui_out_text (uiout, "Inferior has process ID ");
ui_out_field_int (uiout, "process-id", PIDGET (inferior_ptid));
ui_out_text (uiout, ".\n");
ui_out_flush (uiout);
}
static void
environment_info (char *var, int from_tty)
{
if (var)
{
char *val = get_in_environ (inferior_environ, var);
if (val)
{
puts_filtered (var);
puts_filtered (" = ");
puts_filtered (val);
puts_filtered ("\n");
}
else
{
puts_filtered ("Environment variable \"");
puts_filtered (var);
puts_filtered ("\" not defined.\n");
}
}
else
{
char **vector = environ_vector (inferior_environ);
while (*vector)
{
puts_filtered (*vector++);
puts_filtered ("\n");
}
}
}
static void
set_environment_command (char *arg, int from_tty)
{
char *p, *val, *var;
int nullset = 0;
if (arg == 0)
error_no_arg (_("environment variable and value"));
p = (char *) strchr (arg, '=');
val = (char *) strchr (arg, ' ');
if (p != 0 && val != 0)
{
if (p > val)
while (*val == ' ')
val++;
if (p > val)
p = val - 1;
}
else if (val != 0 && p == 0)
p = val;
if (p == arg)
error_no_arg (_("environment variable to set"));
if (p == 0 || p[1] == 0)
{
nullset = 1;
if (p == 0)
p = arg + strlen (arg);
}
else
{
val = p + 1;
while (*val == ' ' || *val == '\t')
val++;
}
while (p != arg && (p[-1] == ' ' || p[-1] == '\t'))
p--;
var = savestring (arg, p - arg);
if (nullset)
{
printf_filtered (_("\
Setting environment variable \"%s\" to null value.\n"),
var);
set_in_environ (inferior_environ, var, "");
}
else
set_in_environ (inferior_environ, var, val);
xfree (var);
}
static void
unset_environment_command (char *var, int from_tty)
{
if (var == 0)
{
if (!from_tty || query (_("Delete all environment variables? ")))
{
free_environ (inferior_environ);
inferior_environ = make_environ ();
}
}
else
unset_in_environ (inferior_environ, var);
}
static const char path_var_name[] = "PATH";
static void
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 ("\n");
}
static void
path_command (char *dirname, int from_tty)
{
char *exec_path;
char *env;
dont_repeat ();
env = get_in_environ (inferior_environ, path_var_name);
if (!env)
env = "";
exec_path = xstrdup (env);
mod_path (dirname, &exec_path);
set_in_environ (inferior_environ, path_var_name, exec_path);
xfree (exec_path);
if (from_tty)
path_info ((char *) NULL, from_tty);
}
void
default_print_registers_info (struct gdbarch *gdbarch,
struct ui_file *file,
struct frame_info *frame,
int regnum, int print_all)
{
int i;
const int numregs = NUM_REGS + NUM_PSEUDO_REGS;
gdb_byte buffer[MAX_REGISTER_SIZE];
for (i = 0; i < numregs; i++)
{
if (regnum == -1)
{
if (print_all)
{
if (!gdbarch_register_reggroup_p (gdbarch, i, all_reggroup))
continue;
}
else
{
if (!gdbarch_register_reggroup_p (gdbarch, i, general_reggroup))
continue;
}
}
else
{
if (i != regnum)
continue;
}
if (REGISTER_NAME (i) == NULL || *(REGISTER_NAME (i)) == '\0')
continue;
fputs_filtered (REGISTER_NAME (i), file);
print_spaces_filtered (15 - strlen (REGISTER_NAME (i)), file);
if (! frame_register_read (frame, i, buffer))
{
fprintf_filtered (file, "*value not available*\n");
continue;
}
if ((TYPE_CODE (register_type (current_gdbarch, i)) == TYPE_CODE_FLT)
|| TYPE_VECTOR (register_type (current_gdbarch, i)))
{
int j;
val_print (register_type (current_gdbarch, i), buffer, 0, 0,
file, 0, 1, 0, Val_pretty_default);
fprintf_filtered (file, "\t(raw 0x");
for (j = 0; j < register_size (current_gdbarch, i); j++)
{
int idx;
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
idx = j;
else
idx = register_size (current_gdbarch, i) - 1 - j;
fprintf_filtered (file, "%02x", (unsigned char) buffer[idx]);
}
fprintf_filtered (file, ")");
}
else
{
val_print (register_type (current_gdbarch, i), buffer, 0, 0,
file, 'x', 1, 0, Val_pretty_default);
if (TYPE_VECTOR (register_type (current_gdbarch, i)) == 0)
{
fprintf_filtered (file, "\t");
val_print (register_type (current_gdbarch, i), buffer, 0, 0,
file, 0, 1, 0, Val_pretty_default);
}
}
fprintf_filtered (file, "\n");
}
}
void
registers_info (char *addr_exp, int fpregs)
{
int regnum, numregs;
char *end;
if (!target_has_registers)
error (_("The program has no registers now."));
if (deprecated_selected_frame == NULL)
error (_("No selected frame."));
if (!addr_exp)
{
gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
deprecated_selected_frame, -1, fpregs);
return;
}
while (*addr_exp != '\0')
{
char *start;
const char *end;
if (isspace ((*addr_exp)))
{
addr_exp++;
continue;
}
if (addr_exp[0] == '$')
addr_exp++;
if (isspace ((*addr_exp)) || (*addr_exp) == '\0')
error (_("Missing register name"));
start = addr_exp;
while ((*addr_exp) != '\0' && !isspace ((*addr_exp)))
addr_exp++;
end = addr_exp;
{
int regnum = frame_map_name_to_regnum (deprecated_selected_frame,
start, end - start);
if (regnum >= 0)
{
gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
deprecated_selected_frame, regnum, fpregs);
continue;
}
}
{
char *endptr;
int regnum = strtol (start, &endptr, 0);
if (endptr == end
&& regnum >= 0
&& regnum < NUM_REGS + NUM_PSEUDO_REGS)
{
gdbarch_print_registers_info (current_gdbarch, gdb_stdout,
deprecated_selected_frame, regnum, fpregs);
continue;
}
}
{
struct reggroup *group;
for (group = reggroup_next (current_gdbarch, NULL);
group != NULL;
group = reggroup_next (current_gdbarch, group))
{
if (strncmp (start, reggroup_name (group), end - start) == 0)
break;
}
if (group != NULL)
{
int regnum;
for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
{
if (gdbarch_register_reggroup_p (current_gdbarch, regnum,
group))
gdbarch_print_registers_info (current_gdbarch,
gdb_stdout, deprecated_selected_frame,
regnum, fpregs);
}
continue;
}
}
error (_("Invalid register `%.*s'"), (int) (end - start), start);
}
}
void
all_registers_info (char *addr_exp, int from_tty)
{
registers_info (addr_exp, 1);
}
static void
nofp_registers_info (char *addr_exp, int from_tty)
{
registers_info (addr_exp, 0);
}
static void
print_vector_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
if (!target_has_registers)
error (_("The program has no registers now."));
if (deprecated_selected_frame == NULL)
error (_("No selected frame."));
if (gdbarch_print_vector_info_p (gdbarch))
gdbarch_print_vector_info (gdbarch, file, frame, args);
else
{
int regnum;
int printed_something = 0;
for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, vector_reggroup))
{
printed_something = 1;
gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1);
}
}
if (!printed_something)
fprintf_filtered (file, "No vector information\n");
}
}
static void
vector_info (char *args, int from_tty)
{
print_vector_info (current_gdbarch, gdb_stdout, deprecated_selected_frame, args);
}
void
attach_command (char *args, int from_tty)
{
char *exec_file;
char *full_exec_path = NULL;
dont_repeat ();
if (target_has_execution)
{
if (query ("A program is being debugged already. Kill it? "))
target_kill ();
else
error (_("Not killed."));
}
#ifdef CLEAR_SOLIB
CLEAR_SOLIB ();
#else
clear_solib ();
#endif
target_attach (args, from_tty);
target_terminal_init ();
init_wait_for_inferior ();
clear_proceed_status ();
#ifndef ATTACH_NO_WAIT
stop_soon = STOP_QUIETLY_NO_SIGSTOP;
wait_for_inferior ();
stop_soon = NO_STOP_QUIETLY;
#endif
exec_file = (char *) get_exec_file (0);
if (!exec_file)
{
exec_file = target_pid_to_exec_file (PIDGET (inferior_ptid));
if (exec_file)
{
if (!source_full_path_of (exec_file, &full_exec_path))
full_exec_path = savestring (exec_file, strlen (exec_file));
exec_file_attach (full_exec_path, from_tty);
symbol_file_add_main (full_exec_path, from_tty);
}
}
else
{
reopen_exec_file ();
reread_symbols ();
}
#ifdef SOLIB_ADD
SOLIB_ADD ((char *) 0, from_tty, ¤t_target, auto_solib_add);
#else
solib_add (NULL, from_tty, ¤t_target, auto_solib_add);
#endif
re_enable_breakpoints_in_shlibs (0);
target_post_attach (PIDGET (inferior_ptid));
target_terminal_inferior ();
normal_stop ();
if (deprecated_attach_hook)
deprecated_attach_hook ();
}
static void
detach_command (char *args, int from_tty)
{
dont_repeat ();
target_detach (args, from_tty);
#if defined(SOLIB_RESTART)
SOLIB_RESTART ();
#endif
if (deprecated_detach_hook)
deprecated_detach_hook ();
}
static void
disconnect_command (char *args, int from_tty)
{
dont_repeat ();
target_disconnect (args, from_tty);
#if defined(SOLIB_RESTART)
SOLIB_RESTART ();
#endif
if (deprecated_detach_hook)
deprecated_detach_hook ();
}
void
interrupt_target_command (char *args, int from_tty)
{
if (target_can_async_p ())
{
dont_repeat ();
target_stop ();
}
}
static void
print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
if (!target_has_registers)
error (_("The program has no registers now."));
if (deprecated_selected_frame == NULL)
error (_("No selected frame."));
if (gdbarch_print_float_info_p (gdbarch))
gdbarch_print_float_info (gdbarch, file, frame, args);
else
{
int regnum;
int printed_something = 0;
for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, float_reggroup))
{
printed_something = 1;
gdbarch_print_registers_info (gdbarch, file, frame, regnum, 1);
}
}
if (!printed_something)
fprintf_filtered (file, "\
No floating-point info available for this processor.\n");
}
}
static void
float_info (char *args, int from_tty)
{
print_float_info (current_gdbarch, gdb_stdout,
deprecated_selected_frame, args);
}
static void
unset_command (char *args, int from_tty)
{
printf_filtered (_("\
\"unset\" must be followed by the name of an unset subcommand.\n"));
help_list (unsetlist, "unset ", -1, gdb_stdout);
}
void
_initialize_infcmd (void)
{
struct cmd_list_element *c = NULL;
add_setshow_filename_cmd ("inferior-tty", class_run,
&inferior_io_terminal, _("\
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);
add_com_alias ("tty", "set inferior-tty", class_alias, 0);
add_setshow_optional_filename_cmd ("args", class_run,
&inferior_args, _("\
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,
&setlist, &showlist);
c = add_cmd ("environment", no_class, environment_info, _("\
The environment to give the program, or one variable's value.\n\
With an argument VAR, prints the value of environment variable VAR to\n\
give the program being debugged. With no arguments, prints the entire\n\
environment to be given to the program."), &showlist);
set_cmd_completer (c, noop_completer);
add_prefix_cmd ("unset", no_class, unset_command,
_("Complement to certain \"set\" commands."),
&unsetlist, "unset ", 0, &cmdlist);
c = add_cmd ("environment", class_run, unset_environment_command, _("\
Cancel environment variable VAR for the program.\n\
This does not affect the program until the next \"run\" command."),
&unsetlist);
set_cmd_completer (c, noop_completer);
c = add_cmd ("environment", class_run, set_environment_command, _("\
Set environment variable value to give the program.\n\
Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
VALUES of environment variables are uninterpreted strings.\n\
This does not affect the program until the next \"run\" command."),
&setlist);
set_cmd_completer (c, noop_completer);
c = add_com ("path", class_files, path_command, _("\
Add directory DIR(s) to beginning of search path for object files.\n\
$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."));
set_cmd_completer (c, filename_completer);
c = add_cmd ("paths", no_class, path_info, _("\
Current search path for finding object files.\n\
$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."),
&showlist);
set_cmd_completer (c, noop_completer);
c = 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\
\"target\" command (\"info files\" will show your target stack).\n\
The command may take as argument a process id, a process name\n\
(with an optional process-id as a suffix), or a device file.\n\
For a process id, you must have permission to send the process a signal,\n\
and it must have the same effective uid as the debugger.\n\
When using \"attach\" to an existing process, the debugger finds the\n\
program running in the process, looking first in the current working\n\
directory, or (if not found there) using the source file search path\n\
(see the \"directory\" command). You can also use the \"file\" command\n\
to specify the program, and to load its symbol table."));
set_cmd_completer (c, PROCESS_COMPLETER);
#ifdef PROCESS_COMPLETER_WORD_BREAK_CHARACTERS
#endif
add_com ("detach", class_run, detach_command, _("\
Detach a process or file previously attached.\n\
If a process, it is no longer traced, and it continues its execution. If\n\
you were debugging a file, the file is closed and gdb no longer accesses it."));
add_com ("disconnect", class_run, disconnect_command, _("\
Disconnect from a target.\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."));
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)."));
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)."));
add_com_alias ("ni", "nexti", class_alias, 0);
add_com ("finish", class_run, finish_command, _("\
Execute until selected stack frame returns.\n\
Upon return, the value returned is printed and put in the value history."));
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)."));
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)."));
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."));
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\
Execution will also stop upon exit from the current stack frame."));
set_cmd_completer (c, location_completer);
c = add_com ("jump", class_run, jump_command, _("\
Continue program being debugged at specified line or address.\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);
if (xdb_commands)
{
c = add_com ("go", class_run, go_command, _("\
Usage: go <location>\n\
Continue program being debugged, stopping at specified line or \n\
address.\n\
Give as argument either LINENUM or *ADDR, where ADDR is an \n\
expression for an address to start at.\n\
This command is a combination of tbreak and jump."));
set_cmd_completer (c, location_completer);
}
if (xdb_commands)
add_com_alias ("g", "go", class_run, 1);
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\
the breakpoint won't break until the Nth time it is reached)."));
add_com_alias ("c", "cont", class_run, 1);
add_com_alias ("fg", "cont", class_run, 1);
c = add_com ("run", class_run, run_command, _("\
Start debugged program. You may specify arguments to give it.\n\
If 'start-with-shell' is set to 1, args may include \"*\", or \"[...]\";\n\
they will be expanded using \"sh\". Input and output redirection with\n\
\">\", \"<\", or \">>\" will also be 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);
add_com_alias ("r", "run", class_run, 1);
if (xdb_commands)
add_com ("R", class_run, run_no_args_command,
_("Start debugged program with no arguments."));
c = add_com ("start", class_run, start_command, _("\
Run the debugged program until the beginning of the main procedure.\n\
You may specify arguments to give to your program, just as with the\n\
\"run\" command."));
set_cmd_completer (c, filename_completer);
add_com ("interrupt", class_run, interrupt_target_command,
_("Interrupt the execution of the debugged program."));
add_info ("registers", nofp_registers_info, _("\
List of integer registers and their contents, for selected stack frame.\n\
Register name as argument means describe only that register."));
add_info_alias ("r", "registers", 1);
if (xdb_commands)
add_com ("lr", class_info, nofp_registers_info, _("\
List of integer registers and their contents, for selected stack frame.\n\
Register name as argument means describe only that register."));
add_info ("all-registers", all_registers_info, _("\
List of all registers and their contents, for selected stack frame.\n\
Register name as argument means describe only that register."));
add_info ("program", program_info,
_("Execution status of the program."));
add_info ("pid", pid_info,
"Process ID of the program.");
add_info ("float", float_info,
_("Print the status of the floating point unit\n"));
add_info ("vector", vector_info,
_("Print the status of the vector unit\n"));
inferior_environ = make_environ ();
init_environ (inferior_environ);
smuggle_dyld_settings (inferior_environ);
}