"#define m(r) 4(r)\n"
},
{"386", "plan9",
+ "// Plan 9 does not have per-process segment descriptors with\n"
+ "// which to do thread-local storage. Instead, we will use a\n"
+ "// fixed offset from the per-process TOS struct address for\n"
+ "// the local storage. Since the process ID is contained in the\n"
+ "// TOS struct, we specify an offset for that here as well.\n"
"#define get_tls(r) MOVL _tos(SB), r \n"
"#define g(r) -8(r)\n"
"#define m(r) -4(r)\n"
+ "#define procid(r) 48(r)\n"
},
{"386", "linux",
"// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n"
-// nothing to see here
-#define tos_pid 48
#define PAGESIZE 0x1000
+
+typedef struct Ureg Ureg;
+
+struct Ureg
+{
+ uint32 di; /* general registers */
+ uint32 si; /* ... */
+ uint32 bp; /* ... */
+ uint32 nsp;
+ uint32 bx; /* ... */
+ uint32 dx; /* ... */
+ uint32 cx; /* ... */
+ uint32 ax; /* ... */
+ uint32 gs; /* data segments */
+ uint32 fs; /* ... */
+ uint32 es; /* ... */
+ uint32 ds; /* ... */
+ uint32 trap; /* trap type */
+ uint32 ecode; /* error code (or zero) */
+ uint32 pc; /* pc */
+ uint32 cs; /* old context */
+ uint32 flags; /* old flags */
+ union {
+ uint32 usp;
+ uint32 sp;
+ };
+ uint32 ss; /* old stack segment */
+};
-// nothing to see here
#define PAGESIZE 0x200000ULL
+
+typedef struct Ureg Ureg;
+
+struct Ureg {
+ uint64 ax;
+ uint64 bx;
+ uint64 cx;
+ uint64 dx;
+ uint64 si;
+ uint64 di;
+ uint64 bp;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+
+ uint16 ds;
+ uint16 es;
+ uint16 fs;
+ uint16 gs;
+
+ uint64 type;
+ uint64 error; /* error code (or zero) */
+ uint64 ip; /* pc */
+ uint64 cs; /* old context */
+ uint64 flags; /* old flags */
+ uint64 sp; /* sp */
+ uint64 ss; /* old stack segment */
+};
int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms);
int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
-int32 runtime·notify(void (*fn)(void*, byte*));
+int32 runtime·notify(void (*fn)(void*, int8*));
int32 runtime·noted(int32);
-void runtime·gonote(void*, byte*);
+void runtime·sigtramp(void*, int8*);
+int32 runtime·sighandler(void*, int8*, G*);
+void runtime·sigpanic(void);
+void runtime·goexitsall(int8*);
void runtime·setfpmasks(void);
/* open */
/* top of stack is here */
};
-#define NSIG 1
+#define NSIG 5 /* number of signals in runtime·SigTab array */
+#define ERRMAX 128 /* max length of note string */
#ifdef GOOS_windows
void* thread; // thread handle
+#endif
+#ifdef GOOS_plan9
+ int8* notesig;
#endif
SEH* seh;
uintptr end[];
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Ureg *u)
+{
+ runtime·printf("ax %X\n", u->ax);
+ runtime·printf("bx %X\n", u->bx);
+ runtime·printf("cx %X\n", u->cx);
+ runtime·printf("dx %X\n", u->dx);
+ runtime·printf("di %X\n", u->di);
+ runtime·printf("si %X\n", u->si);
+ runtime·printf("bp %X\n", u->bp);
+ runtime·printf("sp %X\n", u->sp);
+ runtime·printf("pc %X\n", u->pc);
+ runtime·printf("flags %X\n", u->flags);
+ runtime·printf("cs %X\n", u->cs);
+ runtime·printf("fs %X\n", u->fs);
+ runtime·printf("gs %X\n", u->gs);
+}
+
+int32
+runtime·sighandler(void *v, int8 *s, G *gp)
+{
+ Ureg *ureg;
+ uintptr *sp;
+ SigTab *sig, *nsig;
+ int32 len, i;
+
+ if(!s)
+ return NCONT;
+
+ len = runtime·findnull((byte*)s);
+ if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
+ return NDFLT;
+
+ nsig = nil;
+ sig = runtime·sigtab;
+ for(i=0; i < NSIG; i++) {
+ if(runtime·strstr((byte*)s, (byte*)sig->name)) {
+ nsig = sig;
+ break;
+ }
+ sig++;
+ }
+
+ if(nsig == nil)
+ return NDFLT;
+
+ ureg = v;
+ if(nsig->flags & SigPanic) {
+ if(gp == nil || m->notesig == 0)
+ goto Throw;
+
+ // Save error string from sigtramp's stack,
+ // into gsignal->sigcode0, so we can reliably
+ // access it from the panic routines.
+ if(len > ERRMAX)
+ len = ERRMAX;
+ runtime·memmove((void*)m->notesig, (void*)s, len);
+
+ gp->sig = i;
+ gp->sigpc = ureg->pc;
+
+ // Only push runtime·sigpanic if ureg->pc != 0.
+ // If ureg->pc == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(ureg->pc != 0) {
+ sp = (uintptr*)ureg->sp;
+ *--sp = ureg->pc;
+ ureg->sp = (uint32)sp;
+ }
+ ureg->pc = (uintptr)runtime·sigpanic;
+ return NCONT;
+ }
+
+ if(!(nsig->flags & SigThrow))
+ return NDFLT;
+
+Throw:
+ runtime·startpanic();
+
+ runtime·printf("%s\n", s);
+ runtime·printf("PC=%X\n", ureg->pc);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()) {
+ runtime·traceback((void*)ureg->pc, (void*)ureg->sp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(ureg);
+ }
+ runtime·goexitsall("");
+ runtime·exits(s);
+
+ return 0;
+}
+
void
runtime·sigenable(uint32 sig)
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Ureg *u)
+{
+ runtime·printf("ax %X\n", u->ax);
+ runtime·printf("bx %X\n", u->bx);
+ runtime·printf("cx %X\n", u->cx);
+ runtime·printf("dx %X\n", u->dx);
+ runtime·printf("di %X\n", u->di);
+ runtime·printf("si %X\n", u->si);
+ runtime·printf("bp %X\n", u->bp);
+ runtime·printf("sp %X\n", u->sp);
+ runtime·printf("r8 %X\n", u->r8);
+ runtime·printf("r9 %X\n", u->r9);
+ runtime·printf("r10 %X\n", u->r10);
+ runtime·printf("r11 %X\n", u->r11);
+ runtime·printf("r12 %X\n", u->r12);
+ runtime·printf("r13 %X\n", u->r13);
+ runtime·printf("r14 %X\n", u->r14);
+ runtime·printf("r15 %X\n", u->r15);
+ runtime·printf("ip %X\n", u->ip);
+ runtime·printf("flags %X\n", u->flags);
+ runtime·printf("cs %X\n", (uint64)u->cs);
+ runtime·printf("fs %X\n", (uint64)u->fs);
+ runtime·printf("gs %X\n", (uint64)u->gs);
+}
+
+int32
+runtime·sighandler(void *v, int8 *s, G *gp)
+{
+ Ureg *ureg;
+ uintptr *sp;
+ SigTab *sig, *nsig;
+ int32 len, i;
+
+ if(!s)
+ return NCONT;
+
+ len = runtime·findnull((byte*)s);
+ if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
+ return NDFLT;
+
+ nsig = nil;
+ sig = runtime·sigtab;
+ for(i=0; i < NSIG; i++) {
+ if(runtime·strstr((byte*)s, (byte*)sig->name)) {
+ nsig = sig;
+ break;
+ }
+ sig++;
+ }
+
+ if(nsig == nil)
+ return NDFLT;
+
+ ureg = v;
+ if(nsig->flags & SigPanic) {
+ if(gp == nil || m->notesig == 0)
+ goto Throw;
+
+ // Save error string from sigtramp's stack,
+ // into gsignal->sigcode0, so we can reliably
+ // access it from the panic routines.
+ if(len > ERRMAX)
+ len = ERRMAX;
+ runtime·memmove((void*)m->notesig, (void*)s, len);
+
+ gp->sig = i;
+ gp->sigpc = ureg->ip;
+
+ // Only push runtime·sigpanic if ureg->ip != 0.
+ // If ureg->ip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(ureg->ip != 0) {
+ sp = (uintptr*)ureg->sp;
+ *--sp = ureg->ip;
+ ureg->sp = (uint64)sp;
+ }
+ ureg->ip = (uintptr)runtime·sigpanic;
+ return NCONT;
+ }
+
+ if(!(nsig->flags & SigThrow))
+ return NDFLT;
+
+Throw:
+ runtime·startpanic();
+
+ runtime·printf("%s\n", s);
+ runtime·printf("PC=%X\n", ureg->ip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()) {
+ runtime·traceback((void*)ureg->ip, (void*)ureg->sp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(ureg);
+ }
+ runtime·goexitsall("");
+ runtime·exits(s);
+
+ return 0;
+}
void
runtime·sigenable(uint32 sig)
-// nothing to see here
+#define N SigNotify
+#define T SigThrow
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ P, "sys: fp:",
+
+ // Go libraries expect to be able
+ // to recover from memory
+ // read/write errors, so we flag
+ // those as panics. All other traps
+ // are generally more serious and
+ // should immediately throw an
+ // exception.
+ P, "sys: trap: fault read addr",
+ P, "sys: trap: fault write addr",
+ T, "sys: trap:",
+
+ N, "sys: bad sys call",
+};
+
+#undef N
+#undef T
+#undef P
enum {
// StackSystem is a number of additional bytes to add
// to each stack below the usual guard area for OS-specific
- // purposes like signal handling. Used on Windows because
- // it does not use a separate stack.
+ // purposes like signal handling. Used on Windows and on
+ // Plan 9 because they do not use a separate stack.
#ifdef GOOS_windows
StackSystem = 512 * sizeof(uintptr),
+#else
+#ifdef GOOS_plan9
+ // The size of the note handler frame varies among architectures,
+ // but 512 bytes should be enough for every implementation.
+ StackSystem = 512,
#else
StackSystem = 0,
-#endif
+#endif // Plan 9
+#endif // Windows
// The amount of extra stack to allocate beyond the size
// needed for the single frame that triggered the split.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "defs_GOOS_GOARCH.h"
#include "zasm_GOOS_GOARCH.h"
// setldt(int entry, int address, int limit)
MOVL DX, g(AX)
MOVL BX, m(AX)
- // Initialize AX from _tos->pid
- MOVL _tos(SB), AX
- MOVL tos_pid(AX), AX
+ // Initialize AX from TOS struct.
+ MOVL procid(AX), AX
MOVL AX, m_procid(BX) // save pid as m->procid
CALL runtime·stackcheck(SB) // smashes AX, CX
CALL runtime·exit(SB)
RET
+// void sigtramp(void *ureg, int8 *note)
+TEXT runtime·sigtramp(SB),7,$0
+ get_tls(AX)
+
+ // check that m exists
+ MOVL m(AX), BX
+ CMPL BX, $0
+ JNE 3(PC)
+ CALL runtime·badsignal(SB) // will exit
+ RET
+
+ // save args
+ MOVL ureg+4(SP), CX
+ MOVL note+8(SP), DX
+
+ // change stack
+ MOVL m_gsignal(BX), BP
+ MOVL g_stackbase(BP), BP
+ MOVL BP, SP
+
+ // make room for args and g
+ SUBL $16, SP
+
+ // save g
+ MOVL g(AX), BP
+ MOVL BP, 12(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), DI
+ MOVL DI, g(AX)
+
+ // load args and call sighandler
+ MOVL CX, 0(SP)
+ MOVL DX, 4(SP)
+ MOVL BP, 8(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVL 12(SP), BP
+ MOVL BP, g(BX)
+
+ // call noted(AX)
+ MOVL AX, 0(SP)
+ CALL runtime·noted(SB)
+ RET
+
// Only used by the 64-bit runtime.
TEXT runtime·setfpmasks(SB),7,$0
RET
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "defs_GOOS_GOARCH.h"
#include "zasm_GOOS_GOARCH.h"
// setldt(int entry, int address, int limit)
MOVQ $38, BP
SYSCALL
RET
-
+
TEXT runtime·rfork(SB),7,$0
MOVQ $0x8000, AX
MOVQ $19, BP // rfork
TEXT runtime·settls(SB),7,$0
RET
+// void sigtramp(void *ureg, int8 *note)
+TEXT runtime·sigtramp(SB),7,$0
+ get_tls(AX)
+
+ // check that m exists
+ MOVQ m(AX), BX
+ CMPQ BX, $0
+ JNE 3(PC)
+ CALL runtime·badsignal(SB) // will exit
+ RET
+
+ // save args
+ MOVQ ureg+8(SP), CX
+ MOVQ note+16(SP), DX
+
+ // change stack
+ MOVQ m_gsignal(BX), R10
+ MOVQ g_stackbase(R10), BP
+ MOVQ BP, SP
+
+ // make room for args and g
+ SUBQ $32, SP
+
+ // save g
+ MOVQ g(AX), BP
+ MOVQ BP, 24(SP)
+
+ // g = m->gsignal
+ MOVQ R10, g(AX)
+
+ // load args and call sighandler
+ MOVQ CX, 0(SP)
+ MOVQ DX, 8(SP)
+ MOVQ BP, 16(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 24(SP), R10
+ MOVQ R10, g(BX)
+
+ // call noted(AX)
+ MOVQ AX, 0(SP)
+ CALL runtime·noted(SB)
+ RET
+
TEXT runtime·setfpmasks(SB),7,$8
STMXCSR 0(SP)
MOVL 0(SP), AX
#include "arch_GOARCH.h"
int8 *goos = "plan9";
-int8 *runtime·exitstatus;
+extern SigTab runtime·sigtab[];
int32 runtime·postnote(int32, int8*);
void
runtime·minit(void)
{
+ // Initialize stack and goroutine for note handling.
+ m->gsignal = runtime·malg(32*1024);
+ m->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8));
+
// Mask all SSE floating-point exceptions
// when running on the 64-bit kernel.
runtime·setfpmasks();
{
runtime·ncpu = getproccount();
m->procid = getpid();
- runtime·notify(runtime·gonote);
+ runtime·notify(runtime·sigtramp);
}
void
}
void
-goexitsall(void)
+runtime·goexitsall(int8 *status)
{
M *mp;
int32 pid;
pid = getpid();
for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
if(mp->procid != pid)
- runtime·postnote(mp->procid, "gointr");
-}
-
-void
-runtime·gonote(void*, byte *s)
-{
- uint8 buf[128];
- int32 l;
-
- l = runtime·findnull(s);
- if(l > 4 && runtime·mcmp(s, (byte*)"sys:", 4) == 0) {
- runtime·memclr(buf, sizeof buf);
- runtime·memmove((void*)buf, (void*)s, runtime·findnull(s));
- runtime·exitstatus = (int8*)buf;
- goexitsall();
- runtime·noted(NDFLT);
- }
-
- if(runtime·exitstatus)
- runtime·exits(runtime·exitstatus);
-
- if(runtime·strcmp(s, (byte*)"gointr") == 0)
- runtime·noted(NCONT);
-
- runtime·noted(NDFLT);
+ runtime·postnote(mp->procid, status);
}
int32
runtime·exit(int32 e)
{
byte tmp[16];
-
+ int8 *status;
+
if(e == 0)
- runtime·exitstatus = "";
+ status = "";
else {
/* build error string */
runtime·itoa(e, tmp, sizeof tmp);
- runtime·exitstatus = (int8*)tmp;
+ status = (int8*)tmp;
}
- goexitsall();
- runtime·exits(runtime·exitstatus);
+ runtime·goexitsall(status);
+ runtime·exits(status);
}
void
runtime·throw("too many writes on closed pipe");
}
-/*
- * placeholder - once notes are implemented,
- * a signal generating a panic must appear as
- * a call to this function for correct handling by
- * traceback.
- */
void
runtime·sigpanic(void)
{
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring(m->notesig);
+
+ if(g->sig == 1 || g->sig == 2)
+ runtime·throw("fault");
}
int32
// This runs on a foreign stack, without an m or a g. No stack split.
#pragma textflag 7
void
-runtime·badsignal(int32 sig)
+runtime·badsignal(void)
{
- USED(sig);
runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
+ runtime·exits(badsignal);
}