]> Cypherpunks repositories - gostls13.git/commitdiff
windows: implement exception handling
authorHector Chu <hectorchu@gmail.com>
Wed, 19 Jan 2011 20:10:15 +0000 (15:10 -0500)
committerRuss Cox <rsc@golang.org>
Wed, 19 Jan 2011 20:10:15 +0000 (15:10 -0500)
R=rsc, brainman
CC=golang-dev
https://golang.org/cl/4079041

13 files changed:
.hgignore
src/cmd/8l/pass.c
src/cmd/godefs/main.c
src/cmd/godefs/stabs.c
src/pkg/runtime/proc.c
src/pkg/runtime/windows/386/defs.h
src/pkg/runtime/windows/386/rt0.s
src/pkg/runtime/windows/386/signal.c
src/pkg/runtime/windows/386/sys.s
src/pkg/runtime/windows/defs.c
src/pkg/runtime/windows/mem.c
src/pkg/runtime/windows/os.h
src/pkg/runtime/windows/thread.c

index 95a1665ec42b48f54b747f98cf422809e1136d49..2d037467ab02c3b95e090aab5fe485a0d7e32a87 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -11,6 +11,8 @@ syntax:glob
 [568a].out
 *~
 *.orig
+*.exe
+.*.swp
 core
 _cgo_*
 _obj
index 6e387b0b5e4d6c9cfb0fdf8979c45b4785276559..c3f1f4736fc142e0c8daea6b819142907916b87f 100644 (file)
@@ -38,8 +38,15 @@ static void xfol(Prog*, Prog**);
 // see ../../pkg/runtime/proc.c:/StackGuard
 enum
 {
+#ifdef __WINDOWS__
+       // use larger stacks to compensate for larger stack guard,
+       // needed for exception handling.
+       StackSmall = 256,
+       StackBig = 8192,
+#else
        StackSmall = 128,
        StackBig = 4096,
+#endif
 };
 
 Prog*
index 69ee1be5dbc099c9c84aebcb6bc459f034fbc341..d4163421d1ab9bee51e007e268ba458d0553269c 100644 (file)
@@ -196,7 +196,7 @@ main(int argc, char **argv)
        av[n++] = "gcc";
        av[n++] = "-fdollars-in-identifiers";
        av[n++] = "-S"; // write assembly
-       av[n++] = "-gstabs";    // include stabs info
+       av[n++] = "-gstabs+";   // include stabs info
        av[n++] = "-o"; // to ...
        av[n++] = "-";  // ... stdout
        av[n++] = "-xc";        // read C
index 1bc96d4c8c200ee8599818524abc2c96d733f193..f2bb57eb651a4d7ef4d24ac57855663f9870f1ea 100644 (file)
@@ -102,6 +102,23 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p)
        return 0;
 }
 
+// Written to parse max/min of vlong correctly.
+static vlong
+parseoctal(char **pp)
+{
+       char *p;
+       vlong n;
+
+       p = *pp;
+       if(*p++ != '0')
+               return 0;
+       n = 0;
+       while(*p >= '0' && *p <= '9')
+               n = n << 3 | *p++ - '0';
+       *pp = p;
+       return n;
+}
+
 // Integer types are represented in stabs as a "range"
 // type with a lo and a hi value.  The lo and hi used to
 // be lo and hi for the type, but there are now odd
@@ -112,31 +129,24 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p)
 typedef struct Intrange Intrange;
 struct Intrange
 {
-       int signlo;     // sign of lo
        vlong lo;
-       int signhi;     // sign of hi
        vlong hi;
        int kind;
 };
 
