mirror of
https://github.com/golang/go
synced 2024-11-21 21:04:41 -07:00
runtime: implement exception handling on windows/amd64
Fixes #2194. R=rsc, alex.brainman, vcc.163, jp CC=golang-dev https://golang.org/cl/4977044
This commit is contained in:
parent
2b6d3b498c
commit
9b011500c0
@ -525,6 +525,48 @@ 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;
|
||||||
|
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
|
void
|
||||||
asmbpe(void)
|
asmbpe(void)
|
||||||
{
|
{
|
||||||
@ -562,7 +604,8 @@ asmbpe(void)
|
|||||||
addexports();
|
addexports();
|
||||||
addsymtable();
|
addsymtable();
|
||||||
addpersrc();
|
addpersrc();
|
||||||
|
addexcept(t);
|
||||||
|
|
||||||
fh.NumberOfSections = nsect;
|
fh.NumberOfSections = nsect;
|
||||||
fh.TimeDateStamp = time(0);
|
fh.TimeDateStamp = time(0);
|
||||||
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
|
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
|
||||||
@ -599,8 +642,16 @@ asmbpe(void)
|
|||||||
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||||
else
|
else
|
||||||
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
|
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(SizeOfHeapReserve, 0x00100000);
|
||||||
set(SizeOfHeapCommit, 0x00001000);
|
set(SizeOfHeapCommit, 0x00001000);
|
||||||
set(NumberOfRvaAndSizes, 16);
|
set(NumberOfRvaAndSizes, 16);
|
||||||
|
@ -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.
|
// MACHINE GENERATED - DO NOT EDIT.
|
||||||
|
|
||||||
@ -37,4 +37,60 @@ struct ExceptionRecord {
|
|||||||
byte pad_godefs_0[4];
|
byte pad_godefs_0[4];
|
||||||
uint64 ExceptionInformation[15];
|
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
|
#pragma pack off
|
||||||
|
@ -6,10 +6,97 @@
|
|||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
extern void *runtime·sigtramp;
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·initsig(int32 queue)
|
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)
|
||||||
{
|
{
|
||||||
runtime·siginit();
|
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
|
void
|
||||||
|
@ -70,6 +70,36 @@ TEXT runtime·setlasterror(SB),7,$0
|
|||||||
MOVL AX, 0x68(CX)
|
MOVL AX, 0x68(CX)
|
||||||
RET
|
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.
|
// Windows runs the ctrl handler in a new thread.
|
||||||
TEXT runtime·ctrlhandler(SB),7,$0
|
TEXT runtime·ctrlhandler(SB),7,$0
|
||||||
PUSHQ BP
|
PUSHQ BP
|
||||||
@ -182,6 +212,13 @@ TEXT runtime·callbackasm(SB),7,$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),7,$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),7,$0
|
TEXT runtime·tstart_stdcall(SB),7,$0
|
||||||
// CX contains first arg newm
|
// 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.
|
// Someday the convention will be D is always cleared.
|
||||||
CLD
|
CLD
|
||||||
|
|
||||||
|
CALL runtime·setstacklimits(SB)
|
||||||
CALL runtime·stackcheck(SB) // clobbers AX,CX
|
CALL runtime·stackcheck(SB) // clobbers AX,CX
|
||||||
CALL runtime·mstart(SB)
|
CALL runtime·mstart(SB)
|
||||||
|
|
||||||
@ -215,5 +253,6 @@ TEXT runtime·notok(SB),7,$0
|
|||||||
|
|
||||||
// set tls base to DI
|
// set tls base to DI
|
||||||
TEXT runtime·settls(SB),7,$0
|
TEXT runtime·settls(SB),7,$0
|
||||||
|
CALL runtime·setstacklimits(SB)
|
||||||
MOVQ DI, 0x58(GS)
|
MOVQ DI, 0x58(GS)
|
||||||
RET
|
RET
|
||||||
|
@ -33,5 +33,10 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef EXCEPTION_RECORD $ExceptionRecord;
|
typedef EXCEPTION_RECORD $ExceptionRecord;
|
||||||
|
#ifdef _X86_
|
||||||
typedef FLOATING_SAVE_AREA $FloatingSaveArea;
|
typedef FLOATING_SAVE_AREA $FloatingSaveArea;
|
||||||
|
#endif
|
||||||
|
#ifdef _AMD64_
|
||||||
|
typedef M128A $M128a;
|
||||||
|
#endif
|
||||||
typedef CONTEXT $Context;
|
typedef CONTEXT $Context;
|
||||||
|
Loading…
Reference in New Issue
Block a user