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
 
 
 
 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 reactivate_fd(int fd, int irqnum);
 extern void deactivate_fd(int fd, int irqnum);
 
 #include "sysdep/ptrace.h"
 #include "sysdep/faultinfo.h"
 
+struct siginfo;
+
 extern int uml_exitcode;
 
 extern int ncpus;
 
 extern int do_signal(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,
                          int is_user, struct uml_pt_regs *regs);
 extern int smp_sigio_handler(void);
 extern void initial_thread_cb(void (*proc)(void *), void *arg);
 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 void paging_init(void);
 extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
 extern int singlestepping(void *t);
 
-extern void segv_handler(int sig, struct uml_pt_regs *regs);
-extern void bus_handler(int sig, struct uml_pt_regs *regs);
-extern void winch(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 siginfo *si, 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 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;
        int n;
 
 #include "kern_util.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;
 
 
        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);
 
        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 (sig == SIGBUS)
                        printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
 
        arch_examine_signal(sig, regs);
 
-       current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
-       force_sig(sig, current);
+       memset(&clean_si, 0, sizeof(clean_si));
+       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)
                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);
 }
 
-void alarm_handler(int, mcontext_t *);
+void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
 
 #include "kern_util.h"
 #include "os.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,
        [SIGFPE]        = relay_signal,
        [SIGILL]        = relay_signal,
        [SIGIO]         = sigio_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;
        int save_errno = errno;
        if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
                unblock_signals();
 
-       (*sig_info[sig])(sig, &r);
+       (*sig_info[sig])(sig, si, &r);
 
        errno = save_errno;
 }
 static int signals_enabled;
 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;
 
 
        block_signals();
 
-       sig_handler_common(sig, mc);
+       sig_handler_common(sig, si, mc);
 
        set_signals(enabled);
 }
                get_regs_from_mc(®s, mc);
        regs.is_user = 0;
        unblock_signals();
-       timer_handler(SIGVTALRM, ®s);
+       timer_handler(SIGVTALRM, NULL, ®s);
 }
 
-void alarm_handler(int sig, mcontext_t *mc)
+void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
 {
        int enabled;
 
                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,
        [SIGBUS] = sig_handler,
        [SIGILL] = sig_handler,
 };
 
 
-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;
        mcontext_t *mc = &uc->uc_mcontext;
                while ((sig = ffs(pending)) != 0){
                        sig--;
                        pending &= ~(1 << sig);
-                       (*handlers[sig])(sig, mc);
+                       (*handlers[sig])(sig, si, mc);
                }
 
                /*
                 * Deal with SIGIO first because the alarm handler might
                 * schedule, leaving the pending SIGIO stranded until we come
                 * back here.
+                *
+                * SIGIO's handler doesn't use siginfo or mcontext,
+                * so they can be NULL.
                 */
                if (save_pending & SIGIO_MASK)
-                       sig_handler_common(SIGIO, NULL);
+                       sig_handler_common(SIGIO, NULL, NULL);
 
                if (save_pending & SIGVTALRM_MASK)
                        real_alarm_handler(NULL);
 
        int err, status, op, pid = userspace_pid[0];
        /* To prevent races if using_sysemu changes under us.*/
        int local_using_sysemu;
+       siginfo_t si;
 
        /* Handle any immediate reschedules or signals */
        interrupt_end();
 
                if (WIFSTOPPED(status)) {
                        int sig = WSTOPSIG(status);
+
+                       ptrace(PTRACE_GETSIGINFO, pid, 0, &si);
+
                        switch (sig) {
                        case SIGSEGV:
                                if (PTRACE_FULL_FAULTINFO ||
                                    !ptrace_faultinfo) {
                                        get_skas_faultinfo(pid,
                                                           ®s->faultinfo);
-                                       (*sig_info[SIGSEGV])(SIGSEGV, regs);
+                                       (*sig_info[SIGSEGV])(SIGSEGV, &si,
+                                                            regs);
                                }
                                else handle_segv(pid, regs);
                                break;
                                handle_trap(pid, regs, local_using_sysemu);
                                break;
                        case SIGTRAP:
-                               relay_signal(SIGTRAP, regs);
+                               relay_signal(SIGTRAP, &si, regs);
                                break;
                        case SIGVTALRM:
                                now = os_nsecs();
                                if (now < nsecs)
                                        break;
                                block_signals();
-                               (*sig_info[sig])(sig, regs);
+                               (*sig_info[sig])(sig, &si, regs);
                                unblock_signals();
                                nsecs = timer.it_value.tv_sec *
                                        UM_NSEC_PER_SEC +
                        case SIGFPE:
                        case SIGWINCH:
                                block_signals();
-                               (*sig_info[sig])(sig, regs);
+                               (*sig_info[sig])(sig, &si, regs);
                                unblock_signals();
                                break;
                        default:
 
 
 static void deliver_alarm(void)
 {
-       alarm_handler(SIGVTALRM, NULL);
+       alarm_handler(SIGVTALRM, NULL, NULL);
 }
 
 static unsigned long long sleep_time(unsigned long long nsecs)