-// NOTE(rsc): Iant says that these might be different depending
-// on the gcc mode, though I haven't observed this yet.
 Intrange intranges[] = {
-       '+', 0, '+', 127, Int8, // char
-       '-', 128, '+', 127, Int8,       // signed char
-       '+', 0, '+', 255, Uint8,
-       '-', 32768, '+', 32767, Int16,
-       '+', 0, '+', 65535, Uint16,
-       '-', 2147483648LL, '+', 2147483647LL, Int32,
-       '+', 0, '+', 4294967295LL, Uint32,
-
-       // abnormal cases
-       '-', 0, '+', 4294967295LL, Int64,
-       '+', 0, '-', 1, Uint64,
-
-       '+', 4, '+', 0, Float32,
-       '+', 8, '+', 0, Float64,
-       '+', 16, '+', 0, Void,
+       0, 127, Int8,           // char
+       -128, 127, Int8,        // signed char
+       0, 255, Uint8,
+       -32768, 32767, Int16,
+       0, 65535, Uint16,
+       -2147483648LL, 2147483647LL, Int32,
+       0, 4294967295LL, Uint32,
+       1LL << 63, ~(1LL << 63), Int64,
+       0, -1, Uint64,
+       4, 0, Float32,
+       8, 0, Float64,
+       16, 0, Void,
 };
 
 static int kindsize[] = {
@@ -158,7 +168,7 @@ parsedef(char **pp, char *name)
 {
        char *p;
        Type *t, *tt;
-       int i, signlo, signhi;
+       int i;
        vlong n1, n2, lo, hi;
        Field *f;
        Intrange *r;
@@ -213,6 +223,11 @@ parsedef(char **pp, char *name)
                *pp = "";
                return t;
 
+       case '@':       // type attribute
+               while (*++p != ';');
+               *pp = ++p;
+               return parsedef(pp, nil);
+
        case '*':       // pointer
                p++;
                t->kind = Ptr;
@@ -269,6 +284,10 @@ parsedef(char **pp, char *name)
                        return nil;
                break;
 
+       case 'k':       // const
+               ++*pp;
+               return parsedef(pp, nil);
+
        case 'r':       // sub-range (used for integers)
                p++;
                if(parsedef(&p, nil) == nil)
@@ -280,23 +299,19 @@ parsedef(char **pp, char *name)
                                fprint(2, "range expected number: %s\n", p);
                        return nil;
                }
-               if(*p == '-') {
-                       signlo = '-';
-                       p++;
-               } else
-                       signlo = '+';
-               lo = strtoll(p, &p, 10);
+               if(*p == '0')
+                       lo = parseoctal(&p);
+               else
+                       lo = strtoll(p, &p, 10);
                if(*p != ';' || *++p == ';') {
                        if(stabsdebug)
                                fprint(2, "range expected number: %s\n", p);
                        return nil;
                }
-               if(*p == '-') {
-                       signhi = '-';
-                       p++;
-               } else
-                       signhi = '+';
-               hi = strtoll(p, &p, 10);
+               if(*p == '0')
+                       hi = parseoctal(&p);
+               else
+                       hi = strtoll(p, &p, 10);
                if(*p != ';') {
                        if(stabsdebug)
                                fprint(2, "range expected trailing semi: %s\n", p);
@@ -306,7 +321,7 @@ parsedef(char **pp, char *name)
                t->size = hi+1; // might be array size
                for(i=0; i<nelem(intranges); i++) {
                        r = &intranges[i];
-                       if(r->signlo == signlo && r->signhi == signhi && r->lo == lo && r->hi == hi) {
+                       if(r->lo == lo && r->hi == hi) {
                                t->kind = r->kind;
                                break;
                        }
index 09c7a1dbc9da85d7675405f12307484d2e52828d..5eb466e04ee4c904412772c4b0f94058874c52bd 100644 (file)
@@ -733,6 +733,14 @@ runtime·endcgocallback(G* g1)
  */
 enum
 {
+#ifdef __WINDOWS__
+       // need enough room in guard area for exception handler.
+       // use larger stacks to compensate for larger stack guard.
+       StackSmall = 256,
+       StackGuard = 2048,
+       StackBig   = 8192,
+       StackExtra = StackGuard,
+#else
        // byte offset of stack guard (g->stackguard) above bottom of stack.
        StackGuard = 256,
 
@@ -745,6 +753,10 @@ enum
        // the frame is allocated) is assumed not to be much bigger
        // than this amount.  it may not be used efficiently if it is.
        StackBig = 4096,
+
+       // extra room over frame size when allocating a stack.
+       StackExtra = 1024,
+#endif
 };
 
 void
@@ -812,7 +824,7 @@ runtime·newstack(void)
                framesize += argsize;
                if(framesize < StackBig)
                        framesize = StackBig;
-               framesize += 1024;      // room for more functions, Stktop.
+               framesize += StackExtra;        // room for more functions, Stktop.
                stk = runtime·stackalloc(framesize);
                top = (Stktop*)(stk+framesize-sizeof(*top));
                free = true;
@@ -915,7 +927,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
                if(newg->stackguard - StackGuard != newg->stack0)
                        runtime·throw("invalid stack in newg");
        } else {
-               newg = runtime·malg(4096);
+               newg = runtime·malg(StackBig);
                newg->status = Gwaiting;
                newg->alllink = runtime·allg;
                runtime·allg = newg;
index f5a16367eb7215941a1a7a0c2bf3f1eb1c036da1..a2a882103462b7cb6d50185e12ce1f2bfaa9504d 100644 (file)
@@ -10,8 +10,69 @@ enum {
        PROT_EXEC = 0x4,
        MAP_ANON = 0x1,
        MAP_PRIVATE = 0x2,
+       EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+       EXCEPTION_BREAKPOINT = 0x80000003,
+       EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
+       EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
+       EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
+       EXCEPTION_FLT_OVERFLOW = 0xc0000091,
+       EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
+       EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
+       EXCEPTION_INT_OVERFLOW = 0xc0000095,
 };
 
 // Types
 #pragma pack on
+
+typedef struct ExceptionRecord ExceptionRecord;
+struct ExceptionRecord {
+       uint32 ExceptionCode;
+       uint32 ExceptionFlags;
+       ExceptionRecord *ExceptionRecord;
+       void *ExceptionAddress;
+       uint32 NumberParameters;
+       uint32 ExceptionInformation[15];
+};
+
+typedef struct FloatingSaveArea FloatingSaveArea;
+struct FloatingSaveArea {
+       uint32 ControlWord;
+       uint32 StatusWord;
+       uint32 TagWord;
+       uint32 ErrorOffset;
+       uint32 ErrorSelector;
+       uint32 DataOffset;
+       uint32 DataSelector;
+       uint8 RegisterArea[80];
+       uint32 Cr0NpxState;
+};
+
+typedef struct Context Context;
+struct Context {
+       uint32 ContextFlags;
+       uint32 Dr0;
+       uint32 Dr1;
+       uint32 Dr2;
+       uint32 Dr3;
+       uint32 Dr6;
+       uint32 Dr7;
+       FloatingSaveArea FloatSave;
+       uint32 SegGs;
+       uint32 SegFs;
+       uint32 SegEs;
+       uint32 SegDs;
+       uint32 Edi;
+       uint32 Esi;
+       uint32 Ebx;
+       uint32 Edx;
+       uint32 Ecx;
+       uint32 Eax;
+       uint32 Ebp;
+       uint32 Eip;
+       uint32 SegCs;
+       uint32 EFlags;
+       uint32 Esp;
+       uint32 SegSs;
+       uint8 ExtendedRegisters[512];
+};
 #pragma pack off
index e379830fb8b3bf46803da1f4566323370358645f..4b67a9f42eddf3b959f244363634cd24b94986c9 100644 (file)
@@ -3,4 +3,9 @@
 // license that can be found in the LICENSE file.
 
 TEXT _rt0_386_windows(SB),7,$0
+       // Set up SEH frame for bootstrap m
+       PUSHL   $runtime·sigtramp(SB)
+       PUSHL   0(FS)
+       MOVL    SP, 0(FS)
+
        JMP     _rt0_386(SB)
index 2ae79e5b56bc2c3494de4902e6de772afdac0efc..33602527c8c8c2206b8294f05af6c5b993d68947 100644 (file)
@@ -3,6 +3,26 @@
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+void
+runtime·dumpregs(Context *r)
+{
+       runtime·printf("eax     %x\n", r->Eax);
+       runtime·printf("ebx     %x\n", r->Ebx);
+       runtime·printf("ecx     %x\n", r->Ecx);
+       runtime·printf("edx     %x\n", r->Edx);
+       runtime·printf("edi     %x\n", r->Edi);
+       runtime·printf("esi     %x\n", r->Esi);
+       runtime·printf("ebp     %x\n", r->Ebp);
+       runtime·printf("esp     %x\n", r->Esp);
+       runtime·printf("eip     %x\n", r->Eip);
+       runtime·printf("eflags  %x\n", r->EFlags);
+       runtime·printf("cs      %x\n", r->SegCs);
+       runtime·printf("fs      %x\n", r->SegFs);
+       runtime·printf("gs      %x\n", r->SegGs);
+}
 
 void
 runtime·initsig(int32)
@@ -15,3 +35,61 @@ runtime·signame(int32)
        return runtime·emptystring;
 }
 
+uint32
+runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
+{
+       uintptr *sp;
+       G *gp;
+
+       USED(frame);
+
+       switch(info->ExceptionCode) {
+       case EXCEPTION_BREAKPOINT:
+               r->Eip--;       // because 8l generates 2 bytes for INT3
+               return 1;
+       }
+
+       if((gp = m->curg) != nil && runtime·issigpanic(info->ExceptionCode)) {
+               // 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 = info->ExceptionCode;
+               gp->sigcode0 = info->ExceptionInformation[0];
+               gp->sigcode1 = info->ExceptionInformation[1];
+
+               // Only push runtime·sigpanic if r->eip != 0.
+               // If r->eip == 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(r->Eip != 0) {
+                       sp = (uintptr*)r->Esp;
+                       *--sp = r->Eip;
+                       r->Esp = (uintptr)sp;
+               }
+               r->Eip = (uintptr)runtime·sigpanic;
+               return 0;
+       }
+
+       if(runtime·panicking)  // traceback already printed
+               runtime·exit(2);
+       runtime·panicking = 1;
+
+       runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
+               info->ExceptionInformation[0], info->ExceptionInformation[1]);
+
+       runtime·printf("PC=%x\n", r->Eip);
+       runtime·printf("\n");
+
+       if(runtime·gotraceback()){
+               runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, m->curg);
+               runtime·tracebackothers(m->curg);
+               runtime·dumpregs(r);
+       }
+
+       runtime·breakpoint();
+       runtime·exit(2);
+       return 0;
+}
index 7f99b34de861cac4d81fb2e027e170a74d82d03f..b3abab5cd4d84c41ba716a51c9025a08c410cf78 100644 (file)
@@ -48,12 +48,58 @@ TEXT runtime·stdcall_raw(SB),7,$4
 
        RET 
 
