Commit 5963dbac authored by Russ Cox's avatar Russ Cox

runtime: turn divide by zero, nil dereference into panics

tested on linux/amd64, linux/386, linux/arm, darwin/amd64, darwin/386.
freebsd untested; will finish in a separate CL.

for now all the panics are errorStrings.
richer structures can be added as necessary
once the mechanism is shaked out.

R=r
CC=golang-dev
https://golang.org/cl/906041
parent 72157c30
// godefs -f -m32 defs.c
// godefs defs.c
// MACHINE GENERATED - DO NOT EDIT.
......@@ -44,6 +44,50 @@ enum {
SA_ONSTACK = 0x1,
SA_USERTRAMP = 0x100,
SA_64REGSET = 0x200,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGEMT = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGBUS = 0xa,
SIGSEGV = 0xb,
SIGSYS = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGTERM = 0xf,
SIGURG = 0x10,
SIGSTOP = 0x11,
SIGTSTP = 0x12,
SIGCONT = 0x13,
SIGCHLD = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGIO = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGINFO = 0x1d,
SIGUSR1 = 0x1e,
SIGUSR2 = 0x1f,
FPE_INTDIV = 0x7,
FPE_INTOVF = 0x8,
FPE_FLTDIV = 0x1,
FPE_FLTOVF = 0x2,
FPE_FLTUND = 0x3,
FPE_FLTRES = 0x4,
FPE_FLTINV = 0x5,
FPE_FLTSUB = 0x6,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
};
// Types
......
......@@ -39,6 +39,39 @@ sighandler(int32 sig, Siginfo *info, void *context)
Ucontext *uc;
Mcontext *mc;
Regs *r;
uintptr *sp;
void (*fn)(void);
G *gp;
byte *pc;
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
if(sig == SIGFPE && info->si_code == 0) {
pc = (byte*)r->eip;
if(pc[0] == 0xF7)
info->si_code = FPE_INTDIV;
}
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->eip = (uintptr)sigpanic;
r->esp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -56,11 +89,6 @@ sighandler(int32 sig, Siginfo *info, void *context)
printf("%s\n", sigtab[sig].name);
}
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
printf("Faulting address: %p\n", info->si_addr);
printf("pc: %x\n", r->eip);
printf("\n");
......
......@@ -44,6 +44,50 @@ enum {
SA_ONSTACK = 0x1,
SA_USERTRAMP = 0x100,
SA_64REGSET = 0x200,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGEMT = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGBUS = 0xa,
SIGSEGV = 0xb,
SIGSYS = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGTERM = 0xf,
SIGURG = 0x10,
SIGSTOP = 0x11,
SIGTSTP = 0x12,
SIGCONT = 0x13,
SIGCHLD = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGIO = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGINFO = 0x1d,
SIGUSR1 = 0x1e,
SIGUSR2 = 0x1f,
FPE_INTDIV = 0x7,
FPE_INTOVF = 0x8,
FPE_FLTDIV = 0x1,
FPE_FLTOVF = 0x2,
FPE_FLTUND = 0x3,
FPE_FLTRES = 0x4,
FPE_FLTINV = 0x5,
FPE_FLTSUB = 0x6,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
};
// Types
......
......@@ -47,6 +47,40 @@ sighandler(int32 sig, Siginfo *info, void *context)
Ucontext *uc;
Mcontext *mc;
Regs *r;
G *gp;
uintptr *sp;
byte *pc;
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
if(sig == SIGFPE && info->si_code == 0) {
pc = (byte*)r->rip;
if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix
pc++;
if(pc[0] == 0xF7)
info->si_code = FPE_INTDIV;
}
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
sp = (uintptr*)r->rsp;
*--sp = r->rip;
r->rip = (uintptr)sigpanic;
r->rsp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -64,11 +98,6 @@ sighandler(int32 sig, Siginfo *info, void *context)
printf("%s\n", sigtab[sig].name);
}
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
printf("Faulting address: %p\n", info->si_addr);
printf("pc: %X\n", r->rip);
printf("\n");
......
......@@ -67,6 +67,54 @@ enum {
$SA_ONSTACK = SA_ONSTACK,
$SA_USERTRAMP = SA_USERTRAMP,
$SA_64REGSET = SA_64REGSET,
$SIGHUP = SIGHUP,
$SIGINT = SIGINT,
$SIGQUIT = SIGQUIT,
$SIGILL = SIGILL,
$SIGTRAP = SIGTRAP,
$SIGABRT = SIGABRT,
$SIGEMT = SIGEMT,
$SIGFPE = SIGFPE,
$SIGKILL = SIGKILL,
$SIGBUS = SIGBUS,
$SIGSEGV = SIGSEGV,
$SIGSYS = SIGSYS,
$SIGPIPE = SIGPIPE,
$SIGALRM = SIGALRM,
$SIGTERM = SIGTERM,
$SIGURG = SIGURG,
$SIGSTOP = SIGSTOP,
$SIGTSTP = SIGTSTP,
$SIGCONT = SIGCONT,
$SIGCHLD = SIGCHLD,
$SIGTTIN = SIGTTIN,
$SIGTTOU = SIGTTOU,
$SIGIO = SIGIO,
$SIGXCPU = SIGXCPU,
$SIGXFSZ = SIGXFSZ,
$SIGVTALRM = SIGVTALRM,
$SIGPROF = SIGPROF,
$SIGWINCH = SIGWINCH,
$SIGINFO = SIGINFO,
$SIGUSR1 = SIGUSR1,
$SIGUSR2 = SIGUSR2,
$FPE_INTDIV = FPE_INTDIV,
$FPE_INTOVF = FPE_INTOVF,
$FPE_FLTDIV = FPE_FLTDIV,
$FPE_FLTOVF = FPE_FLTOVF,
$FPE_FLTUND = FPE_FLTUND,
$FPE_FLTRES = FPE_FLTRES,
$FPE_FLTINV = FPE_FLTINV,
$FPE_FLTSUB = FPE_FLTSUB,
$BUS_ADRALN = BUS_ADRALN,
$BUS_ADRERR = BUS_ADRERR,
$BUS_OBJERR = BUS_OBJERR,
$SEGV_MAPERR = SEGV_MAPERR,
$SEGV_ACCERR = SEGV_ACCERR,
};
typedef mach_msg_body_t $MachBody;
......
......@@ -22,3 +22,4 @@ void sigaction(uintptr, struct Sigaction*, struct Sigaction*);
struct StackT;
void sigaltstack(struct StackT*, struct StackT*);
void sigtramp(void);
void sigpanic(void);
......@@ -6,8 +6,9 @@
#define I SigIgnore
#define R SigRestart
#define Q SigQueue
#define P SigPanic
static SigTab sigtab[] = {
SigTab sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
......@@ -16,10 +17,10 @@ static SigTab sigtab[] = {
/* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */
/* 6 */ C, "SIGABRT: abort",
/* 7 */ C, "SIGEMT: emulate instruction executed",
/* 8 */ C, "SIGFPE: floating-point exception",
/* 8 */ C+P, "SIGFPE: floating-point exception",
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ C, "SIGBUS: bus error",
/* 11 */ C, "SIGSEGV: segmentation violation",
/* 10 */ C+P, "SIGBUS: bus error",
/* 11 */ C+P, "SIGSEGV: segmentation violation",
/* 12 */ C, "SIGSYS: bad system call",
/* 13 */ I, "SIGPIPE: write to broken pipe",
/* 14 */ Q+I+R, "SIGALRM: alarm clock",
......@@ -45,5 +46,6 @@ static SigTab sigtab[] = {
#undef I
#undef R
#undef Q
#undef P
#define NSIG 32
......@@ -6,6 +6,8 @@
#include "defs.h"
#include "os.h"
extern SigTab sigtab[];
static void
unimplemented(int8 *name)
{
......@@ -443,3 +445,26 @@ mach_semrelease(uint32 sem)
}
}
void
sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
panicstring("integer divide by zero");
case FPE_INTOVF:
panicstring("integer overflow");
}
panicstring("floating point error");
}
panicstring(sigtab[g->sig].name);
}
......@@ -48,7 +48,26 @@ void
sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
Mcontext *r;
uc = context;
r = &uc->uc_mcontext;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
sp = (uintptr*)r->mc_esp;
*--sp = r->mc_eip;
r->mc_eip = (uintptr)sigpanic;
r->mc_esp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -60,22 +79,18 @@ sighandler(int32 sig, Siginfo* info, void* context)
exit(2);
panicking = 1;
uc = context;
mc = &uc->uc_mcontext;
if(sig < 0 || sig >= NSIG)
printf("Signal %d\n", sig);
else
printf("%s\n", sigtab[sig].name);
printf("Faulting address: %p\n", info->si_addr);
printf("PC=%X\n", mc->mc_eip);
printf("PC=%X\n", r->mc_eip);
printf("\n");
if(gotraceback()){
traceback((void*)mc->mc_eip, (void*)mc->mc_esp, 0, m->curg);
traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg);
tracebackothers(m->curg);
dumpregs(mc);
dumpregs(r);
}
breakpoint();
......
......@@ -56,7 +56,26 @@ void
sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
Mcontext *r;
uc = context;
r = &uc->uc_mcontext;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
sp = (uintptr*)r->mc_rsp;
*--sp = r->mc_rip;
r->mc_rip = (uintptr)sigpanic;
r->mc_rsp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -68,21 +87,17 @@ sighandler(int32 sig, Siginfo* info, void* context)
exit(2);
panicking = 1;
uc = context;
mc = &uc->uc_mcontext;
if(sig < 0 || sig >= NSIG)
printf("Signal %d\n", sig);
else
printf("%s\n", sigtab[sig].name);
printf("Faulting address: %p\n", info->si_addr);
printf("PC=%X\n", mc->mc_rip);
printf("PC=%X\n", r->mc_rip);
printf("\n");
if(gotraceback()){
traceback((void*)mc->mc_rip, (void*)mc->mc_rsp, 0, (void*)mc->mc_r15);
tracebackothers((void*)mc->mc_r15);
traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, (void*)r->mc_r15);
tracebackothers((void*)r->mc_r15);
dumpregs(mc);
}
......
......@@ -37,6 +37,54 @@ enum {
$UMTX_OP_WAKE = UMTX_OP_WAKE,
$EINTR = EINTR,
$SIGHUP = SIGHUP,
$SIGINT = SIGINT,
$SIGQUIT = SIGQUIT,
$SIGILL = SIGILL,
$SIGTRAP = SIGTRAP,
$SIGABRT = SIGABRT,
$SIGEMT = SIGEMT,
$SIGFPE = SIGFPE,
$SIGKILL = SIGKILL,
$SIGBUS = SIGBUS,
$SIGSEGV = SIGSEGV,
$SIGSYS = SIGSYS,
$SIGPIPE = SIGPIPE,
$SIGALRM = SIGALRM,
$SIGTERM = SIGTERM,
$SIGURG = SIGURG,
$SIGSTOP = SIGSTOP,
$SIGTSTP = SIGTSTP,
$SIGCONT = SIGCONT,
$SIGCHLD = SIGCHLD,
$SIGTTIN = SIGTTIN,
$SIGTTOU = SIGTTOU,
$SIGIO = SIGIO,
$SIGXCPU = SIGXCPU,
$SIGXFSZ = SIGXFSZ,
$SIGVTALRM = SIGVTALRM,
$SIGPROF = SIGPROF,
$SIGWINCH = SIGWINCH,
$SIGINFO = SIGINFO,
$SIGUSR1 = SIGUSR1,
$SIGUSR2 = SIGUSR2,
$FPE_INTDIV = FPE_INTDIV,
$FPE_INTOVF = FPE_INTOVF,
$FPE_FLTDIV = FPE_FLTDIV,
$FPE_FLTOVF = FPE_FLTOVF,
$FPE_FLTUND = FPE_FLTUND,
$FPE_FLTRES = FPE_FLTRES,
$FPE_FLTINV = FPE_FLTINV,
$FPE_FLTSUB = FPE_FLTSUB,
$BUS_ADRALN = BUS_ADRALN,
$BUS_ADRERR = BUS_ADRERR,
$BUS_OBJERR = BUS_OBJERR,
$SEGV_MAPERR = SEGV_MAPERR,
$SEGV_ACCERR = SEGV_ACCERR,
};
typedef struct rtprio $Rtprio;
......
......@@ -6,8 +6,9 @@
#define I SigIgnore
#define R SigRestart
#define Q SigQueue
#define P SigPanic
static SigTab sigtab[] = {
SigTab sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
......@@ -16,10 +17,10 @@ static SigTab sigtab[] = {
/* 5 */ C, "SIGTRAP: trace trap",
/* 6 */ C, "SIGABRT: abort",
/* 7 */ C, "SIGEMT: EMT instruction",
/* 8 */ C, "SIGFPE: floating-point exception",
/* 8 */ C+P, "SIGFPE: floating-point exception",
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ C, "SIGBUS: bus error",
/* 11 */ C, "SIGSEGV: segmentation violation",
/* 10 */ C+P, "SIGBUS: bus error",
/* 11 */ C+P, "SIGSEGV: segmentation violation",
/* 12 */ C, "SIGSYS: bad system call",
/* 13 */ I, "SIGPIPE: write to broken pipe",
/* 14 */ Q+I+R, "SIGALRM: alarm clock",
......@@ -46,5 +47,6 @@ static SigTab sigtab[] = {
#undef I
#undef R
#undef Q
#undef P
#define NSIG 33
......@@ -6,6 +6,8 @@
#include "signals.h"
#include "os.h"
extern SigTab sigtab[];
// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
// thus the code is largely similar. See linux/thread.c for comments.
......@@ -169,3 +171,27 @@ minit(void)
m->gsignal = malg(32*1024);
signalstack(m->gsignal->stackguard, 32*1024);
}
void
sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
panicstring("integer divide by zero");
case FPE_INTOVF:
panicstring("integer overflow");
}
panicstring("floating point error");
}
panicstring(sigtab[g->sig].name);
}
// godefs -f -m32 -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c
// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c
// MACHINE GENERATED - DO NOT EDIT.
......@@ -14,6 +14,49 @@ enum {
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
SA_SIGINFO = 0x4,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGBUS = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGUSR1 = 0xa,
SIGSEGV = 0xb,
SIGUSR2 = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGSTKFLT = 0x10,
SIGCHLD = 0x11,
SIGCONT = 0x12,
SIGSTOP = 0x13,
SIGTSTP = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGURG = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGIO = 0x1d,
SIGPWR = 0x1e,
SIGSYS = 0x1f,
FPE_INTDIV = 0x1,
FPE_INTOVF = 0x2,
FPE_FLTDIV = 0x3,
FPE_FLTOVF = 0x4,
FPE_FLTUND = 0x5,
FPE_FLTRES = 0x6,
FPE_FLTINV = 0x7,
FPE_FLTSUB = 0x8,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
};
// Types
......
......@@ -45,7 +45,28 @@ void
sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Sigcontext *sc;
Sigcontext *r;
uintptr *sp;
G *gp;
uc = context;
r = &uc->uc_mcontext;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[3];
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->eip = (uintptr)sigpanic;
r->esp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -57,22 +78,18 @@ sighandler(int32 sig, Siginfo* info, void* context)
exit(2);
panicking = 1;
uc = context;
sc = &uc->uc_mcontext;
if(sig < 0 || sig >= NSIG)
printf("Signal %d\n", sig);
else
printf("%s\n", sigtab[sig].name);
printf("Faulting address: %p\n", *(void**)info->_sifields);
printf("PC=%X\n", sc->eip);
printf("PC=%X\n", r->eip);
printf("\n");
if(gotraceback()){
traceback((void*)sc->eip, (void*)sc->esp, 0, m->curg);
traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
tracebackothers(m->curg);
dumpregs(sc);
dumpregs(r);
}
breakpoint();
......
......@@ -14,6 +14,49 @@ enum {
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
SA_SIGINFO = 0x4,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGBUS = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGUSR1 = 0xa,
SIGSEGV = 0xb,
SIGUSR2 = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGSTKFLT = 0x10,
SIGCHLD = 0x11,
SIGCONT = 0x12,
SIGSTOP = 0x13,
SIGTSTP = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGURG = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGIO = 0x1d,
SIGPWR = 0x1e,
SIGSYS = 0x1f,
FPE_INTDIV = 0x1,
FPE_INTOVF = 0x2,
FPE_FLTDIV = 0x3,
FPE_FLTOVF = 0x4,
FPE_FLTUND = 0x5,
FPE_FLTRES = 0x6,
FPE_FLTINV = 0x7,
FPE_FLTSUB = 0x8,
BUS_ADRALN = 0x1,
BUS_ADRERR = 0x2,
BUS_OBJERR = 0x3,
SEGV_MAPERR = 0x1,
SEGV_ACCERR = 0x2,
};
// Types
......@@ -116,6 +159,12 @@ struct Fpstate1 {
uint32 padding[24];
};
typedef struct Fpreg1 Fpreg1;
struct Fpreg1 {
uint16 significand[4];
uint16 exponent;
};
typedef struct Sigaltstack Sigaltstack;
struct Sigaltstack {
void *ss_sp;
......
......@@ -54,7 +54,29 @@ sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
Sigcontext *sc;
Sigcontext *r;
uintptr *sp;
G *gp;
uc = context;
mc = &uc->uc_mcontext;
r = (Sigcontext*)mc; // same layout, more conveient names
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[2];
sp = (uintptr*)r->rsp;
*--sp = r->rip;
r->rip = (uintptr)sigpanic;
r->rsp = (uintptr)sp;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -66,23 +88,18 @@ sighandler(int32 sig, Siginfo* info, void* context)
exit(2);
panicking = 1;
uc = context;
mc = &uc->uc_mcontext;
sc = (Sigcontext*)mc; // same layout, more conveient names
if(sig < 0 || sig >= NSIG)
printf("Signal %d\n", sig);
else
printf("%s\n", sigtab[sig].name);
printf("Faulting address: %p\n", *(void**)info->_sifields);
printf("PC=%X\n", sc->rip);
printf("PC=%X\n", r->rip);
printf("\n");
if(gotraceback()){
traceback((void*)sc->rip, (void*)sc->rsp, 0, (void*)sc->r15);
tracebackothers((void*)sc->r15);
dumpregs(sc);
traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15);
tracebackothers((void*)r->r15);
dumpregs(r);
}
breakpoint();
......
......@@ -14,6 +14,49 @@ enum {
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
SA_SIGINFO = 0x4,
SIGHUP = 0x1,
SIGINT = 0x2,
SIGQUIT = 0x3,
SIGILL = 0x4,
SIGTRAP = 0x5,
SIGABRT = 0x6,
SIGBUS = 0x7,
SIGFPE = 0x8,
SIGKILL = 0x9,
SIGUSR1 = 0xa,
SIGSEGV = 0xb,
SIGUSR2 = 0xc,
SIGPIPE = 0xd,
SIGALRM = 0xe,
SIGSTKFLT = 0x10,
SIGCHLD = 0x11,
SIGCONT = 0x12,
SIGSTOP = 0x13,
SIGTSTP = 0x14,
SIGTTIN = 0x15,
SIGTTOU = 0x16,
SIGURG = 0x17,
SIGXCPU = 0x18,
SIGXFSZ = 0x19,
SIGVTALRM = 0x1a,
SIGPROF = 0x1b,
SIGWINCH = 0x1c,
SIGIO = 0x1d,
SIGPWR = 0x1e,
SIGSYS = 0x1f,
FPE_INTDIV = 0x30001,
FPE_INTOVF = 0x30002,
FPE_FLTDIV = 0x30003,
FPE_FLTOVF = 0x30004,
FPE_FLTUND = 0x30005,
FPE_FLTRES = 0x30006,
FPE_FLTINV = 0x30007,
FPE_FLTSUB = 0x30008,
BUS_ADRALN = 0x30001,
BUS_ADRERR = 0x30002,
BUS_OBJERR = 0x30003,
SEGV_MAPERR = 0x30001,
SEGV_ACCERR = 0x30002,
};
// Types
......
......@@ -53,7 +53,27 @@ void
sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Sigcontext *sc;
Sigcontext *r;
G *gp;
uc = context;
r = &uc->uc_mcontext;
if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
// the unwinding code.
gp->sig = sig;
gp->sigcode0 = info->si_code;
gp->sigcode1 = r->fault_address;
// If this is a leaf function, we do smash LR,
// but we're not going back there anyway.
r->arm_lr = r->arm_pc;
r->arm_pc = (uintptr)sigpanic;
return;
}
if(sigtab[sig].flags & SigQueue) {
if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
......@@ -70,18 +90,14 @@ sighandler(int32 sig, Siginfo *info, void *context)
else
printf("%s\n", sigtab[sig].name);
uc = context;
sc = &uc->uc_mcontext;
printf("Faulting address: %p\n", sc->fault_address);
printf("PC=%x\n", sc->arm_pc);
printf("PC=%x\n", r->arm_pc);
printf("\n");
if(gotraceback()){
traceback((void*)sc->arm_pc, (void*)sc->arm_sp, (void*)sc->arm_lr, m->curg);
traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg);
tracebackothers(m->curg);
printf("\n");
dumpregs(sc);
dumpregs(r);
}
// breakpoint();
......
......@@ -32,6 +32,53 @@ enum {
$SA_ONSTACK = SA_ONSTACK,
$SA_RESTORER = SA_RESTORER,
$SA_SIGINFO = SA_SIGINFO,
$SIGHUP = SIGHUP,
$SIGINT = SIGINT,
$SIGQUIT = SIGQUIT,
$SIGILL = SIGILL,
$SIGTRAP = SIGTRAP,
$SIGABRT = SIGABRT,
$SIGBUS = SIGBUS,
$SIGFPE = SIGFPE,
$SIGKILL = SIGKILL,
$SIGUSR1 = SIGUSR1,
$SIGSEGV = SIGSEGV,
$SIGUSR2 = SIGUSR2,
$SIGPIPE = SIGPIPE,
$SIGALRM = SIGALRM,
$SIGSTKFLT = SIGSTKFLT,
$SIGCHLD = SIGCHLD,
$SIGCONT = SIGCONT,
$SIGSTOP = SIGSTOP,
$SIGTSTP = SIGTSTP,
$SIGTTIN = SIGTTIN,
$SIGTTOU = SIGTTOU,
$SIGURG = SIGURG,
$SIGXCPU = SIGXCPU,
$SIGXFSZ = SIGXFSZ,
$SIGVTALRM = SIGVTALRM,
$SIGPROF = SIGPROF,
$SIGWINCH = SIGWINCH,
$SIGIO = SIGIO,
$SIGPWR = SIGPWR,
$SIGSYS = SIGSYS,
$FPE_INTDIV = FPE_INTDIV,
$FPE_INTOVF = FPE_INTOVF,
$FPE_FLTDIV = FPE_FLTDIV,
$FPE_FLTOVF = FPE_FLTOVF,
$FPE_FLTUND = FPE_FLTUND,
$FPE_FLTRES = FPE_FLTRES,
$FPE_FLTINV = FPE_FLTINV,
$FPE_FLTSUB = FPE_FLTSUB,
$BUS_ADRALN = BUS_ADRALN,
$BUS_ADRERR = BUS_ADRERR,
$BUS_OBJERR = BUS_OBJERR,
$SEGV_MAPERR = SEGV_MAPERR,
$SEGV_ACCERR = SEGV_ACCERR,
};
typedef struct timespec $Timespec;
......
......@@ -14,7 +14,6 @@ typedef __sigset_t $Usigset;
typedef struct _libc_fpxreg $Fpxreg;
typedef struct _libc_xmmreg $Xmmreg;
typedef struct _libc_fpstate $Fpstate;
typedef struct _libc_fpreg $Fpreg;
typedef struct _fpxreg $Fpxreg1;
typedef struct _xmmreg $Xmmreg1;
typedef struct _fpstate $Fpstate1;
......
......@@ -4,7 +4,12 @@
/*
* Input to godefs
godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include defs2.c >386/defs.h
godefs -f -m32 \
-f -I/home/rsc/pub/linux-2.6/arch/x86/include \
-f -I/home/rsc/pub/linux-2.6/include \
-f -D_LOOSE_KERNEL_NAMES \
-f -D__ARCH_SI_UID_T=__kernel_uid32_t \
defs2.c >386/defs.h
* The asm header tricks we have to use for Linux on amd64
* (see defs.c and defs1.c) don't work here, so this is yet another
......@@ -47,6 +52,53 @@ enum {
$SA_ONSTACK = SA_ONSTACK,
$SA_RESTORER = SA_RESTORER,
$SA_SIGINFO = SA_SIGINFO,
$SIGHUP = SIGHUP,
$SIGINT = SIGINT,
$SIGQUIT = SIGQUIT,
$SIGILL = SIGILL,
$SIGTRAP = SIGTRAP,
$SIGABRT = SIGABRT,
$SIGBUS = SIGBUS,
$SIGFPE = SIGFPE,
$SIGKILL = SIGKILL,
$SIGUSR1 = SIGUSR1,
$SIGSEGV = SIGSEGV,
$SIGUSR2 = SIGUSR2,
$SIGPIPE = SIGPIPE,
$SIGALRM = SIGALRM,
$SIGSTKFLT = SIGSTKFLT,
$SIGCHLD = SIGCHLD,
$SIGCONT = SIGCONT,
$SIGSTOP = SIGSTOP,
$SIGTSTP = SIGTSTP,
$SIGTTIN = SIGTTIN,
$SIGTTOU = SIGTTOU,
$SIGURG = SIGURG,
$SIGXCPU = SIGXCPU,
$SIGXFSZ = SIGXFSZ,
$SIGVTALRM = SIGVTALRM,
$SIGPROF = SIGPROF,
$SIGWINCH = SIGWINCH,
$SIGIO = SIGIO,
$SIGPWR = SIGPWR,
$SIGSYS = SIGSYS,
$FPE_INTDIV = FPE_INTDIV,
$FPE_INTOVF = FPE_INTOVF,
$FPE_FLTDIV = FPE_FLTDIV,
$FPE_FLTOVF = FPE_FLTOVF,
$FPE_FLTUND = FPE_FLTUND,
$FPE_FLTRES = FPE_FLTRES,
$FPE_FLTINV = FPE_FLTINV,
$FPE_FLTSUB = FPE_FLTSUB,
$BUS_ADRALN = BUS_ADRALN,
$BUS_ADRERR = BUS_ADRERR,
$BUS_OBJERR = BUS_OBJERR,
$SEGV_MAPERR = SEGV_MAPERR,
$SEGV_ACCERR = SEGV_ACCERR,
};
typedef struct _fpreg $Fpreg;
......
......@@ -35,7 +35,54 @@ enum {
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
$SA_RESTORER = SA_RESTORER,
$SA_SIGINFO = SA_SIGINFO
$SA_SIGINFO = SA_SIGINFO,
$SIGHUP = SIGHUP,
$SIGINT = SIGINT,
$SIGQUIT = SIGQUIT,
$SIGILL = SIGILL,
$SIGTRAP = SIGTRAP,
$SIGABRT = SIGABRT,
$SIGBUS = SIGBUS,
$SIGFPE = SIGFPE,
$SIGKILL = SIGKILL,
$SIGUSR1 = SIGUSR1,
$SIGSEGV = SIGSEGV,
$SIGUSR2 = SIGUSR2,
$SIGPIPE = SIGPIPE,
$SIGALRM = SIGALRM,
$SIGSTKFLT = SIGSTKFLT,
$SIGCHLD = SIGCHLD,
$SIGCONT = SIGCONT,
$SIGSTOP = SIGSTOP,
$SIGTSTP = SIGTSTP,
$SIGTTIN = SIGTTIN,
$SIGTTOU = SIGTTOU,
$SIGURG = SIGURG,
$SIGXCPU = SIGXCPU,
$SIGXFSZ = SIGXFSZ,
$SIGVTALRM = SIGVTALRM,
$SIGPROF = SIGPROF,
$SIGWINCH = SIGWINCH,
$SIGIO = SIGIO,
$SIGPWR = SIGPWR,
$SIGSYS = SIGSYS,
$FPE_INTDIV = FPE_INTDIV,
$FPE_INTOVF = FPE_INTOVF,
$FPE_FLTDIV = FPE_FLTDIV,
$FPE_FLTOVF = FPE_FLTOVF,
$FPE_FLTUND = FPE_FLTUND,
$FPE_FLTRES = FPE_FLTRES,
$FPE_FLTINV = FPE_FLTINV,
$FPE_FLTSUB = FPE_FLTSUB,
$BUS_ADRALN = BUS_ADRALN,
$BUS_ADRERR = BUS_ADRERR,
$BUS_OBJERR = BUS_OBJERR,
$SEGV_MAPERR = SEGV_MAPERR,
$SEGV_ACCERR = SEGV_ACCERR,
};
typedef sigset_t $Sigset;
......
......@@ -10,3 +10,4 @@ struct Sigaction;
void rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
void sigaltstack(Sigaltstack*, Sigaltstack*);
void sigpanic(void);
......@@ -6,8 +6,9 @@
#define I SigIgnore
#define R SigRestart
#define Q SigQueue
#define P SigPanic
static SigTab sigtab[] = {
SigTab sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
......@@ -15,11 +16,11 @@ static SigTab sigtab[] = {
/* 4 */ C, "SIGILL: illegal instruction",
/* 5 */ C, "SIGTRAP: trace trap",
/* 6 */ C, "SIGABRT: abort",
/* 7 */ C, "SIGBUS: bus error",
/* 8 */ C, "SIGFPE: floating-point exception",
/* 7 */ C+P, "SIGBUS: bus error",
/* 8 */ C+P, "SIGFPE: floating-point exception",
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ Q+I+R, "SIGUSR1: user-defined signal 1",
/* 11 */ C, "SIGSEGV: segmentation violation",
/* 11 */ C+P, "SIGSEGV: segmentation violation",
/* 12 */ Q+I+R, "SIGUSR2: user-defined signal 2",
/* 13 */ I, "SIGPIPE: write to broken pipe",
/* 14 */ Q+I+R, "SIGALRM: alarm clock",
......@@ -45,5 +46,6 @@ static SigTab sigtab[] = {
#undef I
#undef R
#undef Q
#undef P
#define NSIG 32
......@@ -4,9 +4,10 @@
#include "runtime.h"
#include "defs.h"
#include "signals.h"
#include "os.h"
extern SigTab sigtab[];
// Linux futex.
//
// futexsleep(uint32 *addr, uint32 val)
......@@ -270,3 +271,27 @@ minit(void)
m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
signalstack(m->gsignal->stackguard, 32*1024);
}
void
sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGSEGV:
if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR) && g->sigcode1 < 0x1000)
panicstring("invalid memory address or nil pointer dereference");
break;
case SIGFPE:
switch(g->sigcode0) {
case FPE_INTDIV:
panicstring("integer divide by zero");
case FPE_INTOVF:
panicstring("integer overflow");
}
panicstring("floating point error");
}
panicstring(sigtab[g->sig].name);
}
......@@ -198,6 +198,9 @@ struct G
M* lockedm;
void (*cgofn)(void*); // for cgo/ffi
void *cgoarg;
int32 sig;
uintptr sigcode0;
uintptr sigcode1;
};
struct M
{
......@@ -268,6 +271,7 @@ enum
SigIgnore = 1<<1,
SigRestart = 1<<2,
SigQueue = 1<<3,
SigPanic = 1<<4,
};
// NOTE(rsc): keep in sync with extern.go:/type.Func.
......
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"runtime"
"strings"
"syscall"
)
var didbug bool
func bug() {
if didbug {
return
}
println("BUG")
didbug = true
}
func check(name string, f func(), err string) {
defer func() {
v := recover()
if v == nil {
bug()
println(name, "did not panic")
return
}
runt, ok := v.(runtime.Error)
if !ok {
bug()
println(name, "panicked but not with runtime.Error")
return
}
s := runt.String()
if strings.Index(s, err) < 0 {
bug()
println(name, "panicked with", s, "not", err)
return
}
}()
f()
}
func main() {
var x int
var x64 int64
var p *[10]int
var q *[10000]int
var i int
// not catching divide by zero on the arm. is that even possible?
if syscall.ARCH != "arm" {
check("int-div-zero", func() { println(1/x) }, "integer divide by zero")
check("int64-div-zero", func() { println(1/x64) }, "integer divide by zero")
}
check("nil-deref", func() { println(p[0]) }, "nil pointer dereference")
check("nil-deref-1", func() { println(p[1]) }, "nil pointer dereference")
check("nil-deref-big", func() { println(q[5000]) }, "nil pointer dereference")
i = 99999
var sl []int
check("array-bounds", func() { println(p[i]) }, "index out of range")
check("slice-bounds", func() { println(sl[i]) }, "index out of range")
var inter interface{}
inter = 1
check("type-concrete", func() { println(inter.(string)) }, "int, not string")
check("type-interface", func() { println(inter.(m)) }, "missing method m")
}
type m interface{ m() }
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