]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: implement exception handling on windows/amd64
authorHector Chu <hectorchu@gmail.com>
Sat, 3 Sep 2011 08:27:16 +0000 (18:27 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Sat, 3 Sep 2011 08:27:16 +0000 (18:27 +1000)
Fixes #2194.

R=rsc, alex.brainman, vcc.163, jp
CC=golang-dev
https://golang.org/cl/4977044

src/cmd/ld/pe.c
src/pkg/runtime/windows/amd64/defs.h
src/pkg/runtime/windows/amd64/signal.c
src/pkg/runtime/windows/amd64/sys.s
src/pkg/runtime/windows/defs.c

index 6379b1ad3a9d373164c4a1468b529cc5522d1e5d..df6c95976f2e6f8e58d898e65a146b9c894dd291 100644 (file)
@@ -525,6 +525,48 @@ addpersrc(void)
        dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
 }
 
+static void
+addexcept(IMAGE_SECTION_HEADER *text)
+{
+       IMAGE_SECTION_HEADER *pdata, *xdata;
+       vlong startoff;
+       uvlong n;
+       Sym *sym;
+
+       if(thechar != '6')
+               return;
+
+       // write unwind info
+       sym = lookup("runtime.sigtramp", 0);
+       startoff = cpos();
+       lputl(9);       // version=1, flags=UNW_FLAG_EHANDLER, rest 0
+       lputl(sym->value - PEBASE);
+       lputl(0);
+
+       n = cpos() - startoff;
+       xdata = addpesection(".xdata", n, n);
+       xdata->Characteristics = IMAGE_SCN_MEM_READ|
+               IMAGE_SCN_CNT_INITIALIZED_DATA;
+       chksectoff(xdata, startoff);
+       strnput("", xdata->SizeOfRawData - n);
+
+       // write a function table entry for the whole text segment
+       startoff = cpos();
+       lputl(text->VirtualAddress);
+       lputl(text->VirtualAddress + text->VirtualSize);
+       lputl(xdata->VirtualAddress);
+
+       n = cpos() - startoff;
+       pdata = addpesection(".pdata", n, n);
+       pdata->Characteristics = IMAGE_SCN_MEM_READ|
+               IMAGE_SCN_CNT_INITIALIZED_DATA;
+       chksectoff(pdata, startoff);
+       strnput("", pdata->SizeOfRawData - n);
+
+       dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
+       dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
+}
+
 void
 asmbpe(void)
 {
@@ -562,7 +604,8 @@ asmbpe(void)
        addexports();
        addsymtable();
        addpersrc();
-       
+       addexcept(t);
+
        fh.NumberOfSections = nsect;
        fh.TimeDateStamp = time(0);
        fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
@@ -599,8 +642,16 @@ asmbpe(void)
                set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
        else
                set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
-       set(SizeOfStackReserve, 0x0040000);
-       set(SizeOfStackCommit, 0x00001000);
+
+       // Disable stack growth as we don't want Windows to
+       // fiddle with the thread stack limits, which we set
+       // ourselves to circumvent the stack checks in the
+       // Windows exception dispatcher.
+       // Commit size must be strictly less than reserve
+       // size otherwise reserve will be rounded up to a
+       // larger size, as verified with VMMap.
+       set(SizeOfStackReserve, 0x00010000);
+       set(SizeOfStackCommit, 0x0000ffff);
        set(SizeOfHeapReserve, 0x00100000);
        set(SizeOfHeapCommit, 0x00001000);
        set(NumberOfRvaAndSizes, 16);
index 830c6a855914503b0473f6ef35c80fdb1ebc9c98..30c66df51c91b063ed80d9f15717c2ba8d3cbb7b 100644 (file)
@@ -1,4 +1,4 @@
-// g:\opensource\go\bin\godefs.exe -f -m64 defs.c
+// c:\go\bin\godefs.exe -f -m64 defs.c
 
 // MACHINE GENERATED - DO NOT EDIT.
 
@@ -37,4 +37,60 @@ struct ExceptionRecord {
        byte pad_godefs_0[4];
        uint64 ExceptionInformation[15];
 };
+
+typedef struct M128a M128a;
+struct M128a {
+       uint64 Low;
+       int64 High;
+};
+
+typedef struct Context Context;
+struct Context {
+       uint64 P1Home;
+       uint64 P2Home;
+       uint64 P3Home;
+       uint64 P4Home;
+       uint64 P5Home;
+       uint64 P6Home;
+       uint32 ContextFlags;
+       uint32 MxCsr;
+       uint16 SegCs;
+       uint16 SegDs;
+       uint16 SegEs;
+       uint16 SegFs;
+       uint16 SegGs;
+       uint16 SegSs;
+       uint32 EFlags;
+       uint64 Dr0;
+       uint64 Dr1;
+       uint64 Dr2;
+       uint64 Dr3;
+       uint64 Dr6;
+       uint64 Dr7;
+       uint64 Rax;
+       uint64 Rcx;
+       uint64 Rdx;
+       uint64 Rbx;
+       uint64 Rsp;
+       uint64 Rbp;
+       uint64 Rsi;
+       uint64 Rdi;
+       uint64 R8;
+       uint64 R9;
+       uint64 R10;
+       uint64 R11;
+       uint64 R12;
+       uint64 R13;
+       uint64 R14;
+       uint64 R15;
+       uint64 Rip;
+       byte Pad_godefs_0[512];
+       M128a VectorRegister[26];
+       uint64 VectorControl;
+       uint64 DebugControl;
+       uint64 LastBranchToRip;
+       uint64 LastBranchFromRip;
+       uint64 LastExceptionToRip;
+       uint64 LastExceptionFromRip;
+};
 #pragma pack off
index 46951152f5bede306a4a19401768ad0931d2e005..1e621b76077535dbf066781b338a0208cbd39f2d 100644 (file)
@@ -6,10 +6,97 @@
 #include "defs.h"
 #include "os.h"
 
+extern void *runtime·sigtramp;
+
+void
+runtime·dumpregs(Context *r)
+{
+       runtime·printf("rax     %X\n", r->Rax);
+       runtime·printf("rbx     %X\n", r->Rbx);
+       runtime·printf("rcx     %X\n", r->Rcx);
+       runtime·printf("rdx     %X\n", r->Rdx);
+       runtime·printf("rdi     %X\n", r->Rdi);
+       runtime·printf("rsi     %X\n", r->Rsi);
+       runtime·printf("rbp     %X\n", r->Rbp);
+       runtime·printf("rsp     %X\n", r->Rsp);
+       runtime·printf("r8      %X\n", r->R8 );
+       runtime·printf("r9      %X\n", r->R9 );
+       runtime·printf("r10     %X\n", r->R10);
+       runtime·printf("r11     %X\n", r->R11);
+       runtime·printf("r12     %X\n", r->R12);
+       runtime·printf("r13     %X\n", r->R13);
+       runtime·printf("r14     %X\n", r->R14);
+       runtime·printf("r15     %X\n", r->R15);
+       runtime·printf("rip     %X\n", r->Rip);
+       runtime·printf("rflags  %X\n", r->EFlags);
+       runtime·printf("cs      %X\n", (uint64)r->SegCs);
+       runtime·printf("fs      %X\n", (uint64)r->SegFs);
+       runtime·printf("gs      %X\n", (uint64)r->SegGs);
+}
+
 void
-runtime·initsig(int32 queue)
+runtime·initsig(int32)
 {
        runtime·siginit();
+       // following line keeps sigtramp alive at link stage
+       // if there's a better way please write it here
+       void *p = runtime·sigtramp;
+       USED(p);
+}
+
+uint32
+runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
+{
+       uintptr *sp;
+
+       switch(info->ExceptionCode) {
+       case EXCEPTION_BREAKPOINT:
+               return 1;
+       }
+
+       if(gp != 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];
+               gp->sigpc = r->Rip;
+
+               // Only push runtime·sigpanic if r->rip != 0.
+               // If r->rip == 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->Rip != 0) {
+                       sp = (uintptr*)r->Rsp;
+                       *--sp = r->Rip;
+                       r->Rsp = (uintptr)sp;
+               }
+               r->Rip = (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->Rip);
+       runtime·printf("\n");
+
+       if(runtime·gotraceback()){
+               runtime·traceback((void*)r->Rip, (void*)r->Rsp, 0, gp);
+               runtime·tracebackothers(gp);
+               runtime·dumpregs(r);
+       }
+
+       runtime·exit(2);
+       return 0;
 }
 
 void