+TEXT runtime·sigtramp(SB),7,$0
+       PUSHL   BP                                      // cdecl
+       PUSHL   0(FS)
+       CALL    runtime·sigtramp1(SB)
+       POPL    0(FS)
+       POPL    BP
+       RET
+
+TEXT runtime·sigtramp1(SB),0,$16-28
+       // unwinding?
+       MOVL    info+12(FP), BX
+       MOVL    4(BX), CX                       // exception flags
+       ANDL    $6, CX
+       MOVL    $1, AX
+       JNZ             sigdone
+
+       // place ourselves at the top of the SEH chain to
+       // ensure SEH frames lie within thread stack bounds
+       MOVL    frame+16(FP), CX        // our SEH frame
+       MOVL    CX, 0(FS)
+
+       // copy arguments for call to sighandler
+       MOVL    BX, 0(SP)
+       MOVL    CX, 4(SP)
+       MOVL    context+20(FP), BX
+       MOVL    BX, 8(SP)
+       MOVL    dispatcher+24(FP), BX
+       MOVL    BX, 12(SP)
+
+       CALL    runtime·sighandler(SB)
+       TESTL   AX, AX
+       JZ              sigdone
+
+       // call windows default handler early
+       MOVL    4(SP), BX                       // our SEH frame
+       MOVL    0(BX), BX                       // SEH frame of default handler
+       MOVL    4(BX), AX                       // handler function pointer
+       MOVL    BX, 4(SP)                       // set establisher frame
+       CALL    AX
+
+sigdone:
+       RET
+
 // void tstart(M *newm);
 TEXT runtime·tstart(SB),7,$0
        MOVL    newm+4(SP), CX          // m
        MOVL    m_g0(CX), DX            // g
 
