From: Alex Brainman Date: Wed, 26 Mar 2014 00:13:50 +0000 (+1100) Subject: runtime: use VEH for windows/amd64 exception handling X-Git-Tag: go1.3beta1~278 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=a837347dd95d045e05bf0e6df9bf1c9b157c7c53;p=gostls13.git runtime: use VEH for windows/amd64 exception handling Fixes windows/amd64 build. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/79470046 --- diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index e4848643ee..4419471240 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -529,49 +529,6 @@ 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; - LSym *sym; - - USED(text); - if(thechar != '6') - return; - - // write unwind info - sym = linklookup(ctxt, "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) { @@ -609,7 +566,6 @@ asmbpe(void) addexports(); addsymtable(); addpersrc(); - addexcept(t); fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c index af03247418..523efedf0a 100644 --- a/src/pkg/runtime/os_windows.c +++ b/src/pkg/runtime/os_windows.c @@ -248,15 +248,12 @@ runtime·minit(void) (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle, (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); runtime·atomicstorep(&m->thread, thandle); - - runtime·install_exception_handler(); } // Called from dropm to undo the effect of an minit. void runtime·unminit(void) { - runtime·remove_exception_handler(); } #pragma textflag NOSPLIT diff --git a/src/pkg/runtime/os_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c index 27094ff497..1b23673af0 100644 --- a/src/pkg/runtime/os_windows_amd64.c +++ b/src/pkg/runtime/os_windows_amd64.c @@ -32,6 +32,11 @@ runtime·dumpregs(Context *r) runtime·printf("gs %X\n", (uint64)r->SegGs); } +#define DBG_PRINTEXCEPTION_C 0x40010006 + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (-1) +// or should be made available to other handlers in the chain (0). uint32 runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { @@ -39,8 +44,25 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) uintptr *sp; switch(info->ExceptionCode) { + case DBG_PRINTEXCEPTION_C: + // This exception is intended to be caught by debuggers. + // There is a not-very-informational message like + // "Invalid parameter passed to C runtime function" + // sitting at info->ExceptionInformation[0] (a wchar_t*), + // with length info->ExceptionInformation[1]. + // The default behavior is to ignore this exception, + // but somehow returning 0 here (meaning keep going) + // makes the program crash instead. Maybe Windows has no + // other handler registered? In any event, ignore it. + return -1; + case EXCEPTION_BREAKPOINT: - return 1; + // It is unclear whether this is needed, unclear whether it + // would work, and unclear how to test it. Leave out for now. + // This only handles breakpoint instructions written in the + // assembly sources, not breakpoints set by a debugger, and + // there are very few of the former. + break; } if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { @@ -65,15 +87,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) r->Rsp = (uintptr)sp; } r->Rip = (uintptr)runtime·sigpanic; - return 0; + return -1; } 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("Exception %x %p %p %p\n", info->ExceptionCode, + info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip); + runtime·printf("PC=%X\n", r->Rip); if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { @@ -92,7 +115,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return 0; + return -1; // not reached } void diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s index 26dc30094f..3721fb4c58 100644 --- a/src/pkg/runtime/sys_windows_386.s +++ b/src/pkg/runtime/sys_windows_386.s @@ -313,14 +313,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0 MOVL CX, 0x14(FS) RET -// void install_exception_handler() -TEXT runtime·install_exception_handler(SB),NOSPLIT,$0 - RET - -// void remove_exception_handler() -TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0 - RET - // Sleep duration is in 100ns units. TEXT runtime·usleep1(SB),NOSPLIT,$0 MOVL duration+0(FP), BX diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s index 288cd7748f..94845903ed 100644 --- a/src/pkg/runtime/sys_windows_amd64.s +++ b/src/pkg/runtime/sys_windows_amd64.s @@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 MOVL AX, 0x68(CX) RET -TEXT runtime·sigtramp(SB),NOSPLIT,$0 - // CX: exception record - // R8: context +// Called by Windows as a Vectored Exception Handler (VEH). +// First argument is pointer to struct containing +// exception record and context pointers. +// Return 0 for 'not handled', -1 for handled. +TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 + // CX: PEXCEPTION_POINTERS ExceptionInfo - // unwinding? - TESTL $6, 4(CX) // exception flags - MOVL $1, AX - JNZ sigdone - - // copy arguments for call to sighandler. - - // Stack adjustment is here to hide from 6l, - // which doesn't understand that sigtramp - // runs on essentially unlimited stack. - SUBQ $56, SP - MOVQ CX, 0(SP) - MOVQ R8, 8(SP) - - get_tls(CX) - - // check that m exists - MOVQ m(CX), AX + // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved + // as required by windows callback convention. + PUSHFQ + SUBQ $88, SP + MOVQ DI, 80(SP) + MOVQ SI, 72(SP) + MOVQ BP, 64(SP) + MOVQ BX, 56(SP) + MOVQ R12, 48(SP) + MOVQ R13, 40(SP) + MOVQ R14, 32(SP) + MOVQ R15, 24(SP) + + MOVQ 0(CX), BX // ExceptionRecord* + MOVQ 8(CX), CX // Context* + + // fetch g + get_tls(DX) + MOVQ m(DX), AX CMPQ AX, $0 JNE 2(PC) CALL runtime·badsignal2(SB) - - MOVQ g(CX), CX - MOVQ CX, 16(SP) - - MOVQ BX, 24(SP) - MOVQ BP, 32(SP) - MOVQ SI, 40(SP) - MOVQ DI, 48(SP) - + MOVQ g(DX), DX + // call sighandler(ExceptionRecord*, Context*, G*) + MOVQ BX, 0(SP) + MOVQ CX, 8(SP) + MOVQ DX, 16(SP) CALL runtime·sighandler(SB) + // AX is set to report result back to Windows - MOVQ 24(SP), BX - MOVQ 32(SP), BP - MOVQ 40(SP), SI - MOVQ 48(SP), DI - ADDQ $56, SP + // restore registers as required for windows callback + MOVQ 24(SP), R15 + MOVQ 32(SP), R14 + MOVQ 40(SP), R13 + MOVQ 48(SP), R12 + MOVQ 56(SP), BX + MOVQ 64(SP), BP + MOVQ 72(SP), SI + MOVQ 80(SP), DI + ADDQ $88, SP + POPFQ -sigdone: RET TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 @@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 POPQ -8(CX)(DX*1) // restore bytes just after the args RET -TEXT runtime·setstacklimits(SB),NOSPLIT,$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),NOSPLIT,$0 // CX contains first arg newm @@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0 MOVQ DI, 0x28(GS) RET -// void install_exception_handler() -TEXT runtime·install_exception_handler(SB),NOSPLIT,$0 - CALL runtime·setstacklimits(SB) - RET - -TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0 - RET - // Sleep duration is in 100ns units. TEXT runtime·usleep1(SB),NOSPLIT,$0 MOVL duration+0(FP), BX