index eb197d72ef27058345716f8db308a0e256f247de..9b4a17eda71178e8bb8b892ae7635a91f78469ff 100644 (file)
@@ -70,6 +70,36 @@ TEXT runtime·setlasterror(SB),7,$0
        MOVL    AX, 0x68(CX)
        RET
 
+TEXT runtime·sigtramp(SB),7,$56
+       // CX: exception record
+       // R8: context
+
+       // unwinding?
+       TESTL   $6, 4(CX)               // exception flags
+       MOVL    $1, AX
+       JNZ     sigdone
+
+       // copy arguments for call to sighandler
+       MOVQ    CX, 0(SP)
+       MOVQ    R8, 8(SP)
+       get_tls(CX)
+       MOVQ    g(CX), CX
+       MOVQ    CX, 16(SP)
+
+       MOVQ    BX, 24(SP)
+       MOVQ    BP, 32(SP)
+       MOVQ    SI, 40(SP)
+       MOVQ    DI, 48(SP)
+
+       CALL    runtime·sighandler(SB)
+
+       MOVQ    24(SP), BX
+       MOVQ    32(SP), BP
+       MOVQ    40(SP), SI
+       MOVQ    48(SP), DI
+sigdone:
+       RET
+
 // Windows runs the ctrl handler in a new thread.
 TEXT runtime·ctrlhandler(SB),7,$0
        PUSHQ   BP