-       MOVL    SP, DI                  // remember stack
+       // Set up SEH frame
+       PUSHL   $runtime·sigtramp(SB)
+       PUSHL   0(FS)
+       MOVL    SP, 0(FS)
 
        // Layout new m scheduler stack on os stack.
        MOVL    SP, AX
@@ -74,14 +120,14 @@ TEXT runtime·tstart(SB),7,$0
        // Someday the convention will be D is always cleared.
        CLD
 
-       PUSHL   DI                      // original stack
-
        CALL    runtime·stackcheck(SB)         // clobbers AX,CX
 
        CALL    runtime·mstart(SB)
 
-       POPL    DI                      // original stack
-       MOVL    DI, SP
+       // Pop SEH frame
+       MOVL    0(FS), SP
+       POPL    0(FS)
+       POPL    CX
 
        RET
 
index db5f1400ef25afa80f832f94a85388a3e79e2737..5aac03c81677d8508b022da8130294cdda17d75e 100644 (file)
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+
 enum {
        $PROT_NONE = 0,
        $PROT_READ = 1,
@@ -10,4 +14,18 @@ enum {
 
        $MAP_ANON = 1,
        $MAP_PRIVATE = 2,
+
+       $EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
+       $EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
+       $EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
+       $EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO,
+       $EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT,
+       $EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW,
+       $EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW,
+       $EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO,
+       $EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW,
 };
+
+typedef EXCEPTION_RECORD $ExceptionRecord;
+typedef FLOATING_SAVE_AREA $FloatingSaveArea;
+typedef CONTEXT $Context;
index ba89887ea99955c370731cd93f1c506af0251e17..c42bf9fef764fcd994100159d6e8fd8d7c18666a 100644 (file)
@@ -53,6 +53,7 @@ runtime·SysFree(void *v, uintptr n)
 {
        uintptr r;
 
+       USED(n);
        r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, 0, MEM_RELEASE);
        if(r == 0)
                abort("VirtualFree");
index 77d0d32a0c8ffa7f8aee6d9fbed3ea1b250484fc..23f6863ae607337765e54a7016620a7bfcd7b845 100644 (file)
@@ -34,3 +34,5 @@ struct StdcallParams
 };
 
 void runtime·syscall(StdcallParams *p);
