add to_pass_signals.
(target_notice_signals): Remove.
(target_pass_signals): Add prototype.
* target.c (update_current_target): Remove to_notice_signals;
mention to_pass_signals.
(target_pass_signals): New function.
(debug_to_notice_signals): Remove.
(setup_target_debug): Do not install debug_to_notice_signals.
* infrun.c (signal_pass): New global.
(resume): Call target_pass_signals.
(handle_inferior_event): Report all signals while stepping over
non-steppable watchpoint. Reset trap_expected to ensure breakpoints
are re-inserted when stepping over a signal handler.
(signal_cache_update): New function.
(signal_stop_update): Call it.
(signal_print_update): Likewise.
(signal_pass_update): Likewise.
(handle_command): Call signal_cache_update and target_pass_signals
instead of target_notice_signals.
(_initialize_infrun): Initialize signal_pass.
* linux-nat.c (pass_mask): New global.
(linux_nat_pass_signals): New function.
(linux_nat_create_inferior): Report all signals initially.
(linux_nat_attach): Likewise.
(linux_nat_resume): Use pass_mask to decide whether to directly
handle an inferior signal.
(linux_nat_wait_1): Likewise.
(linux_nat_add_target): Install to_pass_signals callback.
* nto-procfs.c (notice_signals): Remove.
(procfs_resume): Do not call notice_signals.
(procfs_notice_signals): Remove.
(procfs_pass_signals): New function.
(init_procfs_ops): Install to_pass_signals callback instead of
to_notice_signals callback.
(_initialize_procfs): Report all signals initially.
* procfs.c (procfs_notice_signals): Remove.
(procfs_pass_signals): New function.
(procfs_target): Install to_pass_signals callback instead of
to_notice_signals callback.
(register_gdb_signals): Remove.
(procfs_debug_inferior): Report all signals initially.
(procfs_init_inferior): Remove redundant register_gdb_signals call.
* remote.c (remote_pass_signals): Add numsigs and pass_signals
parameters; use them instead of calling signal_..._state routines.
(remote_notice_signals): Remove.
(remote_start_remote): Report all signals initially.
(remote_resume): Do not call remote_pass_signals.
(_initialize_remote): Install to_pass_signals callback instead of
to_notice_signals callback.
+2011-04-27 Ulrich Weigand <ulrich.weigand@linaro.org>
+
+ * target.h (struct target_ops): Remove to_notice_signals;
+ add to_pass_signals.
+ (target_notice_signals): Remove.
+ (target_pass_signals): Add prototype.
+ * target.c (update_current_target): Remove to_notice_signals;
+ mention to_pass_signals.
+ (target_pass_signals): New function.
+ (debug_to_notice_signals): Remove.
+ (setup_target_debug): Do not install debug_to_notice_signals.
+
+ * infrun.c (signal_pass): New global.
+ (resume): Call target_pass_signals.
+ (handle_inferior_event): Report all signals while stepping over
+ non-steppable watchpoint. Reset trap_expected to ensure breakpoints
+ are re-inserted when stepping over a signal handler.
+ (signal_cache_update): New function.
+ (signal_stop_update): Call it.
+ (signal_print_update): Likewise.
+ (signal_pass_update): Likewise.
+ (handle_command): Call signal_cache_update and target_pass_signals
+ instead of target_notice_signals.
+ (_initialize_infrun): Initialize signal_pass.
+
+ * linux-nat.c (pass_mask): New global.
+ (linux_nat_pass_signals): New function.
+ (linux_nat_create_inferior): Report all signals initially.
+ (linux_nat_attach): Likewise.
+ (linux_nat_resume): Use pass_mask to decide whether to directly
+ handle an inferior signal.
+ (linux_nat_wait_1): Likewise.
+ (linux_nat_add_target): Install to_pass_signals callback.
+
+ * nto-procfs.c (notice_signals): Remove.
+ (procfs_resume): Do not call notice_signals.
+ (procfs_notice_signals): Remove.
+ (procfs_pass_signals): New function.
+ (init_procfs_ops): Install to_pass_signals callback instead of
+ to_notice_signals callback.
+ (_initialize_procfs): Report all signals initially.
+
+ * procfs.c (procfs_notice_signals): Remove.
+ (procfs_pass_signals): New function.
+ (procfs_target): Install to_pass_signals callback instead of
+ to_notice_signals callback.
+ (register_gdb_signals): Remove.
+ (procfs_debug_inferior): Report all signals initially.
+ (procfs_init_inferior): Remove redundant register_gdb_signals call.
+
+ * remote.c (remote_pass_signals): Add numsigs and pass_signals
+ parameters; use them instead of calling signal_..._state routines.
+ (remote_notice_signals): Remove.
+ (remote_start_remote): Report all signals initially.
+ (remote_resume): Do not call remote_pass_signals.
+ (_initialize_remote): Install to_pass_signals callback instead of
+ to_notice_signals callback.
+
2011-04-27 Pedro Alves <pedro@codesourcery.com>
* breakpoint.c (user_settable_breakpoint): Delete.
static unsigned char *signal_print;
static unsigned char *signal_program;
+/* Table of signals that the target may silently handle.
+ This is automatically determined from the flags above,
+ and simply cached here. */
+static unsigned char *signal_pass;
+
#define SET_SIGS(nsigs,sigs,flags) \
do { \
int signum = (nsigs); \
happens to apply to another thread. */
tp->suspend.stop_signal = TARGET_SIGNAL_0;
+ /* Advise target which signals may be handled silently. If we have
+ removed breakpoints because we are stepping over one (which can
+ happen only if we are not using displaced stepping), we need to
+ receive all signals to avoid accidentally skipping a breakpoint
+ during execution of a signal handler. */
+ if ((step || singlestep_breakpoints_inserted_p)
+ && tp->control.trap_expected
+ && !use_displaced_stepping (gdbarch))
+ target_pass_signals (0, NULL);
+ else
+ target_pass_signals ((int) TARGET_SIGNAL_LAST, signal_pass);
+
target_resume (resume_ptid, step, sig);
}
int hw_step = 1;
if (!target_have_steppable_watchpoint)
- remove_breakpoints ();
+ {
+ remove_breakpoints ();
+ /* See comment in resume why we need to stop bypassing signals
+ while breakpoints have been removed. */
+ target_pass_signals (0, NULL);
+ }
/* Single step */
hw_step = maybe_software_singlestep (gdbarch, stop_pc);
target_resume (ecs->ptid, hw_step, TARGET_SIGNAL_0);
insert_step_resume_breakpoint_at_frame (frame);
ecs->event_thread->step_after_step_resume_breakpoint = 1;
+ /* Reset trap_expected to ensure breakpoints are re-inserted. */
+ ecs->event_thread->control.trap_expected = 0;
keep_going (ecs);
return;
}
"single-step range\n");
insert_step_resume_breakpoint_at_frame (frame);
+ /* Reset trap_expected to ensure breakpoints are re-inserted. */
+ ecs->event_thread->control.trap_expected = 0;
keep_going (ecs);
return;
}
return signal_program[signo];
}
+static void
+signal_cache_update (int signo)
+{
+ if (signo == -1)
+ {
+ for (signo = 0; signo < (int) TARGET_SIGNAL_LAST; signo++)
+ signal_cache_update (signo);
+
+ return;
+ }
+
+ signal_pass[signo] = (signal_stop[signo] == 0
+ && signal_print[signo] == 0
+ && signal_program[signo] == 1);
+}
+
int
signal_stop_update (int signo, int state)
{
int ret = signal_stop[signo];
signal_stop[signo] = state;
+ signal_cache_update (signo);
return ret;
}
int ret = signal_print[signo];
signal_print[signo] = state;
+ signal_cache_update (signo);
return ret;
}
int ret = signal_program[signo];
signal_program[signo] = state;
+ signal_cache_update (signo);
return ret;
}
for (signum = 0; signum < nsigs; signum++)
if (sigs[signum])
{
- target_notice_signals (inferior_ptid);
+ signal_cache_update (-1);
+ target_pass_signals ((int) TARGET_SIGNAL_LAST, signal_pass);
if (from_tty)
{
xmalloc (sizeof (signal_print[0]) * numsigs);
signal_program = (unsigned char *)
xmalloc (sizeof (signal_program[0]) * numsigs);
+ signal_pass = (unsigned char *)
+ xmalloc (sizeof (signal_program[0]) * numsigs);
for (i = 0; i < numsigs; i++)
{
signal_stop[i] = 1;
signal_stop[TARGET_SIGNAL_CANCEL] = 0;
signal_print[TARGET_SIGNAL_CANCEL] = 0;
+ /* Update cached state. */
+ signal_cache_update (-1);
+
add_setshow_zinteger_cmd ("stop-on-solib-events", class_support,
&stop_on_solib_events, _("\
Set stopping for shared library events."), _("\
{
sigprocmask (SIG_SETMASK, prev_mask, NULL);
}
+
+/* Mask of signals to pass directly to the inferior. */
+static sigset_t pass_mask;
+
+/* Update signals to pass to the inferior. */
+static void
+linux_nat_pass_signals (int numsigs, unsigned char *pass_signals)
+{
+ int signo;
+
+ sigemptyset (&pass_mask);
+
+ for (signo = 1; signo < NSIG; signo++)
+ {
+ int target_signo = target_signal_from_host (signo);
+ if (target_signo < numsigs && pass_signals[target_signo])
+ sigaddset (&pass_mask, signo);
+ }
+}
+
\f
/* Prototypes for local functions. */
}
#endif /* HAVE_PERSONALITY */
+ /* Make sure we report all signals during startup. */
+ linux_nat_pass_signals (0, NULL);
+
linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
#ifdef HAVE_PERSONALITY
int status;
ptid_t ptid;
+ /* Make sure we report all signals during attach. */
+ linux_nat_pass_signals (0, NULL);
+
linux_ops->to_attach (ops, args, from_tty);
/* The ptrace base target adds the main thread with (pid,0,0)
if (lp->status && WIFSTOPPED (lp->status))
{
- enum target_signal saved_signo;
- struct inferior *inf;
-
- inf = find_inferior_pid (ptid_get_pid (lp->ptid));
- gdb_assert (inf);
- saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
-
- /* Defer to common code if we're gaining control of the
- inferior. */
- if (inf->control.stop_soon == NO_STOP_QUIETLY
- && signal_stop_state (saved_signo) == 0
- && signal_print_state (saved_signo) == 0
- && signal_pass_state (saved_signo) == 1)
+ if (!lp->step
+ && WSTOPSIG (lp->status)
+ && sigismember (&pass_mask, WSTOPSIG (lp->status)))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
/* FIXME: What should we do if we are supposed to continue
this thread with a signal? */
gdb_assert (signo == TARGET_SIGNAL_0);
- signo = saved_signo;
+ signo = target_signal_from_host (WSTOPSIG (lp->status));
lp->status = 0;
}
}
if (WIFSTOPPED (status))
{
enum target_signal signo = target_signal_from_host (WSTOPSIG (status));
- struct inferior *inf;
-
- inf = find_inferior_pid (ptid_get_pid (lp->ptid));
- gdb_assert (inf);
- /* Defer to common code if we get a signal while
- single-stepping, since that may need special care, e.g. to
- skip the signal handler, or, if we're gaining control of the
- inferior. */
+ /* When using hardware single-step, we need to report every signal.
+ Otherwise, signals in pass_mask may be short-circuited. */
if (!lp->step
- && inf->control.stop_soon == NO_STOP_QUIETLY
- && signal_stop_state (signo) == 0
- && signal_print_state (signo) == 0
- && signal_pass_state (signo) == 1)
+ && WSTOPSIG (status) && sigismember (&pass_mask, WSTOPSIG (status)))
{
/* FIMXE: kettenis/2001-06-06: Should we resume all threads
here? It is not clear we should. GDB may not expect
t->to_detach = linux_nat_detach;
t->to_resume = linux_nat_resume;
t->to_wait = linux_nat_wait;
+ t->to_pass_signals = linux_nat_pass_signals;
t->to_xfer_partial = linux_nat_xfer_partial;
t->to_kill = linux_nat_kill;
t->to_mourn_inferior = linux_nat_mourn_inferior;
struct mem_attrib *attrib,
struct target_ops *);
-static void notice_signals (void);
-
static void init_procfs_ops (void);
static ptid_t do_attach (ptid_t ptid);
run.flags |= _DEBUG_RUN_ARM;
- sigemptyset (&run.trace);
- notice_signals ();
signal_to_pass = target_signal_to_host (signo);
if (signal_to_pass)
}
}
+/* Set list of signals to be handled in the target. */
+
static void
-notice_signals (void)
+procfs_pass_signals (int numsigs, unsigned char *pass_signals)
{
int signo;
+ sigfillset (&run.trace);
+
for (signo = 1; signo < NSIG; signo++)
{
- if (signal_stop_state (target_signal_from_host (signo)) == 0
- && signal_print_state (target_signal_from_host (signo)) == 0
- && signal_pass_state (target_signal_from_host (signo)) == 1)
- sigdelset (&run.trace, signo);
- else
- sigaddset (&run.trace, signo);
+ int target_signo = target_signal_from_host (signo);
+ if (target_signo < numsigs && pass_signals[target_signo])
+ sigdelset (&run.trace, signo);
}
}
-/* When the user changes the state of gdb's signal handling via the
- "handle" command, this function gets called to see if any change
- in the /proc interface is required. It is also called internally
- by other /proc interface functions to initialize the state of
- the traced signal set. */
-static void
-procfs_notice_signals (ptid_t ptid)
-{
- sigemptyset (&run.trace);
- notice_signals ();
-}
-
static struct tidinfo *
procfs_thread_info (pid_t pid, short tid)
{
procfs_ops.to_create_inferior = procfs_create_inferior;
procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
procfs_ops.to_can_run = procfs_can_run;
- procfs_ops.to_notice_signals = procfs_notice_signals;
+ procfs_ops.to_pass_signals = procfs_pass_signals;
procfs_ops.to_thread_alive = procfs_thread_alive;
procfs_ops.to_find_new_threads = procfs_find_new_threads;
procfs_ops.to_pid_to_str = procfs_pid_to_str;
sigaddset (&set, SIGUSR1);
sigprocmask (SIG_BLOCK, &set, NULL);
- /* Set up trace and fault sets, as gdb expects them. */
- sigemptyset (&run.trace);
+ /* Initially, make sure all signals are reported. */
+ sigfillset (&run.trace);
/* Stuff some information. */
nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags;
struct regcache *, int);
static void procfs_store_registers (struct target_ops *,
struct regcache *, int);
-static void procfs_notice_signals (ptid_t);
+static void procfs_pass_signals (ptid_t, int, unsigned char *);
static void procfs_kill_inferior (struct target_ops *ops);
static void procfs_mourn_inferior (struct target_ops *ops);
static void procfs_create_inferior (struct target_ops *, char *,
t->to_store_registers = procfs_store_registers;
t->to_xfer_partial = procfs_xfer_partial;
t->deprecated_xfer_memory = procfs_xfer_memory;
- t->to_notice_signals = procfs_notice_signals;
+ t->to_pass_signals = procfs_pass_signals;
t->to_files_info = procfs_files_info;
t->to_stop = procfs_stop;
static ptid_t do_attach (ptid_t ptid);
static void do_detach (int signo);
-static int register_gdb_signals (procinfo *, gdb_sigset_t *);
static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum,
int entry_or_exit, int mode, int from_tty);
if (!proc_set_traced_faults (pi, &traced_faults))
return __LINE__;
- /* Register to trace selected signals in the child. */
- premptyset (&traced_signals);
- if (!register_gdb_signals (pi, &traced_signals))
+ /* Initially, register to trace all signals in the child. */
+ prfillset (&traced_signals);
+ if (!proc_set_traced_signals (pi, &traced_signals))
return __LINE__;
}
}
-/* Traverse the list of signals that GDB knows about (see "handle"
- command), and arrange for the target to be stopped or not,
- according to these settings. Returns non-zero for success, zero
- for failure. */
-
-static int
-register_gdb_signals (procinfo *pi, gdb_sigset_t *signals)
-{
- int signo;
-
- for (signo = 0; signo < NSIG; signo ++)
- if (signal_stop_state (target_signal_from_host (signo)) == 0 &&
- signal_print_state (target_signal_from_host (signo)) == 0 &&
- signal_pass_state (target_signal_from_host (signo)) == 1)
- gdb_prdelset (signals, signo);
- else
- gdb_praddset (signals, signo);
-
- return proc_set_traced_signals (pi, signals);
-}
-
/* Set up to trace signals in the child process. */
static void
-procfs_notice_signals (ptid_t ptid)
+procfs_pass_signals (int numsigs, unsigned char *pass_signals)
{
gdb_sigset_t signals;
- procinfo *pi = find_procinfo_or_die (PIDGET (ptid), 0);
+ procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
+ int signo;
- if (proc_get_traced_signals (pi, &signals) &&
- register_gdb_signals (pi, &signals))
- return;
- else
- proc_error (pi, "notice_signals", __LINE__);
+ prfillset (&signals);
+
+ for (signo = 0; signo < NSIG; signo++)
+ {
+ int target_signo = target_signal_from_host (signo);
+ if (target_signo < numsigs && pass_signals[target_signo])
+ gdb_prdelset (&signals, signo);
+ }
+
+ if (!proc_set_traced_signals (pi, &signals))
+ proc_error (pi, "pass_signals", __LINE__);
}
/* Print status information about the child process. */
if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
proc_error (pi, "init_inferior, get_traced_sysexit", __LINE__);
- /* Register to trace selected signals in the child. */
- prfillset (&signals);
- if (!register_gdb_signals (pi, &signals))
- proc_error (pi, "init_inferior, register_signals", __LINE__);
-
if ((fail = procfs_debug_inferior (pi)) != 0)
proc_error (pi, "init_inferior (procfs_debug_inferior)", fail);
it can simply pass through to the inferior without reporting. */
static void
-remote_pass_signals (void)
+remote_pass_signals (int numsigs, unsigned char *pass_signals)
{
if (remote_protocol_packets[PACKET_QPassSignals].support != PACKET_DISABLE)
{
char *pass_packet, *p;
- int numsigs = (int) TARGET_SIGNAL_LAST;
int count = 0, i;
gdb_assert (numsigs < 256);
for (i = 0; i < numsigs; i++)
{
- if (signal_stop_state (i) == 0
- && signal_print_state (i) == 0
- && signal_pass_state (i) == 1)
+ if (pass_signals[i])
count++;
}
pass_packet = xmalloc (count * 3 + strlen ("QPassSignals:") + 1);
p = pass_packet + strlen (pass_packet);
for (i = 0; i < numsigs; i++)
{
- if (signal_stop_state (i) == 0
- && signal_print_state (i) == 0
- && signal_pass_state (i) == 1)
+ if (pass_signals[i])
{
if (i >= 16)
*p++ = tohex (i >> 4);
}
}
-static void
-remote_notice_signals (ptid_t ptid)
-{
- /* Update the remote on signals to silently pass, if they've
- changed. */
- remote_pass_signals ();
-}
-
/* If PTID is MAGIC_NULL_PTID, don't set any thread. If PTID is
MINUS_ONE_PTID, set the thread to -1, so the stub returns the
thread. If GEN is set, set the general thread, if not, then set
the stop reply queue. */
gdb_assert (wait_status == NULL);
- /* Update the remote on signals to silently pass, or more
- importantly, which to not ignore, in case a previous session
- had set some different set of signals to be ignored. */
- remote_pass_signals ();
+ /* Report all signals during attach/startup. */
+ remote_pass_signals (0, NULL);
}
/* If we connected to a live target, do some additional setup. */
last_sent_signal = siggnal;
last_sent_step = step;
- /* Update the inferior on signals to silently pass, if they've changed. */
- remote_pass_signals ();
-
/* The vCont packet doesn't need to specify threads via Hc. */
/* No reverse support (yet) for vCont. */
if (execution_direction != EXEC_REVERSE)
remote_ops.to_kill = remote_kill;
remote_ops.to_load = generic_load;
remote_ops.to_mourn_inferior = remote_mourn;
- remote_ops.to_notice_signals = remote_notice_signals;
+ remote_ops.to_pass_signals = remote_pass_signals;
remote_ops.to_thread_alive = remote_thread_alive;
remote_ops.to_find_new_threads = remote_threads_info;
remote_ops.to_pid_to_str = remote_pid_to_str;
static int debug_to_can_run (void);
-static void debug_to_notice_signals (ptid_t);
-
static void debug_to_stop (ptid_t);
/* Pointer to array of target architecture structures; the size of the
INHERIT (to_has_exited, t);
/* Do not inherit to_mourn_inferior. */
INHERIT (to_can_run, t);
- INHERIT (to_notice_signals, t);
+ /* Do not inherit to_pass_signals. */
/* Do not inherit to_thread_alive. */
/* Do not inherit to_find_new_threads. */
/* Do not inherit to_pid_to_str. */
return_zero);
de_fault (to_can_run,
return_zero);
- de_fault (to_notice_signals,
- (void (*) (ptid_t))
- target_ignore);
de_fault (to_extra_thread_info,
(char *(*) (struct thread_info *))
return_zero);
noprocess ();
}
+
+void
+target_pass_signals (int numsigs, unsigned char *pass_signals)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_pass_signals != NULL)
+ {
+ if (targetdebug)
+ {
+ int i;
+
+ fprintf_unfiltered (gdb_stdlog, "target_pass_signals (%d, {",
+ numsigs);
+
+ for (i = 0; i < numsigs; i++)
+ if (pass_signals[i])
+ fprintf_unfiltered (gdb_stdlog, " %s",
+ target_signal_to_name (i));
+
+ fprintf_unfiltered (gdb_stdlog, " })\n");
+ }
+
+ (*t->to_pass_signals) (numsigs, pass_signals);
+ return;
+ }
+ }
+}
+
/* Look through the list of possible targets for a target that can
follow forks. */
return retval;
}
-static void
-debug_to_notice_signals (ptid_t ptid)
-{
- debug_target.to_notice_signals (ptid);
-
- fprintf_unfiltered (gdb_stdlog, "target_notice_signals (%d)\n",
- PIDGET (ptid));
-}
-
static struct gdbarch *
debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
{
current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
current_target.to_has_exited = debug_to_has_exited;
current_target.to_can_run = debug_to_can_run;
- current_target.to_notice_signals = debug_to_notice_signals;
current_target.to_stop = debug_to_stop;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;
int (*to_has_exited) (int, int, int *);
void (*to_mourn_inferior) (struct target_ops *);
int (*to_can_run) (void);
- void (*to_notice_signals) (ptid_t ptid);
+
+ /* Documentation of this routine is provided with the corresponding
+ target_* macro. */
+ void (*to_pass_signals) (int, unsigned char *);
+
int (*to_thread_alive) (struct target_ops *, ptid_t ptid);
void (*to_find_new_threads) (struct target_ops *);
char *(*to_pid_to_str) (struct target_ops *, ptid_t);
#define target_can_run(t) \
((t)->to_can_run) ()
-/* post process changes to signal handling in the inferior. */
+/* Set list of signals to be handled in the target.
+
+ PASS_SIGNALS is an array of size NSIG, indexed by target signal number
+ (enum target_signal). For every signal whose entry in this array is
+ non-zero, the target is allowed -but not required- to skip reporting
+ arrival of the signal to the GDB core by returning from target_wait,
+ and to pass the signal directly to the inferior instead.
+
+ However, if the target is hardware single-stepping a thread that is
+ about to receive a signal, it needs to be reported in any case, even
+ if mentioned in a previous target_pass_signals call. */
-#define target_notice_signals(ptid) \
- (*current_target.to_notice_signals) (ptid)
+extern void target_pass_signals (int nsig, unsigned char *pass_signals);
/* Check to see if a thread is still alive. */