@@ -182,6 +212,13 @@ TEXT runtime·callbackasm(SB),7,$0
        POPQ    -8(CX)(DX*1)      // restore bytes just after the args
        RET
 
+TEXT runtime·setstacklimits(SB),7,$0
+       MOVQ    0x30(GS), CX
+       MOVQ    $0, 0x10(CX)
+       MOVQ    $0xffffffffffff, AX
+       MOVQ    AX, 0x08(CX)
+       RET
+
 // uint32 tstart_stdcall(M *newm);
 TEXT runtime·tstart_stdcall(SB),7,$0
        // CX contains first arg newm
@@ -202,6 +239,7 @@ TEXT runtime·tstart_stdcall(SB),7,$0
        // Someday the convention will be D is always cleared.
        CLD
 
+       CALL    runtime·setstacklimits(SB)
        CALL    runtime·stackcheck(SB) // clobbers AX,CX
        CALL    runtime·mstart(SB)
 
@@ -215,5 +253,6 @@ TEXT runtime·notok(SB),7,$0
 
 // set tls base to DI
 TEXT runtime·settls(SB),7,$0
+       CALL    runtime·setstacklimits(SB)
        MOVQ    DI, 0x58(GS)
        RET
index 3b2824940f9401bfbe762b379eaac36fca82506d..b076afd5dde3c9bdbf16c2aa5eff329cdfd2b2eb 100644 (file)
@@ -33,5 +33,10 @@ enum {
 };
 
 typedef EXCEPTION_RECORD $ExceptionRecord;
+#ifdef _X86_
 typedef FLOATING_SAVE_AREA $FloatingSaveArea;
+#endif
+#ifdef _AMD64_
+typedef M128A $M128a;
+#endif
 typedef CONTEXT $Context;