+uint32 runtime·issigpanic(uint32);
+void runtime·sigpanic(void);
index 9b518133735da17d232cd8956c4559cfd250dba7..5ab5128eb759d37f73b3add2ffbca317d7b0d9c4 100644 (file)
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "defs.h"
 #include "os.h"
 
 #pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
@@ -215,3 +216,43 @@ runtime·syscall(StdcallParams *p)
        p->err = (uintptr)runtime·stdcall_raw(runtime·GetLastError, 0, &a);
        runtime·exitsyscall();
 }
+
+uint32
+runtime·issigpanic(uint32 code)
+{
+       switch(code) {
+       case EXCEPTION_ACCESS_VIOLATION:
+       case EXCEPTION_INT_DIVIDE_BY_ZERO:
+       case EXCEPTION_INT_OVERFLOW:
+       case EXCEPTION_FLT_DENORMAL_OPERAND:
+       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+       case EXCEPTION_FLT_INEXACT_RESULT:
+       case EXCEPTION_FLT_OVERFLOW:
+       case EXCEPTION_FLT_UNDERFLOW:
+               return 1;
+       }
+       return 0;
+}
+
+void
+runtime·sigpanic(void)
+{
+       switch(g->sig) {
+       case EXCEPTION_ACCESS_VIOLATION:
+               if(g->sigcode1 < 0x1000)
+                       runtime·panicstring("invalid memory address or nil pointer dereference");
+               runtime·printf("unexpected fault address %p\n", g->sigcode1);
+               runtime·throw("fault");
+       case EXCEPTION_INT_DIVIDE_BY_ZERO:
+               runtime·panicstring("integer divide by zero");
+       case EXCEPTION_INT_OVERFLOW:
+               runtime·panicstring("integer overflow");
+       case EXCEPTION_FLT_DENORMAL_OPERAND:
+       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+       case EXCEPTION_FLT_INEXACT_RESULT:
+       case EXCEPTION_FLT_OVERFLOW:
+       case EXCEPTION_FLT_UNDERFLOW:
+               runtime·panicstring("floating point error");
+       }
+       runtime·throw("fault");
+}