#include <errno.h>
#include <sys/syscall.h>
+#ifndef PTRACE_GETSIGINFO
+# define PTRACE_GETSIGINFO 0x4202
+# define PTRACE_SETSIGINFO 0x4203
+#endif
+
/* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
however. This requires changing the ID in place when we go from !using_threads
to using_threads, immediately.
int using_threads;
static void linux_resume_one_process (struct inferior_list_entry *entry,
- int step, int signal);
+ int step, int signal, siginfo_t *info);
static void linux_resume (struct thread_resume *resume_info);
static void stop_all_processes (void);
static int linux_wait_for_event (struct thread_info *child);
struct pending_signals
{
int signal;
+ siginfo_t info;
struct pending_signals *prev;
};
So instead of reporting the old SIGTRAP, pretend we got to
the breakpoint just after it was removed instead of just
before; resume the process. */
- linux_resume_one_process (&process->head, 0, 0);
+ linux_resume_one_process (&process->head, 0, 0, NULL);
return 0;
}
(*childp)->stopped = 1;
(*childp)->pending_is_breakpoint = 0;
+ (*childp)->last_status = *wstatp;
+
if (debug_threads
&& WIFSTOPPED (*wstatp))
{
fprintf (stderr, "Expected stop.\n");
event_child->stop_expected = 0;
linux_resume_one_process (&event_child->head,
- event_child->stepping, 0);
+ event_child->stepping, 0, NULL);
continue;
}
&& (WSTOPSIG (wstat) == __SIGRTMIN
|| WSTOPSIG (wstat) == __SIGRTMIN + 1))
{
+ siginfo_t info, *info_p;
+
if (debug_threads)
fprintf (stderr, "Ignored signal %d for %ld (LWP %ld).\n",
WSTOPSIG (wstat), event_child->tid,
event_child->head.id);
+
+ if (ptrace (PTRACE_GETSIGINFO, event_child->lwpid, 0, &info) == 0)
+ info_p = &info;
+ else
+ info_p = NULL;
linux_resume_one_process (&event_child->head,
event_child->stepping,
- WSTOPSIG (wstat));
+ WSTOPSIG (wstat), info_p);
continue;
}
}
event_child->bp_reinsert = 0;
/* Clear the single-stepping flag and SIGTRAP as we resume. */
- linux_resume_one_process (&event_child->head, 0, 0);
+ linux_resume_one_process (&event_child->head, 0, 0, NULL);
continue;
}
{
event_child->bp_reinsert = stop_pc;
uninsert_breakpoint (stop_pc);
- linux_resume_one_process (&event_child->head, 1, 0);
+ linux_resume_one_process (&event_child->head, 1, 0, NULL);
}
else
{
reinsert_breakpoint_by_bp
(stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
- linux_resume_one_process (&event_child->head, 0, 0);
+ linux_resume_one_process (&event_child->head, 0, 0, NULL);
}
continue;
static void
linux_resume_one_process (struct inferior_list_entry *entry,
- int step, int signal)
+ int step, int signal, siginfo_t *info)
{
struct process_info *process = (struct process_info *) entry;
struct thread_info *saved_inferior;
p_sig = malloc (sizeof (*p_sig));
p_sig->prev = process->pending_signals;
p_sig->signal = signal;
+ if (info == NULL)
+ memset (&p_sig->info, 0, sizeof (siginfo_t));
+ else
+ memcpy (&p_sig->info, info, sizeof (siginfo_t));
process->pending_signals = p_sig;
}
p_sig = &(*p_sig)->prev;
signal = (*p_sig)->signal;
+ if ((*p_sig)->info.si_signo != 0)
+ ptrace (PTRACE_SETSIGINFO, process->lwpid, 0, &(*p_sig)->info);
+
free (*p_sig);
*p_sig = NULL;
}
else
step = process->resume->step;
- linux_resume_one_process (&process->head, step, process->resume->sig);
+ linux_resume_one_process (&process->head, step, process->resume->sig, NULL);
process->resume = NULL;
}
p_sig = malloc (sizeof (*p_sig));
p_sig->prev = process->pending_signals;
p_sig->signal = process->resume->sig;
+ memset (&p_sig->info, 0, sizeof (siginfo_t));
+
+ /* If this is the same signal we were previously stopped by,
+ make sure to queue its siginfo. We can ignore the return
+ value of ptrace; if it fails, we'll skip
+ PTRACE_SETSIGINFO. */
+ if (WIFSTOPPED (process->last_status)
+ && WSTOPSIG (process->last_status) == process->resume->sig)
+ ptrace (PTRACE_GETSIGINFO, process->lwpid, 0, &p_sig->info);
+
process->pending_signals = p_sig;
}