mirror of
https://github.com/dlang/phobos.git
synced 2025-05-01 23:50:31 +03:00
285 lines
6.9 KiB
D
285 lines
6.9 KiB
D
//
|
|
// Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com
|
|
// All Rights Reserved
|
|
// Written by Walter Bright
|
|
|
|
// Exception handling support for linux
|
|
|
|
//debug=1;
|
|
|
|
import std.c.linux.linuxextern;
|
|
|
|
extern (C) int _d_isbaseof(ClassInfo oc, ClassInfo c);
|
|
|
|
alias int (*fp_t)(); // function pointer in ambient memory model
|
|
|
|
struct DHandlerInfo
|
|
{
|
|
uint offset; // offset from function address to start of guarded section
|
|
uint endoffset; // offset of end of guarded section
|
|
int prev_index; // previous table index
|
|
uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
|
|
void *finally_code; // pointer to finally code to execute
|
|
// (!=0 if try-finally)
|
|
}
|
|
|
|
// Address of DHandlerTable, searched for by eh_finddata()
|
|
|
|
struct DHandlerTable
|
|
{
|
|
void *fptr; // pointer to start of function
|
|
uint espoffset; // offset of ESP from EBP
|
|
uint retoffset; // offset from start of function to return code
|
|
uint nhandlers; // dimension of handler_info[]
|
|
DHandlerInfo handler_info[1];
|
|
}
|
|
|
|
struct DCatchBlock
|
|
{
|
|
ClassInfo type; // catch type
|
|
uint bpoffset; // EBP offset of catch var
|
|
void *code; // catch handler code
|
|
}
|
|
|
|
// Create one of these for each try-catch
|
|
struct DCatchInfo
|
|
{
|
|
uint ncatches; // number of catch blocks
|
|
DCatchBlock catch_block[1]; // data for each catch block
|
|
}
|
|
|
|
// One of these is generated for each function with try-catch or try-finally
|
|
|
|
struct FuncTable
|
|
{
|
|
void *fptr; // pointer to start of function
|
|
DHandlerTable *handlertable; // eh data for this function
|
|
uint fsize; // size of function in bytes
|
|
}
|
|
|
|
void terminate()
|
|
{
|
|
asm
|
|
{
|
|
hlt ;
|
|
}
|
|
}
|
|
|
|
/*******************************************
|
|
* Given address that is inside a function,
|
|
* figure out which function it is in.
|
|
* Return DHandlerTable if there is one, NULL if not.
|
|
*/
|
|
|
|
DHandlerTable *__eh_finddata(void *address)
|
|
{
|
|
FuncTable *ft;
|
|
|
|
// debug printf("__eh_finddata(address = x%x)\n", address);
|
|
// debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
|
|
for (ft = cast(FuncTable *)&_deh_beg;
|
|
ft < cast(FuncTable *)&_deh_end;
|
|
ft++)
|
|
{
|
|
// debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
|
|
// ft.fptr, ft.fsize, ft.handlertable);
|
|
|
|
if (ft.fptr <= address &&
|
|
address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
|
|
{
|
|
// debug printf("\tfound handler table\n");
|
|
return ft.handlertable;
|
|
}
|
|
}
|
|
// debug printf("\tnot found\n");
|
|
return null;
|
|
}
|
|
|
|
|
|
/******************************
|
|
* Given EBP, find return address to caller, and caller's EBP.
|
|
* Input:
|
|
* regbp Value of EBP for current function
|
|
* *pretaddr Return address
|
|
* Output:
|
|
* *pretaddr return address to caller
|
|
* Returns:
|
|
* caller's EBP
|
|
*/
|
|
|
|
uint __eh_find_caller(uint regbp, uint *pretaddr)
|
|
{
|
|
uint bp = *cast(uint *)regbp;
|
|
|
|
if (bp) // if not end of call chain
|
|
{
|
|
// Perform sanity checks on new EBP.
|
|
// If it is screwed up, terminate() hopefully before we do more damage.
|
|
if (bp <= regbp)
|
|
// stack should grow to smaller values
|
|
terminate();
|
|
|
|
*pretaddr = *cast(uint *)(regbp + int.sizeof);
|
|
}
|
|
return bp;
|
|
}
|
|
|
|
/***********************************
|
|
* Throw a D object.
|
|
*/
|
|
|
|
extern (Windows) void _d_throw(Object *h)
|
|
{
|
|
uint regebp;
|
|
|
|
debug
|
|
{
|
|
printf("_d_throw(h = %p, &h = %p)\n", h, &h);
|
|
printf("\tvptr = %p\n", *cast(void **)h);
|
|
}
|
|
|
|
asm
|
|
{
|
|
mov regebp,EBP ;
|
|
}
|
|
|
|
//static uint abc;
|
|
//if (++abc == 2) *(char *)0=0;
|
|
|
|
//int count = 0;
|
|
while (1) // for each function on the stack
|
|
{
|
|
DHandlerTable *handler_table;
|
|
FuncTable *pfunc;
|
|
DHandlerInfo *phi;
|
|
uint retaddr;
|
|
uint funcoffset;
|
|
uint spoff;
|
|
uint retoffset;
|
|
int index;
|
|
int dim;
|
|
int ndx;
|
|
int prev_ndx;
|
|
|
|
regebp = __eh_find_caller(regebp,&retaddr);
|
|
if (!regebp)
|
|
{ // if end of call chain
|
|
debug printf("end of call chain\n");
|
|
break;
|
|
}
|
|
|
|
debug printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr);
|
|
//if (++count == 12) *(char*)0=0;
|
|
handler_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function
|
|
if (!handler_table) // if no static data
|
|
{
|
|
debug printf("no handler table\n");
|
|
continue;
|
|
}
|
|
funcoffset = cast(uint)handler_table.fptr;
|
|
spoff = handler_table.espoffset;
|
|
retoffset = handler_table.retoffset;
|
|
|
|
debug
|
|
{
|
|
printf("retaddr = x%x\n",cast(uint)retaddr);
|
|
printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
|
|
regebp,funcoffset,spoff,retoffset);
|
|
}
|
|
|
|
// Find start index for retaddr in static data
|
|
dim = handler_table.nhandlers;
|
|
|
|
debug
|
|
{
|
|
printf("handler_info[]:\n");
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
phi = &handler_table.handler_info[i];
|
|
printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n",
|
|
i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code);
|
|
}
|
|
}
|
|
|
|
index = -1;
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
phi = &handler_table.handler_info[i];
|
|
|
|
debug printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset);
|
|
if (cast(uint)retaddr > funcoffset + phi.offset &&
|
|
cast(uint)retaddr <= funcoffset + phi.endoffset)
|
|
index = i;
|
|
}
|
|
debug printf("index = %d\n", index);
|
|
|
|
// walk through handler table, checking each handler
|
|
// with an index smaller than the current table_index
|
|
for (ndx = index; ndx != -1; ndx = prev_ndx)
|
|
{
|
|
phi = &handler_table.handler_info[ndx];
|
|
prev_ndx = phi.prev_index;
|
|
if (phi.cioffset)
|
|
{
|
|
// this is a catch handler (no finally)
|
|
DCatchInfo *pci;
|
|
int ncatches;
|
|
int i;
|
|
|
|
pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
|
|
ncatches = pci.ncatches;
|
|
for (i = 0; i < ncatches; i++)
|
|
{
|
|
DCatchBlock *pcb;
|
|
ClassInfo ci = **cast(ClassInfo **)h;
|
|
|
|
pcb = &pci.catch_block[i];
|
|
|
|
if (_d_isbaseof(ci, pcb.type))
|
|
{ // Matched the catch type, so we've found the handler.
|
|
|
|
// Initialize catch variable
|
|
*cast(void **)(regebp + (pcb.bpoffset)) = h;
|
|
|
|
// Jump to catch block. Does not return.
|
|
{
|
|
uint catch_esp;
|
|
fp_t catch_addr;
|
|
|
|
catch_addr = cast(fp_t)(pcb.code);
|
|
catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
|
|
asm
|
|
{
|
|
mov EAX,catch_esp ;
|
|
mov ECX,catch_addr ;
|
|
mov [EAX],ECX ;
|
|
mov EBP,regebp ;
|
|
mov ESP,EAX ; // reset stack
|
|
ret ; // jump to catch block
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (phi.finally_code)
|
|
{ // Call finally block
|
|
// Note that it is unnecessary to adjust the ESP, as the finally block
|
|
// accesses all items on the stack as relative to EBP.
|
|
|
|
void *blockaddr = phi.finally_code;
|
|
|
|
asm
|
|
{
|
|
push EBX ;
|
|
mov EBX,blockaddr ;
|
|
push EBP ;
|
|
mov EBP,regebp ;
|
|
call EBX ;
|
|
pop EBP ;
|
|
pop EBX ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|