mirror of https://github.com/golang/go.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
This commit is contained in:
parent
8c9e838f7b
commit
a837347dd9
|
|
@ -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
|
||||
// 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)
|
||||
|
||||
// copy arguments for call to sighandler.
|
||||
MOVQ 0(CX), BX // ExceptionRecord*
|
||||
MOVQ 8(CX), CX // Context*
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue