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)
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);
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
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