1 /* 2 * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com 3 * Written by Walter Bright 4 * 5 * This software is provided 'as-is', without any express or implied 6 * warranty. In no event will the authors be held liable for any damages 7 * arising from the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, in both source and binary form, subject to the following 12 * restrictions: 13 * 14 * o The origin of this software must not be misrepresented; you must not 15 * claim that you wrote the original software. If you use this software 16 * in a product, an acknowledgment in the product documentation would be 17 * appreciated but is not required. 18 * o Altered source versions must be plainly marked as such, and must not 19 * be misrepresented as being the original software. 20 * o This notice may not be removed or altered from any source 21 * distribution. 22 */ 23 24 module rt.compiler.dmd.posix.deh; 25 26 // Exception handling support for linux 27 28 //debug=1; 29 import tango.stdc.stdio : printf; 30 import tango.stdc.stdlib : exit; 31 32 version (darwin) 33 import rt.compiler.dmd.darwin.Image; 34 35 extern (C) 36 { 37 version (darwin) {} 38 39 else 40 { 41 extern void* _deh_beg; 42 extern void* _deh_end; 43 } 44 45 int _d_isbaseof(ClassInfo oc, ClassInfo c); 46 } 47 48 alias int (*fp_t)(); // function pointer in ambient memory model 49 50 struct DHandlerInfo 51 { 52 uint offset; // offset from function address to start of guarded section 53 uint endoffset; // offset of end of guarded section 54 int prev_index; // previous table index 55 uint 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) 58 } 59 60 // Address of DHandlerTable, searched for by eh_finddata() 61 62 struct DHandlerTable 63 { 64 void *fptr; // pointer to start of function 65 uint espoffset; // offset of ESP from EBP 66 uint retoffset; // offset from start of function to return code 67 size_t nhandlers; // dimension of handler_info[] 68 DHandlerInfo handler_info[1]; 69 } 70 71 struct DCatchBlock 72 { 73 ClassInfo type; // catch type 74 size_t bpoffset; // EBP offset of catch var 75 void *code; // catch handler code 76 } 77 78 // Create one of these for each try-catch 79 struct DCatchInfo 80 { 81 size_t ncatches; // number of catch blocks 82 DCatchBlock catch_block[1]; // data for each catch block 83 } 84 85 // One of these is generated for each function with try-catch or try-finally 86 87 struct FuncTable 88 { 89 void *fptr; // pointer to start of function 90 DHandlerTable *handlertable; // eh data for this function 91 uint fsize; // size of function in bytes 92 } 93 94 void terminate() 95 { 96 asm 97 { 98 hlt ; 99 } 100 } 101 102 /******************************************* 103 * Given address that is inside a function, 104 * figure out which function it is in. 105 * Return DHandlerTable if there is one, NULL if not. 106 */ 107 108 DHandlerTable *__eh_finddata(void *address) 109 { 110 version (darwin) 111 { 112 static FuncTable[] functionTables; 113 static bool hasFunctionTables; 114 115 if (!hasFunctionTables) 116 { 117 functionTables = getSectionData!(FuncTable, "__DATA", "__deh_eh"); 118 hasFunctionTables = true; 119 } 120 121 foreach (ft ; functionTables) 122 { 123 if (ft.fptr <= address && address < cast(void *)(cast(char *)ft.fptr + ft.fsize)) 124 return ft.handlertable; 125 } 126 127 return null; 128 } 129 else 130 { 131 FuncTable *ft; 132 133 // debug printf("__eh_finddata(address = x%x)\n", address); 134 // debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end); 135 for (ft = cast(FuncTable *)&_deh_beg; 136 ft < cast(FuncTable *)&_deh_end; 137 ft++) 138 { 139 // debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n", 140 // ft.fptr, ft.fsize, ft.handlertable); 141 142 if (ft.fptr <= address && 143 address < cast(void *)(cast(char *)ft.fptr + ft.fsize)) 144 { 145 // debug printf("\tfound handler table\n"); 146 return ft.handlertable; 147 } 148 } 149 // debug printf("\tnot found\n"); 150 return null; 151 } 152 } 153 154 155 /****************************** 156 * Given EBP, find return address to caller, and caller's EBP. 157 * Input: 158 * regbp Value of EBP for current function 159 * *pretaddr Return address 160 * Output: 161 * *pretaddr return address to caller 162 * Returns: 163 * caller's EBP 164 */ 165 166 size_t __eh_find_caller(size_t regbp, size_t *pretaddr) 167 { 168 size_t bp = *cast(size_t *)regbp; 169 170 if (bp) // if not end of call chain 171 { 172 // Perform sanity checks on new EBP. 173 // If it is screwed up, terminate() hopefully before we do more damage. 174 if (bp <= regbp) 175 // stack should grow to smaller values 176 terminate(); 177 178 *pretaddr = *cast(size_t *)(regbp + size_t.sizeof); 179 } 180 return bp; 181 } 182 183 /*********************************** 184 * Deprecated because of Bugzilla 4398, 185 * keep for the moment for backwards compatibility. 186 */ 187 188 extern (Windows) void _d_throw(Object *h) 189 { 190 _d_throwc(h); 191 } 192 193 /*********************************** 194 * Throw a D object. 195 */ 196 197 extern(C) void _d_throwc(Object *h) 198 { 199 size_t regebp; 200 201 debug(deh) 202 { 203 printf("_d_throw(h = %p, &h = %p)\n", h, &h); 204 printf("\tvptr = %p\n", *cast(void **)h); 205 } 206 207 version (D_InlineAsm_X86) 208 asm 209 { 210 mov regebp,EBP ; 211 } 212 else version (D_InlineAsm_X86_64) 213 asm 214 { 215 mov regebp,RBP ; 216 } 217 else 218 static assert(0); 219 220 //static uint abc; 221 //if (++abc == 2) *(char *)0=0; 222 223 //int count = 0; 224 while (1) // for each function on the stack 225 { 226 DHandlerTable *handler_table; 227 FuncTable *pfunc; 228 DHandlerInfo *phi; 229 size_t retaddr; 230 size_t funcoffset; 231 uint spoff; 232 uint retoffset; 233 int index; 234 size_t dim; 235 int ndx; 236 int prev_ndx; 237 238 regebp = __eh_find_caller(regebp,&retaddr); 239 if (!regebp) 240 { // if end of call chain 241 debug(deh) printf("end of call chain\n"); 242 printf("unhandled exception\n"); 243 exit(1); 244 break; 245 } 246 247 debug(deh) printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr); 248 //if (++count == 12) *(char*)0=0; 249 handler_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function 250 if (!handler_table) // if no static data 251 { 252 debug(deh) printf("no handler table\n"); 253 continue; 254 } 255 funcoffset = cast(size_t)handler_table.fptr; 256 spoff = handler_table.espoffset; 257 retoffset = handler_table.retoffset; 258 259 debug(deh) 260 { 261 printf("retaddr = x%x\n",cast(uint)retaddr); 262 printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n", 263 regebp,funcoffset,spoff,retoffset); 264 } 265 266 // Find start index for retaddr in static data 267 dim = handler_table.nhandlers; 268 269 debug(deh) 270 { 271 printf("handler_info[]:\n"); 272 for (size_t i = 0; i < dim; i++) 273 { 274 phi = handler_table.handler_info.ptr + i; 275 printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n", 276 i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code); 277 } 278 } 279 280 index = -1; 281 for (size_t i = 0; i < dim; i++) 282 { 283 phi = handler_table.handler_info.ptr + i; 284 285 debug(deh) printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset); 286 if (retaddr > funcoffset + phi.offset && 287 retaddr <= funcoffset + phi.endoffset) 288 index = i; 289 } 290 debug(deh) printf("index = %d\n", index); 291 292 // walk through handler table, checking each handler 293 // with an index smaller than the current table_index 294 for (ndx = index; ndx != -1; ndx = prev_ndx) 295 { 296 phi = handler_table.handler_info.ptr + ndx; 297 prev_ndx = phi.prev_index; 298 299 if (phi.cioffset) 300 { 301 // this is a catch handler (no finally) 302 DCatchInfo *pci; 303 size_t ncatches; 304 size_t i; 305 306 pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset); 307 ncatches = pci.ncatches; 308 309 for (i = 0; i < ncatches; i++) 310 { 311 DCatchBlock *pcb; 312 ClassInfo ci = **cast(ClassInfo **)h; 313 314 pcb = pci.catch_block.ptr + i; 315 316 if (_d_isbaseof(ci, pcb.type)) 317 { // Matched the catch type, so we've found the handler. 318 319 // Initialize catch variable 320 *cast(void **)(regebp + (pcb.bpoffset)) = h; 321 322 // Jump to catch block. Does not return. 323 { 324 size_t catch_esp; 325 fp_t catch_addr; 326 327 catch_addr = cast(fp_t)(pcb.code); 328 catch_esp = regebp - handler_table.espoffset - fp_t.sizeof; 329 330 version (D_InlineAsm_X86) 331 asm 332 { 333 mov EAX,catch_esp ; 334 mov ECX,catch_addr ; 335 mov [EAX],ECX ; 336 mov EBP,regebp ; 337 mov ESP,EAX ; // reset stack 338 ret ; // jump to catch block 339 } 340 else version (D_InlineAsm_X86_64) 341 asm 342 { 343 mov RAX,catch_esp ; 344 mov RCX,catch_esp ; 345 mov RCX,catch_addr ; 346 mov [RAX],RCX ; 347 mov RBP,regebp ; 348 mov RSP,RAX ; // reset stack 349 ret ; // jump to catch block 350 } 351 else 352 static assert(0); 353 354 } 355 } 356 } 357 } 358 else if (phi.finally_code) 359 { // Call finally block 360 // Note that it is unnecessary to adjust the ESP, as the finally block 361 // accesses all items on the stack as relative to EBP. 362 363 void *blockaddr = phi.finally_code; 364 365 version (OSX) 366 { 367 version (D_InlineAsm_X86) 368 asm 369 { 370 sub ESP,4 ; 371 push EBX ; 372 mov EBX,blockaddr ; 373 push EBP ; 374 mov EBP,regebp ; 375 call EBX ; 376 pop EBP ; 377 pop EBX ; 378 add ESP,4 ; 379 } 380 else version (D_InlineAsm_X86_64) 381 asm 382 { 383 sub RSP,8 ; 384 push RBX ; 385 mov RBX,blockaddr ; 386 push RBP ; 387 mov RBP,regebp ; 388 call RBX ; 389 pop RBP ; 390 pop RBX ; 391 add RSP,8 ; 392 } 393 else 394 static assert(0); 395 } 396 else 397 { 398 version (D_InlineAsm_X86) 399 asm 400 { 401 push EBX ; 402 mov EBX,blockaddr ; 403 push EBP ; 404 mov EBP,regebp ; 405 call EBX ; 406 pop EBP ; 407 pop EBX ; 408 } 409 else version (D_InlineAsm_X86_64) 410 asm 411 { 412 sub RSP,8 ; 413 push RBX ; 414 mov RBX,blockaddr ; 415 push RBP ; 416 mov RBP,regebp ; 417 call RBX ; 418 pop RBP ; 419 pop RBX ; 420 add RSP,8 ; 421 } 422 else 423 static assert(0); 424 } 425 } 426 } 427 } 428 }