#include "breakpoint.h"
#include "wait.h"
#include "gdbcore.h"
-#include "signame.h"
#include "command.h"
#include "terminal.h" /* For #ifdef TIOCGPGRP and new_tty */
#include "target.h"
/* Prototypes for local functions */
static void
-signals_info PARAMS ((char *));
+signals_info PARAMS ((char *, int));
static void
handle_command PARAMS ((char *, int));
#define SKIP_TRAMPOLINE_CODE(pc) 0
#endif
+/* For SVR4 shared libraries, each call goes through a small piece of
+ trampoline code in the ".init" section. IN_SOLIB_TRAMPOLINE evaluates
+ to nonzero if we are current stopped in one of these. */
+#ifndef IN_SOLIB_TRAMPOLINE
+#define IN_SOLIB_TRAMPOLINE(pc,name) 0
+#endif
+
+/* Notify other parts of gdb that might care that signal handling may
+ have changed for one or more signals. */
+#ifndef NOTICE_SIGNAL_HANDLING_CHANGE
+#define NOTICE_SIGNAL_HANDLING_CHANGE /* No actions */
+#endif
#ifdef TDESC
#include "tdesc.h"
/* Tables of how to react to signals; the user sets them. */
-static char signal_stop[NSIG];
-static char signal_print[NSIG];
-static char signal_program[NSIG];
+static unsigned char *signal_stop;
+static unsigned char *signal_print;
+static unsigned char *signal_program;
+
+#define SET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 1; \
+ } while (0)
+
+#define UNSET_SIGS(nsigs,sigs,flags) \
+ do { \
+ int signum = (nsigs); \
+ while (signum-- > 0) \
+ if ((sigs)[signum]) \
+ (flags)[signum] = 0; \
+ } while (0)
/* Nonzero if breakpoints are now inserted in the inferior. */
/* Nonstatic for initialization during xxx_create_inferior. FIXME. */
{
int pid;
char *shell_command;
- extern int sys_nerr;
- extern char *sys_errlist[];
char *shell_file;
static char default_shell_file[] = SHELL_FILE;
int len;
for the inferior. */
#ifdef USE_PROC_FS
- proc_set_exec_trap (); /* Use SVR4 /proc interface */
+ /* Use SVR4 /proc interface */
+ proc_set_exec_trap ();
#else
- call_ptrace (0, 0, 0, 0); /* "Trace me, Dr. Memory!" */
+ /* "Trace me, Dr. Memory!" */
+ call_ptrace (0, 0, (PTRACE_ARG3_TYPE) 0, 0);
#endif
/* There is no execlpe call, so we have to set the environment
execlp (shell_file, shell_file, "-c", shell_command, (char *)0);
fprintf (stderr, "Cannot exec %s: %s.\n", shell_file,
- errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+ safe_strerror (errno));
fflush (stderr);
_exit (0177);
}
correct program, and are poised at the first instruction of the
new program. */
#ifdef SOLIB_CREATE_INFERIOR_HOOK
- SOLIB_CREATE_INFERIOR_HOOK ();
+ SOLIB_CREATE_INFERIOR_HOOK (pid);
#endif
- /* Should this perhaps just be a "proceed" call? FIXME */
- insert_step_breakpoint ();
- breakpoints_failed = insert_breakpoints ();
- if (!breakpoints_failed)
- {
- breakpoints_inserted = 1;
- target_terminal_inferior();
- /* Start the child program going on its first instruction, single-
- stepping if we need to. */
- resume (bpstat_should_step (), 0);
- wait_for_inferior ();
- normal_stop ();
- }
+ /* Pedal to the metal. Away we go. */
+ proceed ((CORE_ADDR) -1, 0, 0);
}
/* Start remote-debugging of a machine over a serial link. */
#else
pid = atoi (args);
+ if (pid == getpid()) /* Trying to masturbate? */
+ error ("I refuse to debug myself!");
+
if (target_has_execution)
{
if (query ("A program is being debugged already. Kill it? "))
target_wait (&w);
+#ifdef SIGTRAP_STOP_AFTER_LOAD
+
+ /* Somebody called load(2), and it gave us a "trap signal after load".
+ Ignore it gracefully. */
+
+ SIGTRAP_STOP_AFTER_LOAD (w);
+#endif
+
/* See if the process still exists; clean up if it doesn't. */
if (WIFEXITED (w))
{
target_terminal_ours (); /* Must do this before mourn anyway */
if (WEXITSTATUS (w))
- printf ("\nProgram exited with code 0%o.\n",
+ printf_filtered ("\nProgram exited with code 0%o.\n",
(unsigned int)WEXITSTATUS (w));
else
if (!batch_mode())
- printf ("\nProgram exited normally.\n");
+ printf_filtered ("\nProgram exited normally.\n");
fflush (stdout);
target_mourn_inferior ();
#ifdef NO_SINGLE_STEP
target_terminal_ours (); /* Must do this before mourn anyway */
target_kill (); /* kill mourns as well */
#ifdef PRINT_RANDOM_SIGNAL
- printf ("\nProgram terminated: ");
+ printf_filtered ("\nProgram terminated: ");
PRINT_RANDOM_SIGNAL (stop_signal);
#else
- printf ("\nProgram terminated with signal %d, %s\n",
- stop_signal,
- stop_signal < NSIG
- ? sys_siglist[stop_signal]
- : "(undocumented)");
+ printf_filtered ("\nProgram terminated with signal %d, %s\n",
+ stop_signal, safe_strsignal (stop_signal));
#endif
- printf ("The inferior process no longer exists.\n");
+ printf_filtered ("The inferior process no longer exists.\n");
fflush (stdout);
#ifdef NO_SINGLE_STEP
one_stepped = 0;
stop_func_name = 0;
/* Don't care about return value; stop_func_start and stop_func_name
will both be 0 if it doesn't work. */
- (void) find_pc_partial_function (stop_pc, &stop_func_name,
- &stop_func_start);
+ find_pc_partial_function (stop_pc, &stop_func_name, &stop_func_start);
stop_func_start += FUNCTION_START_OFFSET;
another_trap = 0;
bpstat_clear (&stop_bpstat);
if (stop_signal == SIGTRAP
|| (breakpoints_inserted &&
(stop_signal == SIGILL
- || stop_signal == SIGEMT))
+#ifdef SIGEMT
+ || stop_signal == SIGEMT
+#endif
+ ))
|| stop_soon_quietly)
{
if (stop_signal == SIGTRAP && stop_after_trap)
#ifdef PRINT_RANDOM_SIGNAL
PRINT_RANDOM_SIGNAL (stop_signal);
#else
- printf ("\nProgram received signal %d, %s\n",
- stop_signal,
- stop_signal < NSIG
- ? sys_siglist[stop_signal]
- : "(undocumented)");
+ printf_filtered ("\nProgram received signal %d, %s\n",
+ stop_signal, safe_strsignal (stop_signal));
#endif /* PRINT_RANDOM_SIGNAL */
fflush (stdout);
}
#if 0
if (* step_frame_address == 0
|| (step_frame_address == stop_frame_address))
-#endif 0
+#endif
{
remove_step_breakpoint ();
step_resume_break_address = 0;
/* ==> See comments at top of file on this algorithm. <==*/
- if (stop_pc == stop_func_start
- && (stop_func_start != prev_func_start
- || prologue_pc != stop_func_start
- || stop_sp != prev_sp))
+ if ((stop_pc == stop_func_start
+ || IN_SOLIB_TRAMPOLINE (stop_pc, stop_func_name))
+ && (stop_func_start != prev_func_start
+ || prologue_pc != stop_func_start
+ || stop_sp != prev_sp))
{
/* It's a subroutine call.
(0) If we are not stepping over any calls ("stepi"), we
goto step_over_function;
tmp = SKIP_TRAMPOLINE_CODE (stop_pc);
- if (tmp != NULL)
+ if (tmp != 0)
stop_func_start = tmp;
if (find_pc_function (stop_func_start) != 0)
step_range_end = sal.end;
goto save_pc;
}
- abort(); /* We never fall through here */
+ /* We never fall through here */
}
if (trap_expected
{
target_terminal_ours_for_output ();
print_sys_errmsg ("ptrace", breakpoints_failed);
- printf ("Stopped; cannot insert breakpoints.\n\
+ printf_filtered ("Stopped; cannot insert breakpoints.\n\
The same program may be running in another process.\n");
}
if (remove_breakpoints ())
{
target_terminal_ours_for_output ();
- printf ("Cannot remove breakpoints because program is no longer writable.\n\
+ printf_filtered ("Cannot remove breakpoints because program is no longer writable.\n\
It might be running in another process.\n\
Further execution is probably impossible.\n");
}
step_resume_break_shadow);
}
\f
+int signal_stop_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_stop[signo] : 0);
+}
+
+int signal_print_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_print[signo] : 0);
+}
+
+int signal_pass_state (signo)
+ int signo;
+{
+ return ((signo >= 0 && signo < NSIG) ? signal_program[signo] : 0);
+}
+
static void
sig_print_header ()
{
sig_print_info (number)
int number;
{
- char *abbrev = sig_abbrev(number);
- if (abbrev == NULL)
+ char *name;
+
+ if ((name = strsigno (number)) == NULL)
printf_filtered ("%d\t\t", number);
else
- printf_filtered ("SIG%s (%d)\t", abbrev, number);
+ printf_filtered ("%s (%d)\t", name, number);
printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No");
printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No");
printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No");
- printf_filtered ("%s\n", sys_siglist[number]);
+ printf_filtered ("%s\n", safe_strsignal (number));
}
/* Specify how various signals in the inferior should be handled. */
char *args;
int from_tty;
{
- register char *p = args;
- int signum = 0;
- register int digits, wordlen;
- char *nextarg;
+ char **argv;
+ int digits, wordlen;
+ int sigfirst, signum, siglast;
+ int allsigs;
+ int nsigs;
+ unsigned char *sigs;
+ struct cleanup *old_chain;
+
+ if (args == NULL)
+ {
+ error_no_arg ("signal to handle");
+ }
- if (!args)
- error_no_arg ("signal to handle");
+ /* Allocate and zero an array of flags for which signals to handle. */
+
+ nsigs = signo_max () + 1;
+ sigs = (unsigned char *) alloca (nsigs);
+ memset (sigs, 0, nsigs);
+
+ /* Break the command line up into args. */
- while (*p)
+ argv = buildargv (args);
+ if (argv == NULL)
{
- /* Find the end of the next word in the args. */
- for (wordlen = 0;
- p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t';
- wordlen++);
- /* Set nextarg to the start of the word after the one we just
- found, and null-terminate this one. */
- if (p[wordlen] == '\0')
- nextarg = p + wordlen;
- else
- {
- p[wordlen] = '\0';
- nextarg = p + wordlen + 1;
- }
-
+ nomem (0);
+ }
+ old_chain = make_cleanup (freeargv, (char *) argv);
- for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++);
+ /* Walk through the args, looking for signal numbers, signal names, and
+ actions. Signal numbers and signal names may be interspersed with
+ actions, with the actions being performed for all signals cumulatively
+ specified. Signal ranges can be specified as <LOW>-<HIGH>. */
+
+ while (*argv != NULL)
+ {
+ wordlen = strlen (*argv);
+ for (digits = 0; isdigit ((*argv)[digits]); digits++) {;}
+ allsigs = 0;
+ sigfirst = siglast = -1;
- if (signum == 0)
+ if (wordlen >= 1 && !strncmp (*argv, "all", wordlen))
{
- /* It is the first argument--must be the signal to operate on. */
- if (digits == wordlen)
+ /* Apply action to all signals except those used by the
+ debugger. Silently skip those. */
+ allsigs = 1;
+ sigfirst = 0;
+ siglast = nsigs - 1;
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "stop", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_stop);
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 1 && !strncmp (*argv, "ignore", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "print", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_print);
+ }
+ else if (wordlen >= 2 && !strncmp (*argv, "pass", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "nostop", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 3 && !strncmp (*argv, "noignore", wordlen))
+ {
+ SET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "noprint", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_print);
+ UNSET_SIGS (nsigs, sigs, signal_stop);
+ }
+ else if (wordlen >= 4 && !strncmp (*argv, "nopass", wordlen))
+ {
+ UNSET_SIGS (nsigs, sigs, signal_program);
+ }
+ else if (digits > 0)
+ {
+ sigfirst = siglast = atoi (*argv);
+ if ((*argv)[digits] == '-')
{
- /* Numeric. */
- signum = atoi (p);
- if (signum <= 0 || signum >= NSIG)
- {
- p[wordlen] = '\0';
- error ("Invalid signal %s given as argument to \"handle\".", p);
- }
+ siglast = atoi ((*argv) + digits + 1);
}
- else
+ if (sigfirst > siglast)
{
- /* Symbolic. */
- signum = sig_number (p);
- if (signum == -1)
- error ("No such signal \"%s\"", p);
+ /* Bet he didn't figure we'd think of this case... */
+ signum = sigfirst;
+ sigfirst = siglast;
+ siglast = signum;
}
-
- if (signum == SIGTRAP || signum == SIGINT)
+ if (sigfirst < 0 || sigfirst >= nsigs)
{
- if (!query ("SIG%s is used by the debugger.\nAre you sure you want to change it? ", sig_abbrev (signum)))
- error ("Not confirmed.");
+ error ("Signal %d not in range 0-%d", sigfirst, nsigs - 1);
+ }
+ if (siglast < 0 || siglast >= nsigs)
+ {
+ error ("Signal %d not in range 0-%d", siglast, nsigs - 1);
}
}
- /* Else, if already got a signal number, look for flag words
- saying what to do for it. */
- else if (!strncmp (p, "stop", wordlen))
+ else if ((signum = strtosigno (*argv)) != 0)
{
- signal_stop[signum] = 1;
- signal_print[signum] = 1;
+ sigfirst = siglast = signum;
}
- else if (wordlen >= 2 && !strncmp (p, "print", wordlen))
- signal_print[signum] = 1;
- else if (wordlen >= 2 && !strncmp (p, "pass", wordlen))
- signal_program[signum] = 1;
- else if (!strncmp (p, "ignore", wordlen))
- signal_program[signum] = 0;
- else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen))
- signal_stop[signum] = 0;
- else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen))
+ else
{
- signal_print[signum] = 0;
- signal_stop[signum] = 0;
+ /* Not a number and not a recognized flag word => complain. */
+ error ("Unrecognized or ambiguous flag word: \"%s\".", *argv);
}
- else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen))
- signal_program[signum] = 0;
- else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen))
- signal_program[signum] = 1;
- /* Not a number and not a recognized flag word => complain. */
- else
+
+ /* If any signal numbers or symbol names were found, set flags for
+ which signals to apply actions to. */
+
+ for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++)
{
- error ("Unrecognized flag word: \"%s\".", p);
+ switch (signum)
+ {
+ case SIGTRAP:
+ case SIGINT:
+ if (!allsigs && !sigs[signum])
+ {
+ if (query ("%s is used by the debugger.\nAre you sure you want to change it? ", strsigno (signum)))
+ {
+ sigs[signum] = 1;
+ }
+ else
+ {
+ printf ("Not confirmed, unchanged.\n");
+ fflush (stdout);
+ }
+ }
+ break;
+ default:
+ sigs[signum] = 1;
+ break;
+ }
}
- /* Find start of next word. */
- p = nextarg;
- while (*p == ' ' || *p == '\t') p++;
+ argv++;
}
+ NOTICE_SIGNAL_HANDLING_CHANGE;
+
if (from_tty)
{
/* Show the results. */
sig_print_header ();
- sig_print_info (signum);
+ for (signum = 0; signum < nsigs; signum++)
+ {
+ if (sigs[signum])
+ {
+ sig_print_info (signum);
+ }
+ }
}
+
+ do_cleanups (old_chain);
}
/* Print current contents of the tables set by the handle command. */
static void
-signals_info (signum_exp)
+signals_info (signum_exp, from_tty)
char *signum_exp;
+ int from_tty;
{
register int i;
sig_print_header ();
if (signum_exp)
{
/* First see if this is a symbol name. */
- i = sig_number (signum_exp);
- if (i == -1)
+ i = strtosigno (signum_exp);
+ if (i == 0)
{
/* Nope, maybe it's an address which evaluates to a signal
number. */
inf_status->restore_stack_info = restore_stack_info;
inf_status->proceed_to_finish = proceed_to_finish;
- bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+ memcpy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
record_selected_frame (&(inf_status->selected_frame_address),
&(inf_status->selected_level));
breakpoint_proceeded = inf_status->breakpoint_proceeded;
proceed_to_finish = inf_status->proceed_to_finish;
- bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+ memcpy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
/* The inferior can be gone if the user types "print exit(0)"
(and perhaps other times). */
_initialize_infrun ()
{
register int i;
+ register int numsigs;
add_info ("signals", signals_info,
"What debugger does when program gets various signals.\n\
Specify a signal number as argument to print info on that signal only.");
+ add_info_alias ("handle", "signals", 0);
add_com ("handle", class_run, handle_command,
"Specify how to handle a signal.\n\
-Args are signal number followed by flags.\n\
-Flags allowed are \"stop\", \"print\", \"pass\",\n\
- \"nostop\", \"noprint\" or \"nopass\".\n\
-Print means print a message if this signal happens.\n\
+Args are signal numbers and actions to apply to those signals.\n\
+Signal numbers may be numeric (ex. 11) or symbolic (ex. SIGSEGV).\n\
+Numeric ranges may be specified with the form LOW-HIGH (ex. 14-21).\n\
+The special arg \"all\" is recognized to mean all signals except those\n\
+used by the debugger, typically SIGTRAP and SIGINT.\n\
+Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\
+\"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\
Stop means reenter debugger if this signal happens (implies print).\n\
+Print means print a message if this signal happens.\n\
Pass means let program see this signal; otherwise program doesn't know.\n\
+Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
Pass and Stop may be combined.");
- for (i = 0; i < NSIG; i++)
+ numsigs = signo_max () + 1;
+ signal_stop = (unsigned char *)
+ xmalloc (sizeof (signal_stop[0]) * numsigs);
+ signal_print = (unsigned char *)
+ xmalloc (sizeof (signal_print[0]) * numsigs);
+ signal_program = (unsigned char *)
+ xmalloc (sizeof (signal_program[0]) * numsigs);
+ for (i = 0; i < numsigs; i++)
{
signal_stop[i] = 1;
signal_print[i] = 1;