Commit d3c1cfcd authored by Martin Pärtel's avatar Martin Pärtel Committed by Richard Weinberger

um: pass siginfo to guest process

UML guest processes now get correct siginfo_t for SIGTRAP, SIGFPE,
SIGILL and SIGBUS. Specifically, si_addr and si_code are now correct
where previously they were si_addr = NULL and si_code = 128.
Signed-off-by: default avatarMartin Pärtel <martin.partel@gmail.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent d4afcba9
...@@ -60,7 +60,8 @@ extern unsigned long host_task_size; ...@@ -60,7 +60,8 @@ extern unsigned long host_task_size;
extern int linux_main(int argc, char **argv); extern int linux_main(int argc, char **argv);
extern void (*sig_info[])(int, struct uml_pt_regs *); struct siginfo;
extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *);
#endif #endif
......
...@@ -20,7 +20,8 @@ struct irq_fd { ...@@ -20,7 +20,8 @@ struct irq_fd {
enum { IRQ_READ, IRQ_WRITE }; enum { IRQ_READ, IRQ_WRITE };
extern void sigio_handler(int sig, struct uml_pt_regs *regs); struct siginfo;
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
extern void free_irq_by_fd(int fd); extern void free_irq_by_fd(int fd);
extern void reactivate_fd(int fd, int irqnum); extern void reactivate_fd(int fd, int irqnum);
extern void deactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum);
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h" #include "sysdep/faultinfo.h"
struct siginfo;
extern int uml_exitcode; extern int uml_exitcode;
extern int ncpus; extern int ncpus;
...@@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order); ...@@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order);
extern int do_signal(void); extern int do_signal(void);
extern void interrupt_end(void); extern void interrupt_end(void);
extern void relay_signal(int sig, struct uml_pt_regs *regs); extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs);
extern unsigned long segv(struct faultinfo fi, unsigned long ip, extern unsigned long segv(struct faultinfo fi, unsigned long ip,
int is_user, struct uml_pt_regs *regs); int is_user, struct uml_pt_regs *regs);
...@@ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); ...@@ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
extern int smp_sigio_handler(void); extern int smp_sigio_handler(void);
extern void initial_thread_cb(void (*proc)(void *), void *arg); extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int is_syscall(unsigned long addr); extern int is_syscall(unsigned long addr);
extern void timer_handler(int sig, struct uml_pt_regs *regs);
extern void timer_handler(int sig, struct uml_pt_regs *regs); extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
extern int start_uml(void); extern int start_uml(void);
extern void paging_init(void); extern void paging_init(void);
...@@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested); ...@@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested);
extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
extern int singlestepping(void *t); extern int singlestepping(void *t);
extern void segv_handler(int sig, struct uml_pt_regs *regs); extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
extern void bus_handler(int sig, struct uml_pt_regs *regs); extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
extern void winch(int sig, struct uml_pt_regs *regs); extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
extern void fatal_sigsegv(void) __attribute__ ((noreturn)); extern void fatal_sigsegv(void) __attribute__ ((noreturn));
......
...@@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds; ...@@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds;
extern void free_irqs(void); extern void free_irqs(void);
void sigio_handler(int sig, struct uml_pt_regs *regs) void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{ {
struct irq_fd *irq_fd; struct irq_fd *irq_fd;
int n; int n;
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "kern_util.h" #include "kern_util.h"
#include "os.h" #include "os.h"
void timer_handler(int sig, struct uml_pt_regs *regs) void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
......
...@@ -172,7 +172,7 @@ void fatal_sigsegv(void) ...@@ -172,7 +172,7 @@ void fatal_sigsegv(void)
os_dump_core(); os_dump_core();
} }
void segv_handler(int sig, struct uml_pt_regs *regs) void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{ {
struct faultinfo * fi = UPT_FAULTINFO(regs); struct faultinfo * fi = UPT_FAULTINFO(regs);
...@@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, ...@@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
return 0; return 0;
} }
void relay_signal(int sig, struct uml_pt_regs *regs) void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
{ {
struct faultinfo *fi;
struct siginfo clean_si;
if (!UPT_IS_USER(regs)) { if (!UPT_IS_USER(regs)) {
if (sig == SIGBUS) if (sig == SIGBUS)
printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
...@@ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs) ...@@ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs)
arch_examine_signal(sig, regs); arch_examine_signal(sig, regs);
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); memset(&clean_si, 0, sizeof(clean_si));
force_sig(sig, current); clean_si.si_signo = si->si_signo;
clean_si.si_errno = si->si_errno;
clean_si.si_code = si->si_code;
switch (sig) {
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
case SIGTRAP:
fi = UPT_FAULTINFO(regs);
clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi);
current->thread.arch.faultinfo = *fi;
#ifdef __ARCH_SI_TRAPNO
clean_si.si_trapno = si->si_trapno;
#endif
break;
default:
printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n",
sig, si->si_code);
}
force_sig_info(sig, &clean_si, current);
} }
void bus_handler(int sig, struct uml_pt_regs *regs) void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)
{ {
if (current->thread.fault_catcher != NULL) if (current->thread.fault_catcher != NULL)
UML_LONGJMP(current->thread.fault_catcher, 1); UML_LONGJMP(current->thread.fault_catcher, 1);
else relay_signal(sig, regs); else
relay_signal(sig, si, regs);
} }
void winch(int sig, struct uml_pt_regs *regs) void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{ {
do_IRQ(WINCH_IRQ, regs); do_IRQ(WINCH_IRQ, regs);
} }
......
void alarm_handler(int, mcontext_t *); void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
#include "kern_util.h" #include "kern_util.h"
#include "os.h" #include "os.h"
#include "sysdep/mcontext.h" #include "sysdep/mcontext.h"
#include "internal.h"
void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = {
[SIGTRAP] = relay_signal, [SIGTRAP] = relay_signal,
[SIGFPE] = relay_signal, [SIGFPE] = relay_signal,
[SIGILL] = relay_signal, [SIGILL] = relay_signal,
...@@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { ...@@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
[SIGIO] = sigio_handler, [SIGIO] = sigio_handler,
[SIGVTALRM] = timer_handler }; [SIGVTALRM] = timer_handler };
static void sig_handler_common(int sig, mcontext_t *mc) static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc)
{ {
struct uml_pt_regs r; struct uml_pt_regs r;
int save_errno = errno; int save_errno = errno;
...@@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) ...@@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
unblock_signals(); unblock_signals();
(*sig_info[sig])(sig, &r); (*sig_info[sig])(sig, si, &r);
errno = save_errno; errno = save_errno;
} }
...@@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc) ...@@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
static int signals_enabled; static int signals_enabled;
static unsigned int signals_pending; static unsigned int signals_pending;
void sig_handler(int sig, mcontext_t *mc) void sig_handler(int sig, siginfo_t *si, mcontext_t *mc)
{ {
int enabled; int enabled;
...@@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc) ...@@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc)
block_signals(); block_signals();
sig_handler_common(sig, mc); sig_handler_common(sig, si, mc);
set_signals(enabled); set_signals(enabled);
} }
...@@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc) ...@@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc)
get_regs_from_mc(&regs, mc); get_regs_from_mc(&regs, mc);
regs.is_user = 0; regs.is_user = 0;
unblock_signals(); unblock_signals();
timer_handler(SIGVTALRM, &regs); timer_handler(SIGVTALRM, NULL, &regs);
} }
void alarm_handler(int sig, mcontext_t *mc) void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
{ {
int enabled; int enabled;
...@@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size) ...@@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size)
panic("enabling signal stack failed, errno = %d\n", errno); panic("enabling signal stack failed, errno = %d\n", errno);
} }
static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = {
[SIGSEGV] = sig_handler, [SIGSEGV] = sig_handler,
[SIGBUS] = sig_handler, [SIGBUS] = sig_handler,
[SIGILL] = sig_handler, [SIGILL] = sig_handler,
...@@ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = { ...@@ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = {
}; };
static void hard_handler(int sig, siginfo_t *info, void *p) static void hard_handler(int sig, siginfo_t *si, void *p)
{ {
struct ucontext *uc = p; struct ucontext *uc = p;
mcontext_t *mc = &uc->uc_mcontext; mcontext_t *mc = &uc->uc_mcontext;
...@@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p) ...@@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p)
while ((sig = ffs(pending)) != 0){ while ((sig = ffs(pending)) != 0){
sig--; sig--;
pending &= ~(1 << sig); pending &= ~(1 << sig);
(*handlers[sig])(sig, mc); (*handlers[sig])(sig, si, mc);
} }
/* /*
...@@ -273,9 +274,12 @@ void unblock_signals(void) ...@@ -273,9 +274,12 @@ void unblock_signals(void)
* Deal with SIGIO first because the alarm handler might * Deal with SIGIO first because the alarm handler might
* schedule, leaving the pending SIGIO stranded until we come * schedule, leaving the pending SIGIO stranded until we come
* back here. * back here.
*
* SIGIO's handler doesn't use siginfo or mcontext,
* so they can be NULL.
*/ */
if (save_pending & SIGIO_MASK) if (save_pending & SIGIO_MASK)
sig_handler_common(SIGIO, NULL); sig_handler_common(SIGIO, NULL, NULL);
if (save_pending & SIGVTALRM_MASK) if (save_pending & SIGVTALRM_MASK)
real_alarm_handler(NULL); real_alarm_handler(NULL);
......
...@@ -346,6 +346,7 @@ void userspace(struct uml_pt_regs *regs) ...@@ -346,6 +346,7 @@ void userspace(struct uml_pt_regs *regs)
int err, status, op, pid = userspace_pid[0]; int err, status, op, pid = userspace_pid[0];
/* To prevent races if using_sysemu changes under us.*/ /* To prevent races if using_sysemu changes under us.*/
int local_using_sysemu; int local_using_sysemu;
siginfo_t si;
/* Handle any immediate reschedules or signals */ /* Handle any immediate reschedules or signals */
interrupt_end(); interrupt_end();
...@@ -407,13 +408,17 @@ void userspace(struct uml_pt_regs *regs) ...@@ -407,13 +408,17 @@ void userspace(struct uml_pt_regs *regs)
if (WIFSTOPPED(status)) { if (WIFSTOPPED(status)) {
int sig = WSTOPSIG(status); int sig = WSTOPSIG(status);
ptrace(PTRACE_GETSIGINFO, pid, 0, &si);
switch (sig) { switch (sig) {
case SIGSEGV: case SIGSEGV:
if (PTRACE_FULL_FAULTINFO || if (PTRACE_FULL_FAULTINFO ||
!ptrace_faultinfo) { !ptrace_faultinfo) {
get_skas_faultinfo(pid, get_skas_faultinfo(pid,
&regs->faultinfo); &regs->faultinfo);
(*sig_info[SIGSEGV])(SIGSEGV, regs); (*sig_info[SIGSEGV])(SIGSEGV, &si,
regs);
} }
else handle_segv(pid, regs); else handle_segv(pid, regs);
break; break;
...@@ -421,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) ...@@ -421,14 +426,14 @@ void userspace(struct uml_pt_regs *regs)
handle_trap(pid, regs, local_using_sysemu); handle_trap(pid, regs, local_using_sysemu);
break; break;
case SIGTRAP: case SIGTRAP:
relay_signal(SIGTRAP, regs); relay_signal(SIGTRAP, &si, regs);
break; break;
case SIGVTALRM: case SIGVTALRM:
now = os_nsecs(); now = os_nsecs();
if (now < nsecs) if (now < nsecs)
break; break;
block_signals(); block_signals();
(*sig_info[sig])(sig, regs); (*sig_info[sig])(sig, &si, regs);
unblock_signals(); unblock_signals();
nsecs = timer.it_value.tv_sec * nsecs = timer.it_value.tv_sec *
UM_NSEC_PER_SEC + UM_NSEC_PER_SEC +
...@@ -442,7 +447,7 @@ void userspace(struct uml_pt_regs *regs) ...@@ -442,7 +447,7 @@ void userspace(struct uml_pt_regs *regs)
case SIGFPE: case SIGFPE:
case SIGWINCH: case SIGWINCH:
block_signals(); block_signals();
(*sig_info[sig])(sig, regs); (*sig_info[sig])(sig, &si, regs);
unblock_signals(); unblock_signals();
break; break;
default: default:
......
...@@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts) ...@@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts)
static void deliver_alarm(void) static void deliver_alarm(void)
{ {
alarm_handler(SIGVTALRM, NULL); alarm_handler(SIGVTALRM, NULL, NULL);
} }
static unsigned long long sleep_time(unsigned long long nsecs) static unsigned long long sleep_time(unsigned long long nsecs)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment