Commit a837347d authored by Alex Brainman's avatar Alex Brainman

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
parent 8c9e838f
...@@ -529,49 +529,6 @@ addpersrc(void) ...@@ -529,49 +529,6 @@ addpersrc(void)
dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; 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 void
asmbpe(void) asmbpe(void)
{ {
...@@ -609,7 +566,6 @@ asmbpe(void) ...@@ -609,7 +566,6 @@ asmbpe(void)
addexports(); addexports();
addsymtable(); addsymtable();
addpersrc(); addpersrc();
addexcept(t);
fh.NumberOfSections = nsect; fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0); fh.TimeDateStamp = time(0);
......
...@@ -248,15 +248,12 @@ runtime·minit(void) ...@@ -248,15 +248,12 @@ runtime·minit(void)
(uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle, (uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle,
(uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
runtime·atomicstorep(&m->thread, thandle); runtime·atomicstorep(&m->thread, thandle);
runtime·install_exception_handler();
} }
// Called from dropm to undo the effect of an minit. // Called from dropm to undo the effect of an minit.
void void
runtime·unminit(void) runtime·unminit(void)
{ {
runtime·remove_exception_handler();
} }
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
......
...@@ -32,6 +32,11 @@ runtime·dumpregs(Context *r) ...@@ -32,6 +32,11 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %X\n", (uint64)r->SegGs); 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 uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{ {
...@@ -39,8 +44,25 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) ...@@ -39,8 +44,25 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
uintptr *sp; uintptr *sp;
switch(info->ExceptionCode) { 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: 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)) { if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
...@@ -65,15 +87,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) ...@@ -65,15 +87,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
r->Rsp = (uintptr)sp; r->Rsp = (uintptr)sp;
} }
r->Rip = (uintptr)runtime·sigpanic; r->Rip = (uintptr)runtime·sigpanic;
return 0; return -1;
} }
if(runtime·panicking) // traceback already printed if(runtime·panicking) // traceback already printed
runtime·exit(2); runtime·exit(2);
runtime·panicking = 1; runtime·panicking = 1;
runtime·printf("Exception %x %p %p\n", info->ExceptionCode, runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
info->ExceptionInformation[0], info->ExceptionInformation[1]); info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
runtime·printf("PC=%X\n", r->Rip); runtime·printf("PC=%X\n", r->Rip);
if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
...@@ -92,7 +115,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) ...@@ -92,7 +115,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
runtime·crash(); runtime·crash();
runtime·exit(2); runtime·exit(2);
return 0; return -1; // not reached
} }
void void
......
...@@ -313,14 +313,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0 ...@@ -313,14 +313,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
MOVL CX, 0x14(FS) MOVL CX, 0x14(FS)
RET 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. // Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0 TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX MOVL duration+0(FP), BX
......
...@@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 ...@@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
MOVL AX, 0x68(CX) MOVL AX, 0x68(CX)
RET RET
TEXT runtime·sigtramp(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH).
// CX: exception record // First argument is pointer to struct containing
// R8: context // 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? // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
TESTL $6, 4(CX) // exception flags // as required by windows callback convention.
MOVL $1, AX PUSHFQ
JNZ sigdone SUBQ $88, SP
MOVQ DI, 80(SP)
// copy arguments for call to sighandler. MOVQ SI, 72(SP)
MOVQ BP, 64(SP)
// Stack adjustment is here to hide from 6l, MOVQ BX, 56(SP)
// which doesn't understand that sigtramp MOVQ R12, 48(SP)
// runs on essentially unlimited stack. MOVQ R13, 40(SP)
SUBQ $56, SP MOVQ R14, 32(SP)
MOVQ CX, 0(SP) MOVQ R15, 24(SP)
MOVQ R8, 8(SP)
MOVQ 0(CX), BX // ExceptionRecord*
get_tls(CX) MOVQ 8(CX), CX // Context*
// check that m exists // fetch g
MOVQ m(CX), AX get_tls(DX)
MOVQ m(DX), AX
CMPQ AX, $0 CMPQ AX, $0
JNE 2(PC) JNE 2(PC)
CALL runtime·badsignal2(SB) CALL runtime·badsignal2(SB)
MOVQ g(DX), DX
MOVQ g(CX), CX // call sighandler(ExceptionRecord*, Context*, G*)
MOVQ CX, 16(SP) MOVQ BX, 0(SP)
MOVQ CX, 8(SP)
MOVQ BX, 24(SP) MOVQ DX, 16(SP)
MOVQ BP, 32(SP)
MOVQ SI, 40(SP)
MOVQ DI, 48(SP)
CALL runtime·sighandler(SB) CALL runtime·sighandler(SB)
// AX is set to report result back to Windows
MOVQ 24(SP), BX // restore registers as required for windows callback
MOVQ 32(SP), BP MOVQ 24(SP), R15
MOVQ 40(SP), SI MOVQ 32(SP), R14
MOVQ 48(SP), DI MOVQ 40(SP), R13
ADDQ $56, SP 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 RET
TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
...@@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 ...@@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
POPQ -8(CX)(DX*1) // restore bytes just after the args POPQ -8(CX)(DX*1) // restore bytes just after the args
RET 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); // uint32 tstart_stdcall(M *newm);
TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
// CX contains first arg newm // CX contains first arg newm
...@@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0 ...@@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0
MOVQ DI, 0x28(GS) MOVQ DI, 0x28(GS)
RET 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. // Sleep duration is in 100ns units.
TEXT runtime·usleep1(SB),NOSPLIT,$0 TEXT runtime·usleep1(SB),NOSPLIT,$0
MOVL duration+0(FP), BX MOVL duration+0(FP), BX
......
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