2 // Copyright (c) 1999-2003 by Digital Mars, www.digitalmars.com
4 // Written by Walter Bright
6 // Exception handling support
13 /* ======================== Win32 =============================== */
20 //#include "\sc\src\include\ehsup.h"
22 /*** From Digital Mars C runtime library ***/
23 EXCEPTION_DISPOSITION __cdecl _local_except_handler (EXCEPTION_RECORD *ExceptionRecord,
24 void* EstablisherFrame,
26 void *DispatcherContext
28 void __cdecl _global_unwind(void *frame,EXCEPTION_RECORD *eRecord);
29 #define EXCEPTION_UNWIND 6 // Flag to indicate if the system is unwinding
31 extern DWORD _except_list;
36 extern ClassInfo D9Exception7__ClassZ;
38 #define _Class_9Exception D9Exception7__ClassZ
40 typedef int (__pascal *fp_t)(); // function pointer in ambient memory model
42 // The layout of DEstablisherFrame is the same for C++
44 struct DEstablisherFrame
46 void *prev; // pointer to previous exception list
47 void *handler; // pointer to routine for exception handler
48 DWORD table_index; // current index into handler_info[]
49 DWORD ebp; // this is EBP of routine
54 int prev_index; // previous table index
55 unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
56 void *finally_code; // pointer to finally code to execute
57 // (!=0 if try-finally)
60 // Address of DHandlerTable is passed in EAX to _d_framehandler()
64 void *fptr; // pointer to start of function
65 unsigned espoffset; // offset of ESP from EBP
66 unsigned retoffset; // offset from start of function to return code
67 struct DHandlerInfo handler_info[1];
72 ClassInfo *type; // catch type
73 unsigned bpoffset; // EBP offset of catch var
74 void *code; // catch handler code
77 // Create one of these for each try-catch
80 unsigned ncatches; // number of catch blocks
81 struct DCatchBlock catch_block[1]; // data for each catch block
84 // Macro to make our own exception code
85 #define MAKE_EXCEPTION_CODE(severity, facility, exception) \
86 (((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception))
88 #define STATUS_DIGITAL_MARS_D_EXCEPTION MAKE_EXCEPTION_CODE(3,'D',1)
90 Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record);
91 void __cdecl _d_local_unwind(struct DHandlerTable *handler_table, struct DEstablisherFrame *frame, int stop_index);
94 /***********************************
95 * The frame handler, this is called for each frame that has been registered
96 * in the OS except_list.
98 * EAX the handler table for the frame
101 EXCEPTION_DISPOSITION _d_framehandler(
102 EXCEPTION_RECORD *exception_record,
103 struct DEstablisherFrame *frame,
105 void *dispatcher_context)
107 struct DHandlerTable *handler_table;
109 __asm { mov handler_table,EAX }
111 if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
113 // Call all the finally blocks in this frame
114 _d_local_unwind(handler_table, frame, -1);
118 // Jump to catch block if matching one is found
121 struct DHandlerInfo *phi;
122 struct DCatchInfo *pci;
123 struct DCatchBlock *pcb;
124 unsigned ncatches; // number of catches in the current handler
128 ci = NULL; // only compute it if we need it
130 // walk through handler table, checking each handler
131 // with an index smaller than the current table_index
132 for (ndx = frame->table_index; ndx != -1; ndx = prev_ndx)
134 phi = &handler_table->handler_info[ndx];
135 prev_ndx = phi->prev_index;
138 // this is a catch handler (no finally)
139 pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
140 ncatches = pci->ncatches;
141 for (i = 0; i < ncatches; i++)
143 pcb = &pci->catch_block[i];
147 // This code must match the translation code
148 if (exception_record->ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION)
150 //printf("ei[0] = %p\n", exception_record->ExceptionInformation[0]);
151 ci = **(ClassInfo ***)(exception_record->ExceptionInformation[0]);
154 ci = &_Class_9Exception;
157 if (_d_isbaseof(ci, pcb->type))
158 { // Matched the catch type, so we've found the handler.
161 pti = _d_translate_se_to_d_exception(exception_record);
163 // Initialize catch variable
164 regebp = (int)&frame->ebp; // EBP for this frame
165 *(void **)(regebp + (pcb->bpoffset)) = pti;
167 // Have system call all finally blocks in intervening frames
168 _global_unwind(frame, exception_record);
170 // Call all the finally blocks skipped in this frame
171 _d_local_unwind(handler_table, frame, ndx);
173 frame->table_index = prev_ndx; // we are out of this handler
175 // Jump to catch block. Does not return.
180 catch_addr = (fp_t)(pcb->code);
181 catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
188 mov ESP,EAX // reset stack
189 ret // jump to catch block
197 return ExceptionContinueSearch;
200 /***********************************
201 * Exception filter for use in __try..__except block
202 * surrounding call to Dmain()
205 int _d_exception_filter(struct _EXCEPTION_POINTERS *eptrs,
207 Object **exception_object)
209 *exception_object = _d_translate_se_to_d_exception(eptrs->ExceptionRecord);
213 /***********************************
217 void __stdcall _d_throw(Object *h)
219 //printf("_d_throw(h = %p, &h = %p)\n", h, &h);
220 //printf("\tvptr = %p\n", *(void **)h);
221 RaiseException(STATUS_DIGITAL_MARS_D_EXCEPTION,
222 EXCEPTION_NONCONTINUABLE,
226 /***********************************
227 * Create an exception object
230 Object *_d_create_exception_object(ClassInfo *ci, char *msg)
234 exc = (Exception *)_d_newclass(ci);
235 // BUG: what if _d_newclass() throws an out of memory exception?
239 exc->msglen = strlen(msg);
242 return (Object *)exc;
245 /***********************************
246 * Converts a Windows Structured Exception code to a D Exception Object.
249 Object *_d_translate_se_to_d_exception(EXCEPTION_RECORD *exception_record)
253 switch (exception_record->ExceptionCode) {
254 case STATUS_DIGITAL_MARS_D_EXCEPTION:
255 // Generated D exception
256 pti = (Object *)(exception_record->ExceptionInformation[0]);
259 case STATUS_INTEGER_DIVIDE_BY_ZERO:
260 pti = _d_create_exception_object(&_Class_9Exception, "Integer Divide by Zero");
263 case STATUS_FLOAT_DIVIDE_BY_ZERO:
264 pti = _d_create_exception_object(&_Class_9Exception, "Float Divide by Zero");
267 case STATUS_ACCESS_VIOLATION:
268 pti = _d_create_exception_object(&_Class_9Exception, "Access Violation");
271 case STATUS_STACK_OVERFLOW:
272 pti = _d_create_exception_object(&_Class_9Exception, "Stack Overflow");
275 // convert all other exception codes into a Win32Exception
277 pti = _d_create_exception_object(&_Class_9Exception, "Win32 Exception");
284 /**************************************
285 * Call finally blocks in the current stack frame until stop_index.
286 * This is roughly equivalent to _local_unwind() for C in \src\win32\ehsup.c
289 void __cdecl _d_local_unwind(struct DHandlerTable *handler_table,
290 struct DEstablisherFrame *frame, int stop_index)
292 struct DHandlerInfo *phi;
293 struct DCatchInfo *pci;
296 // Set up a special exception handler to catch double-fault exceptions.
301 push offset _local_except_handler // defined in src\win32\ehsup.c
302 push dword ptr fs:_except_list
303 mov FS:_except_list,ESP
306 for (i = frame->table_index; i != -1 && i != stop_index; i = phi->prev_index)
308 phi = &handler_table->handler_info[i];
309 if (phi->finally_code)
311 // Note that it is unnecessary to adjust the ESP, as the finally block
312 // accesses all items on the stack as relative to EBP.
314 DWORD *catch_ebp = &frame->ebp;
315 void *blockaddr = phi->finally_code;
337 /***********************************
338 * external version of the unwinder
341 __declspec(naked) void __cdecl _d_local_unwind2()
349 /***********************************
350 * The frame handler, this is called for each frame that has been registered
351 * in the OS except_list.
353 * EAX the handler table for the frame
356 EXCEPTION_DISPOSITION _d_monitor_handler(
357 EXCEPTION_RECORD *exception_record,
358 struct DEstablisherFrame *frame,
360 void *dispatcher_context)
362 if (exception_record->ExceptionFlags & EXCEPTION_UNWIND)
364 _d_monitorexit((Object *)frame->table_index);
369 return ExceptionContinueSearch;
372 /***********************************
375 void _d_monitor_prolog(void *x, void *y, Object *h)
381 //printf("_d_monitor_prolog(x=%p, y=%p, h=%p)\n", x, y, h);
389 /***********************************
392 void _d_monitor_epilog(void *x, void *y, Object *h)
394 //printf("_d_monitor_epilog(x=%p, y=%p, h=%p)\n", x, y, h);
410 /* ======================== linux =============================== */
416 extern ClassInfo D9Exception7__ClassZ;
418 #define _Class_9Exception D9Exception7__ClassZ
420 typedef int (*fp_t)(); // function pointer in ambient memory model
424 unsigned offset; // offset from function address to start of guarded section
425 int prev_index; // previous table index
426 unsigned cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
427 void *finally_code; // pointer to finally code to execute
428 // (!=0 if try-finally)
431 // Address of DHandlerTable, searched for by eh_finddata()
435 void *fptr; // pointer to start of function
436 unsigned espoffset; // offset of ESP from EBP
437 unsigned retoffset; // offset from start of function to return code
438 unsigned nhandlers; // dimension of handler_info[]
439 struct DHandlerInfo handler_info[1];
444 ClassInfo *type; // catch type
445 unsigned bpoffset; // EBP offset of catch var
446 void *code; // catch handler code
449 // Create one of these for each try-catch
452 unsigned ncatches; // number of catch blocks
453 struct DCatchBlock catch_block[1]; // data for each catch block
456 // One of these is generated for each function with try-catch or try-finally
460 void *fptr; // pointer to start of function
461 struct DHandlerTable *handlertable; // eh data for this function
462 unsigned size; // size of function in bytes
465 extern struct FuncTable *table_start;
466 extern struct FuncTable *table_end;
476 /*******************************************
477 * Given address that is inside a function,
478 * figure out which function it is in.
479 * Return DHandlerTable if there is one, NULL if not.
482 struct DHandlerTable *__eh_finddata(void *address)
484 struct FuncTable *ft;
486 for (ft = (struct FuncTable *)table_start;
487 ft < (struct FuncTable *)table_end;
490 if (ft->fptr <= address &&
491 address < (void *)((char *)ft->fptr + ft->size))
493 return ft->handlertable;
500 /******************************
501 * Given EBP, find return address to caller, and caller's EBP.
503 * regbp Value of EBP for current function
504 * *pretaddr Return address
506 * *pretaddr return address to caller
511 unsigned __eh_find_caller(unsigned regbp, unsigned *pretaddr)
513 unsigned bp = *(unsigned *)regbp;
515 if (bp) // if not end of call chain
517 // Perform sanity checks on new EBP.
518 // If it is screwed up, terminate() hopefully before we do more damage.
520 // stack should grow to smaller values
523 *pretaddr = *(unsigned *)(regbp + sizeof(int));
528 /***********************************
532 void __stdcall _d_throw(Object *h)
536 //printf("_d_throw(h = %p, &h = %p)\n", h, &h);
537 //printf("\tvptr = %p\n", *(void **)h);
541 while (1) // for each function on the stack
543 struct DHandlerTable *handler_table;
544 struct FuncTable *pfunc;
545 struct DHandlerInfo *phi;
555 regebp = __eh_find_caller(regebp,&retaddr);
557 // if end of call chain
560 handler_table = __eh_finddata((void *)retaddr); // find static data associated with function
561 if (!handler_table) // if no static data
565 funcoffset = (unsigned)handler_table->fptr;
566 spoff = handler_table->espoffset;
567 retoffset = handler_table->retoffset;
570 printf("retaddr = x%x\n",(unsigned)retaddr);
571 printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
572 regebp,funcoffset,spoff,retoffset);
575 // Find start index for retaddr in static data
576 dim = handler_table->nhandlers;
578 for (int i = 0; i < dim; i++)
580 phi = &handler_table->handler_info[i];
582 if ((unsigned)retaddr >= funcoffset + phi->offset)
586 // walk through handler table, checking each handler
587 // with an index smaller than the current table_index
588 for (ndx = index; ndx != -1; ndx = prev_ndx)
590 phi = &handler_table->handler_info[ndx];
591 prev_ndx = phi->prev_index;
594 // this is a catch handler (no finally)
595 struct DCatchInfo *pci;
599 pci = (struct DCatchInfo *)((char *)handler_table + phi->cioffset);
600 ncatches = pci->ncatches;
601 for (i = 0; i < ncatches; i++)
603 struct DCatchBlock *pcb;
604 ClassInfo *ci = **(ClassInfo ***)h;
606 pcb = &pci->catch_block[i];
608 if (_d_isbaseof(ci, pcb->type))
609 { // Matched the catch type, so we've found the handler.
611 // Initialize catch variable
612 *(void **)(regebp + (pcb->bpoffset)) = h;
614 // Jump to catch block. Does not return.
619 catch_addr = (fp_t)(pcb->code);
620 catch_esp = regebp - handler_table->espoffset - sizeof(fp_t);
627 mov ESP,EAX // reset stack
628 ret // jump to catch block
634 else if (phi->finally_code)
635 { // Call finally block
636 // Note that it is unnecessary to adjust the ESP, as the finally block
637 // accesses all items on the stack as relative to EBP.
639 void *blockaddr = phi->finally_code;