mirror of
https://github.com/golang/go
synced 2024-11-12 08:10:21 -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;
|
||||
}
|
||||
|
||||
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
|
||||
asmbpe(void)
|
||||
{
|
||||
@ -562,7 +604,8 @@ asmbpe(void)
|
||||
addexports();
|
||||
addsymtable();
|
||||
addpersrc();
|
||||
|
||||
addexcept(t);
|
||||
|
||||
fh.NumberOfSections = nsect;
|
||||
fh.TimeDateStamp = time(0);
|
||||
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
|
||||
@ -599,8 +642,16 @@ asmbpe(void)
|
||||
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
||||
else
|
||||
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(SizeOfHeapCommit, 0x00001000);
|
||||
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.
|
||||
|
||||
@ -37,4 +37,60 @@ struct ExceptionRecord {
|
||||
byte pad_godefs_0[4];
|
||||
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
|
||||
|
@ -6,10 +6,97 @@
|
||||
#include "defs.h"
|
||||
#include "os.h"
|
||||
|
||||
extern void *runtime·sigtramp;
|
||||
|
||||
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();
|
||||
// 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
|
||||
|
@ -70,6 +70,36 @@ TEXT runtime·setlasterror(SB),7,$0
|
||||
MOVL AX, 0x68(CX)
|
||||
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.
|
||||
TEXT runtime·ctrlhandler(SB),7,$0
|
||||
PUSHQ BP
|
||||
@ -182,6 +212,13 @@ TEXT runtime·callbackasm(SB),7,$0
|
||||
POPQ -8(CX)(DX*1) // restore bytes just after the args
|
||||
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);
|
||||
TEXT runtime·tstart_stdcall(SB),7,$0
|
||||
// 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.
|
||||
CLD
|
||||
|
||||
CALL runtime·setstacklimits(SB)
|
||||
CALL runtime·stackcheck(SB) // clobbers AX,CX
|
||||
CALL runtime·mstart(SB)
|
||||
|
||||
@ -215,5 +253,6 @@ TEXT runtime·notok(SB),7,$0
|
||||
|
||||
// set tls base to DI
|
||||
TEXT runtime·settls(SB),7,$0
|
||||
CALL runtime·setstacklimits(SB)
|
||||
MOVQ DI, 0x58(GS)
|
||||
RET
|
||||
|
@ -33,5 +33,10 @@ enum {
|
||||
};
|
||||
|
||||
typedef EXCEPTION_RECORD $ExceptionRecord;
|
||||
#ifdef _X86_
|
||||
typedef FLOATING_SAVE_AREA $FloatingSaveArea;
|
||||
#endif
|
||||
#ifdef _AMD64_
|
||||
typedef M128A $M128a;
|
||||
#endif
|
||||
typedef CONTEXT $Context;
|
||||
|
Loading…
Reference in New Issue
Block a user