blob: a19a74f08fa99e505b5278345541f102b5022ddc [file] [log] [blame]
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -08001/*
Jeff Dikeba180fd2007-10-16 01:27:00 -07002 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Jeff Dikeba180fd2007-10-16 01:27:00 -07006#include <errno.h>
7#include <signal.h>
8#include "sysdep/ptrace.h"
9#include "kern_constants.h"
10#include "as-layout.h"
Jeff Dikeedea1382008-02-04 22:30:46 -080011#include "kern_util.h"
Gennady Sharapov0805d892006-01-08 01:01:29 -080012#include "os.h"
Jeff Dikeba180fd2007-10-16 01:27:00 -070013#include "sigcontext.h"
14#include "task.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
Jeff Dikeedea1382008-02-04 22:30:46 -080016void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
17 [SIGTRAP] = relay_signal,
18 [SIGFPE] = relay_signal,
19 [SIGILL] = relay_signal,
20 [SIGWINCH] = winch,
21 [SIGBUS] = bus_handler,
22 [SIGSEGV] = segv_handler,
23 [SIGIO] = sigio_handler,
24 [SIGVTALRM] = timer_handler };
25
Jeff Dike77bf4402007-10-16 01:26:58 -070026static struct uml_pt_regs ksig_regs[UM_NR_CPUS];
Jeff Dike377fad32007-05-06 14:51:25 -070027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028void sig_handler_common_skas(int sig, void *sc_ptr)
29{
30 struct sigcontext *sc = sc_ptr;
Jeff Dike77bf4402007-10-16 01:26:58 -070031 struct uml_pt_regs *r;
32 void (*handler)(int, struct uml_pt_regs *);
Jeff Dike5d864562007-05-06 14:51:24 -070033 int save_user, save_errno = errno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Jeff Dikeba180fd2007-10-16 01:27:00 -070035 /*
36 * This is done because to allow SIGSEGV to be delivered inside a SEGV
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 * handler. This can happen in copy_user, and if SEGV is disabled,
38 * the process will die.
39 * XXX Figure out why this is better than SA_NODEFER
40 */
Jeff Dikeba180fd2007-10-16 01:27:00 -070041 if (sig == SIGSEGV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 change_sig(SIGSEGV, 1);
Jeff Dikeba180fd2007-10-16 01:27:00 -070043 /*
44 * For segfaults, we want the data from the
Jeff Dike377fad32007-05-06 14:51:25 -070045 * sigcontext. In this case, we don't want to mangle
46 * the process registers, so use a static set of
47 * registers. For other signals, the process
48 * registers are OK.
49 */
50 r = &ksig_regs[cpu()];
51 copy_sc(r, sc_ptr);
52 }
53 else r = TASK_REGS(get_current());
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Jeff Dike77bf4402007-10-16 01:26:58 -070055 save_user = r->is_user;
56 r->is_user = 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -070057 if ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
58 (sig == SIGILL) || (sig == SIGTRAP))
Jeff Dike77bf4402007-10-16 01:26:58 -070059 GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 change_sig(SIGUSR1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -080063 handler = sig_info[sig];
64
Jeff Dike61b63c52007-10-16 01:27:27 -070065 /* unblock SIGVTALRM, SIGIO if sig isn't IRQ signal */
66 if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
Gennady Sharapovea2ba7d2006-01-08 01:01:31 -080067 unblock_signals();
68
Jeff Dike5d864562007-05-06 14:51:24 -070069 handler(sig, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71 errno = save_errno;
Jeff Dike77bf4402007-10-16 01:26:58 -070072 r->is_user = save_user;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073}