1: // Copyright (C) 1994-1998 by Symantec
  2: // Copyright (C) 2000-2011 by Digital Mars
  3: // All Rights Reserved
  4: // http://www.digitalmars.com
  5: // Written by Walter Bright
  6: /*
  7:  * This source file is made available for personal use
  8:  * only. The license is in /dmd/src/dmd/backendlicense.txt
  9:  * or /dm/src/dmd/backendlicense.txt
 10:  * For any other uses, please contact Digital Mars.
 11:  */
 12: 
 13: // Support for NT exception handling
 14: 
 15: #include        <stdio.h>
 16: #include        <string.h>
 17: #include        <time.h>
 18: 
 19: #include        "cc.h"
 20: #include        "el.h"
 21: #include        "code.h"
 22: #include        "oper.h"
 23: #include        "global.h"
 24: #include        "type.h"
 25: #include        "dt.h"
 26: #if SCPP
 27: #include        "scope.h"
 28: #endif
 29: #include        "exh.h"
 30: 
 31: #if !SPP && NTEXCEPTIONS
 32: 
 33: static char __file__[] = __FILE__;      /* for tassert.h                */
 34: #include        "tassert.h"
 35: 
 36: static symbol *s_table;
 37: static symbol *s_context;
 38: static char s_name_context_tag[] = "__nt_context";
 39: static char s_name_context[] = "__context";
 40: static char s_name_ecode[] = "__ecode";
 41: 
 42: static char text_nt[] =
 43:     "struct __nt_context {"
 44:         "int esp; int info; int prev; int handler; int stable; int sindex; int ebp;"
 45:      "};\n";
 46: 
 47: // member stable is not used for MARS or C++
 48: 
 49: int nteh_EBPoffset_sindex()     { return -4; }
 50: int nteh_EBPoffset_prev()       { return -nteh_contextsym_size() + 8; }
warning C4146: unary minus operator applied to unsigned type, result still unsigned
51: int nteh_EBPoffset_info() { return -nteh_contextsym_size() + 4; }
warning C4146: unary minus operator applied to unsigned type, result still unsigned
52: int nteh_EBPoffset_esp() { return -nteh_contextsym_size() + 0; }
warning C4146: unary minus operator applied to unsigned type, result still unsigned
53: 54: int nteh_offset_sindex() { return MARS ? 16 : 20; } 55: int nteh_offset_sindex_seh() { return 20; } 56: int nteh_offset_info() { return 4; } 57: 58: /*********************************** 59: */ 60: 61: unsigned char *nteh_context_string() 62: { 63: if (config.flags2 & CFG2seh) 64: return (unsigned char *)text_nt; 65: else 66: return NULL; 67: } 68: 69: /******************************* 70: * Get symbol for scope table for current function. 71: * Returns: 72: * symbol of table 73: */ 74: 75: STATIC symbol *nteh_scopetable() 76: { symbol *s; 77: type *t; 78: 79: if (!s_table) 80: { 81: t = type_alloc(TYint); 82: s = symbol_generate(SCstatic,t); 83: s->Sseg = UNKNOWN; 84: symbol_keep(s); 85: s_table = s; 86: } 87: return s_table; 88: } 89: 90: /************************************* 91: */ 92: 93: void nteh_filltables() 94: { 95: #if MARS 96: symbol *s = s_table; 97: symbol_debug(s); 98: except_fillInEHTable(s); 99: #endif 100: } 101: 102: /**************************** 103: * Generate and output scope table. 104: * Not called for NTEH C++ exceptions 105: */ 106: 107: void nteh_gentables() 108: { 109: symbol *s = s_table; 110: symbol_debug(s); 111: #if MARS 112: //except_fillInEHTable(s); 113: #else 114: /* NTEH table for C. 115: * The table consists of triples: 116: * parent index 117: * filter address 118: * handler address 119: */ 120: unsigned fsize = 4; // target size of function pointer 121: dt_t **pdt = &s->Sdt; 122: int sz = 0; // size so far 123: 124: for (block *b = startblock; b; b = b->Bnext) 125: { 126: if (b->BC == BC_try) 127: { dt_t *dt; 128: block *bhandler; 129: 130: pdt = dtdword(pdt,b->Blast_index); // parent index 131: 132: // If try-finally 133: if (list_nitems(b->Bsucc) == 2) 134: { 135: pdt = dtdword(pdt,0); // filter address 136: bhandler = list_block(list_next(b->Bsucc)); 137: assert(bhandler->BC == BC_finally); 138: // To successor of BC_finally block 139: bhandler = list_block(bhandler->Bsucc); 140: } 141: else // try-except 142: { 143: bhandler = list_block(list_next(b->Bsucc)); 144: assert(bhandler->BC == BC_filter); 145: pdt = dtcoff(pdt,bhandler->Boffset); // filter address 146: bhandler = list_block(list_next(list_next(b->Bsucc))); 147: assert(bhandler->BC == BC_except); 148: } 149: pdt = dtcoff(pdt,bhandler->Boffset); // handler address 150: sz += 4 + fsize * 2; 151: } 152: } 153: assert(sz != 0); 154: #endif 155: 156: outdata(s); // output the scope table 157: #if MARS 158: nteh_framehandler(s); 159: #endif 160: s_table = NULL; 161: } 162: 163: /************************** 164: * Declare frame variables. 165: */ 166: 167: void nteh_declarvars(Blockx *bx) 168: { symbol *s; 169: 170: #if MARS 171: if (!(bx->funcsym->Sfunc->Fflags3 & Fnteh)) // if haven't already done it 172: { bx->funcsym->Sfunc->Fflags3 |= Fnteh; 173: s = symbol_name(s_name_context,SCbprel,tsint); 174: s->Soffset = -5 * 4; // -6 * 4 for C __try, __except, __finally 175: s->Sflags |= SFLfree | SFLnodebug; 176: type_setty(&s->Stype,mTYvolatile | TYint); 177: symbol_add(s); 178: bx->context = s; 179: } 180: #else 181: if (!(funcsym_p->Sfunc->Fflags3 & Fnteh)) // if haven't already done it 182: { funcsym_p->Sfunc->Fflags3 |= Fnteh; 183: if (!s_context) 184: s_context = scope_search(s_name_context_tag,CPP ? SCTglobal : SCTglobaltag); 185: symbol_debug(s_context); 186: 187: s = symbol_name(s_name_context,SCbprel,s_context->Stype); 188: s->Soffset = -6 * 4; // -5 * 4 for C++ 189: s->Sflags |= SFLfree; 190: symbol_add(s); 191: type_setty(&s->Stype,mTYvolatile | TYstruct); 192: 193: s = symbol_name(s_name_ecode,SCauto,type_alloc(mTYvolatile | TYint)); 194: s->Sflags |= SFLfree; 195: symbol_add(s); 196: } 197: #endif 198: } 199: 200: /************************************** 201: * Generate elem that sets the context index into the scope table. 202: */ 203: 204: #if MARS 205: elem *nteh_setScopeTableIndex(Blockx *blx, int scope_index) 206: { 207: elem *e; 208: Symbol *s; 209: 210: s = blx->context; 211: symbol_debug(s); 212: e = el_var(s); 213: e->EV.sp.Voffset = nteh_offset_sindex(); 214: return el_bin(OPeq, TYint, e, el_long(TYint, scope_index)); 215: } 216: #endif 217: 218: 219: /********************************** 220: * Return pointer to context symbol. 221: */ 222: 223: symbol *nteh_contextsym() 224: { SYMIDX si; 225: symbol *sp; 226: 227: for (si = 0; 1; si++) 228: { assert(si < globsym.top); 229: sp = globsym.tab[si]; 230: symbol_debug(sp); 231: if (strcmp(sp->Sident,s_name_context) == 0) 232: return sp; 233: } 234: } 235: 236: /********************************** 237: * Return size of context symbol on stack. 238: */ 239: 240: unsigned nteh_contextsym_size() 241: { int sz; 242: 243: if (usednteh & NTEH_try) 244: { 245: #if MARS 246: sz = 5 * 4; 247: #elif SCPP 248: sz = 6 * 4; 249: #else 250: assert(0); 251: #endif 252: assert(usedalloca != 1); 253: } 254: else if (usednteh & NTEHcpp) 255: { sz = 5 * 4; // C++ context record 256: assert(usedalloca != 1); 257: } 258: else if (usednteh & NTEHpassthru) 259: { sz = 1 * 4; 260: } 261: else 262: sz = 0; // no context record 263: return sz; 264: } 265: 266: /********************************** 267: * Return pointer to ecode symbol. 268: */ 269: 270: symbol *nteh_ecodesym() 271: { SYMIDX si; 272: symbol *sp; 273: 274: for (si = 0; 1; si++) 275: { assert(si < globsym.top); 276: sp = globsym.tab[si]; 277: symbol_debug(sp); 278: if (strcmp(sp->Sident,s_name_ecode) == 0) 279: return sp; 280: } 281: } 282: 283: /********************************* 284: * Mark EH variables as used so that they don't get optimized away. 285: */ 286: 287: void nteh_usevars() 288: { 289: #if SCPP 290: // Turn off SFLdead and SFLunambig in Sflags 291: nteh_contextsym()->Sflags &= ~(SFLdead | SFLunambig); 292: nteh_contextsym()->Sflags |= SFLread; 293: nteh_ecodesym()->Sflags &= ~(SFLdead | SFLunambig); 294: nteh_ecodesym()->Sflags |= SFLread; 295: #else 296: // Turn off SFLdead and SFLunambig in Sflags 297: nteh_contextsym()->Sflags &= ~SFLdead; 298: nteh_contextsym()->Sflags |= SFLread; 299: #endif 300: } 301: 302: /********************************* 303: * Generate NT exception handling function prolog. 304: */ 305: 306: code *nteh_prolog() 307: { 308: code cs; 309: code *c1; 310: code *c; 311: 312: if (usednteh & NTEHpassthru) 313: { 314: /* An sindex value of -2 is a magic value that tells the 315: * stack unwinder to skip this frame. 316: */ 317: assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64)); 318: cs.Iop = 0x68; 319: cs.Iflags = 0; 320: cs.Irex = 0; 321: cs.IFL2 = FLconst; 322: cs.IEV2.Vint = -2; 323: return gen(CNIL,&cs); // PUSH -2 324: } 325: 326: /* Generate instance of struct __nt_context on stack frame: 327: [ ] // previous ebp already there 328: push -1 // sindex 329: mov EDX,FS:__except_list 330: push offset FLAT:scope_table // stable (not for MARS or C++) 331: push offset FLAT:__except_handler3 // handler 332: push EDX // prev 333: mov FS:__except_list,ESP 334: sub ESP,8 // info, esp for __except support 335: */ 336: 337: // useregs(mAX); // What is this for? 338: 339: cs.Iop = 0x68; 340: cs.Iflags = 0; 341: cs.Irex = 0; 342: cs.IFL2 = FLconst; 343: cs.IEV2.Vint = -1; 344: c1 = gen(CNIL,&cs); // PUSH -1 345: 346: if (usednteh & NTEHcpp || MARS) 347: { 348: // PUSH &framehandler 349: cs.IFL2 = FLframehandler; 350: #if MARS 351: nteh_scopetable(); 352: #endif 353: } 354: else 355: { 356: // Do stable 357: cs.Iflags |= CFoff; 358: cs.IFL2 = FLextern; 359: cs.IEVsym2 = nteh_scopetable(); 360: cs.IEVoffset2 = 0; 361: c1 = gen(c1,&cs); // PUSH &scope_table 362: 363: cs.IFL2 = FLextern; 364: cs.IEVsym2 = rtlsym[RTLSYM_EXCEPT_HANDLER3]; 365: makeitextern(rtlsym[RTLSYM_EXCEPT_HANDLER3]); 366: } 367: c = gen(NULL,&cs); // PUSH &__except_handler3 368: 369: if (config.exe == EX_NT) 370: { 371: makeitextern(rtlsym[RTLSYM_EXCEPT_LIST]); 372: #if 0 373: cs.Iop = 0xFF; 374: cs.Irm = modregrm(0,6,BPRM); 375: cs.Iflags = CFfs; 376: cs.Irex = 0; 377: cs.IFL1 = FLextern; 378: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 379: cs.IEVoffset1 = 0; 380: gen(c,&cs); // PUSH FS:__except_list 381: #else 382: useregs(mDX); 383: cs.Iop = 0x8B; 384: cs.Irm = modregrm(0,DX,BPRM); 385: cs.Iflags = CFfs; 386: cs.Irex = 0; 387: cs.IFL1 = FLextern; 388: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 389: cs.IEVoffset1 = 0; 390: gen(c1,&cs); // MOV EDX,FS:__except_list 391: 392: gen1(c,0x50 + DX); // PUSH EDX 393: #endif 394: cs.Iop = 0x89; 395: NEWREG(cs.Irm,SP); 396: gen(c,&cs); // MOV FS:__except_list,ESP 397: } 398: 399: c = genc2(c,0x81,modregrm(3,5,SP),8); // SUB ESP,8 400: 401: return cat(c1,c); 402: } 403: 404: /********************************* 405: * Generate NT exception handling function epilog. 406: */ 407: 408: code *nteh_epilog() 409: { 410: if (!(config.flags2 & CFG2seh)) 411: return NULL; 412: 413: /* Generate: 414: mov ECX,__context[EBP].prev 415: mov FS:__except_list,ECX 416: */ 417: code cs; 418: code *c; 419: unsigned reg; 420: 421: #if MARS 422: reg = CX; 423: #else 424: reg = (tybasic(funcsym_p->Stype->Tnext->Tty) == TYvoid) ? AX : CX; 425: #endif 426: useregs(mask[reg]); 427: 428: cs.Iop = 0x8B; 429: cs.Irm = modregrm(2,reg,BPRM); 430: cs.Iflags = 0; 431: cs.Irex = 0; 432: cs.IFL1 = FLconst; 433: // EBP offset of __context.prev 434: cs.IEV1.Vint = nteh_EBPoffset_prev(); 435: c = gen(CNIL,&cs); 436: 437: cs.Iop = 0x89; 438: cs.Irm = modregrm(0,reg,BPRM); 439: cs.Iflags |= CFfs; 440: cs.IFL1 = FLextern; 441: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 442: cs.IEVoffset1 = 0; 443: return gen(c,&cs); 444: } 445: 446: /************************** 447: * Set/Reset ESP from context. 448: */ 449: 450: code *nteh_setsp(int op) 451: { code cs; 452: 453: cs.Iop = op; 454: cs.Irm = modregrm(2,SP,BPRM); 455: cs.Iflags = 0; 456: cs.Irex = 0; 457: cs.IFL1 = FLconst; 458: // EBP offset of __context.esp 459: cs.IEV1.Vint = nteh_EBPoffset_esp(); 460: return gen(CNIL,&cs); // MOV ESP,__context[EBP].esp 461: } 462: 463: /**************************** 464: * Put out prolog for BC_filter block. 465: */ 466: 467: code *nteh_filter(block *b) 468: { code *c; 469: code cs; 470: 471: assert(b->BC == BC_filter); 472: c = CNIL; 473: if (b->Bflags & BFLehcode) // if referenced __ecode 474: { 475: /* Generate: 476: mov EAX,__context[EBP].info 477: mov EAX,[EAX] 478: mov EAX,[EAX] 479: mov __ecode[EBP],EAX 480: */ 481: 482: c = getregs(mAX); 483: 484: cs.Iop = 0x8B; 485: cs.Irm = modregrm(2,AX,BPRM); 486: cs.Iflags = 0; 487: cs.Irex = 0; 488: cs.IFL1 = FLconst; 489: // EBP offset of __context.info 490: cs.IEV1.Vint = nteh_EBPoffset_info(); 491: c = gen(c,&cs); // MOV EAX,__context[EBP].info 492: cs.Irm = modregrm(0,AX,0); 493: gen(c,&cs); // MOV EAX,[EAX] 494: gen(c,&cs); // MOV EAX,[EAX] 495: cs.Iop = 0x89; 496: cs.Irm = modregrm(2,AX,BPRM); 497: cs.IFL1 = FLauto; 498: cs.IEVsym1 = nteh_ecodesym(); 499: cs.IEVoffset1 = 0; 500: gen(c,&cs); // MOV __ecode[EBP],EAX 501: } 502: return c; 503: } 504: 505: /******************************* 506: * Generate C++ or D frame handler. 507: */ 508: 509: void nteh_framehandler(symbol *scopetable) 510: { code *c; 511: 512: // Generate: 513: // MOV EAX,&scope_table 514: // JMP __cpp_framehandler 515: 516: if (scopetable) 517: { 518: symbol_debug(scopetable); 519: c = gencs(NULL,0xB8+AX,0,FLextern,scopetable); // MOV EAX,&scope_table 520: gencs(c,0xE9,0,FLfunc,rtlsym[RTLSYM_CPP_HANDLER]); // JMP __cpp_framehandler 521: 522: pinholeopt(c,NULL); 523: codout(c); 524: code_free(c); 525: } 526: } 527: 528: /********************************* 529: * Generate code to set scope index. 530: */ 531: 532: code *nteh_gensindex(int sindex) 533: { code *c; 534: 535: if (!(config.flags2 & CFG2seh)) 536: return NULL; 537: 538: // Generate: 539: // MOV -4[EBP],sindex 540: 541: c = genc(NULL,0xC7,modregrm(1,0,BP),FLconst,(targ_uns)nteh_EBPoffset_sindex(),FLconst,sindex); // 7 bytes long 542: c->Iflags |= CFvolatile; 543: #ifdef DEBUG 544: //assert(GENSINDEXSIZE == calccodsize(c)); 545: #endif 546: return c; 547: } 548: 549: /********************************* 550: * Generate code for setjmp(). 551: */ 552: 553: code *cdsetjmp(elem *e,regm_t *pretregs) 554: { code cs; 555: code *c; 556: regm_t retregs; 557: unsigned stackpushsave; 558: unsigned flag; 559: 560: c = NULL; 561: stackpushsave = stackpush; 562: #if SCPP 563: if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp)) 564: { 565: /* If in C++ try block 566: If the frame that is calling setjmp has a try,catch block then 567: the call to setjmp3 is as follows: 568: __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata); 569: 570: __cpp_longjmp_unwind is a routine in the RTL. This is a 571: stdcall routine that will deal with unwinding for CPP Frames. 572: trylevel is the value that gets incremented at each catch, 573: constructor invocation. 574: funcdata is the same value that you put into EAX prior to 575: cppframehandler getting called. 576: */ 577: symbol *s; 578: 579: s = except_gensym(); 580: if (!s) 581: goto L1; 582: 583: c = gencs(c,0x68,0,FLextern,s); // PUSH &scope_table 584: stackpush += 4; 585: genadjesp(c,4); 586: 587: c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4); 588: // PUSH trylevel 589: stackpush += 4; 590: genadjesp(c,4); 591: 592: cs.Iop = 0x68; 593: cs.Iflags = CFoff; 594: cs.Irex = 0; 595: cs.IFL2 = FLextern; 596: cs.IEVsym2 = rtlsym[RTLSYM_CPP_LONGJMP]; 597: cs.IEVoffset2 = 0; 598: c = gen(c,&cs); // PUSH &_cpp_longjmp_unwind 599: stackpush += 4; 600: genadjesp(c,4); 601: 602: flag = 3; 603: } 604: else 605: #endif 606: if (funcsym_p->Sfunc->Fflags3 & Fnteh) 607: { 608: /* If in NT SEH try block 609: If the frame that is calling setjmp has a try, except block 610: then the call to setjmp3 is as follows: 611: __setjmp3(environment,2,__seh_longjmp_unwind,trylevel); 612: __seth_longjmp_unwind is supplied by the RTL and is a stdcall 613: function. It is the name that MSOFT uses, we should 614: probably use the same one. 615: trylevel is the value that you increment at each try and 616: decrement at the close of the try. This corresponds to the 617: index field of the ehrec. 618: */ 619: int sindex_off; 620: 621: sindex_off = 20; // offset of __context.sindex 622: cs.Iop = 0xFF; 623: cs.Irm = modregrm(2,6,BPRM); 624: cs.Iflags = 0; 625: cs.Irex = 0; 626: cs.IFL1 = FLbprel; 627: cs.IEVsym1 = nteh_contextsym(); 628: cs.IEVoffset1 = sindex_off; 629: c = gen(c,&cs); // PUSH scope_index 630: stackpush += 4; 631: genadjesp(c,4); 632: 633: cs.Iop = 0x68; 634: cs.Iflags = CFoff; 635: cs.Irex = 0; 636: cs.IFL2 = FLextern; 637: cs.IEVsym2 = rtlsym[RTLSYM_LONGJMP]; 638: cs.IEVoffset2 = 0; 639: c = gen(c,&cs); // PUSH &_seh_longjmp_unwind 640: stackpush += 4; 641: genadjesp(c,4); 642: 643: flag = 2; 644: } 645: else 646: { 647: /* If the frame calling setjmp has neither a try..except, nor a 648: try..catch, then call setjmp3 as follows: 649: _setjmp3(environment,0) 650: */ 651: L1:
warning C4102: 'L1' : unreferenced label
652: flag = 0; 653: } 654: 655: cs.Iop = 0x68; 656: cs.Iflags = 0; 657: cs.Irex = 0; 658: cs.IFL2 = FLconst; 659: cs.IEV2.Vint = flag; 660: c = gen(c,&cs); // PUSH flag 661: stackpush += 4; 662: genadjesp(c,4); 663: 664: c = cat(c,params(e->E1,REGSIZE)); 665: 666: c = cat(c,getregs(~rtlsym[RTLSYM_SETJMP3]->Sregsaved & (ALLREGS | mES))); 667: gencs(c,0xE8,0,FLfunc,rtlsym[RTLSYM_SETJMP3]); // CALL __setjmp3 668: 669: c = genc2(c,0x81,modregrm(3,0,SP),stackpush - stackpushsave); // ADD ESP,8 670: genadjesp(c,-(stackpush - stackpushsave));
warning C4146: unary minus operator applied to unsigned type, result still unsigned
671: 672: stackpush = stackpushsave; 673: retregs = regmask(e->Ety, TYnfunc); 674: return cat(c,fixresult(e,retregs,pretregs)); 675: } 676: 677: /**************************************** 678: * Call _local_unwind(), which means call the __finally blocks until 679: * index is reached. 680: */ 681: 682: code *nteh_unwind(regm_t retregs,unsigned index) 683: { code *c; 684: code cs; 685: code *cs1; 686: code *cs2; 687: regm_t desregs; 688: int reg; 689: int local_unwind; 690: 691: // Shouldn't this always be CX? 692: #if SCPP 693: reg = AX; 694: #else 695: reg = CX; 696: #endif 697: 698: #if MARS 699: local_unwind = RTLSYM_D_LOCAL_UNWIND2; 700: #else 701: local_unwind = RTLSYM_LOCAL_UNWIND2; 702: #endif 703: desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg]; 704: gensaverestore(retregs & desregs,&cs1,&cs2); 705: 706: c = getregs(desregs); 707: 708: cs.Iop = 0x8D; 709: cs.Irm = modregrm(2,reg,BPRM); 710: cs.Iflags = 0; 711: cs.Irex = 0; 712: cs.IFL1 = FLconst; 713: // EBP offset of __context.prev 714: cs.IEV1.Vint = nteh_EBPoffset_prev(); 715: c = gen(c,&cs); // LEA ECX,contextsym 716: 717: genc2(c,0x68,0,index); // PUSH index 718: gen1(c,0x50 + reg); // PUSH ECX 719: 720: #if MARS 721: //gencs(c,0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table 722: gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table 723: 724: gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2() 725: genc2(c,0x81,modregrm(3,0,SP),12); // ADD ESP,12 726: #else 727: gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2() 728: genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8 729: #endif 730: 731: c = cat4(cs1,c,cs2,NULL); 732: return c; 733: } 734: 735: /**************************************** 736: * Call _local_unwind(), which means call the __finally blocks until 737: * index is reached. 738: */ 739: 740: #if 0 // Replaced with inline calls to __finally blocks 741: 742: code *linux_unwind(regm_t retregs,unsigned index) 743: { code *c; 744: code *cs1; 745: code *cs2; 746: int i; 747: regm_t desregs; 748: int reg; 749: int local_unwind; 750: 751: // Shouldn't this always be CX? 752: #if SCPP 753: reg = AX; 754: #else 755: reg = CX; 756: #endif 757: 758: #if MARS 759: local_unwind = RTLSYM_D_LOCAL_UNWIND2; 760: #else 761: local_unwind = RTLSYM_LOCAL_UNWIND2; 762: #endif 763: desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg]; 764: gensaverestore(retregs & desregs,&cs1,&cs2); 765: 766: c = getregs(desregs); 767: c = genc2(c,0x68,0,index); // PUSH index 768: 769: #if MARS 770: // gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table 771: 772: gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __d_local_unwind2() 773: genc2(c,0x81,modregrm(3,0,SP),4); // ADD ESP,12 774: #else 775: gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]); // CALL __local_unwind2() 776: genc2(c,0x81,modregrm(3,0,SP),8); // ADD ESP,8 777: #endif 778: 779: c = cat4(cs1,c,cs2,NULL); 780: return c; 781: } 782: 783: #endif 784: 785: /************************************************* 786: * Set monitor, hook monitor exception handler. 787: */ 788: 789: #if MARS 790: 791: code *nteh_monitor_prolog(Symbol *shandle) 792: { 793: /* 794: * PUSH handle 795: * PUSH offset _d_monitor_handler 796: * PUSH FS:__except_list 797: * MOV FS:__except_list,ESP 798: * CALL _d_monitor_prolog 799: */ 800: code *c1 = NULL; 801: code *c; 802: code cs; 803: Symbol *s; 804: regm_t desregs; 805: 806: assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's 807: 808: if (shandle->Sclass == SCfastpar) 809: { assert(shandle->Spreg != DX); 810: c = gen1(NULL,0x50 + shandle->Spreg); // PUSH shandle 811: } 812: else 813: { 814: // PUSH shandle 815: #if 0 816: c = genc1(NULL,0xFF,modregrm(2,6,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); 817: c->Isib = modregrm(0,4,SP); 818: #else 819: useregs(mCX); 820: c = genc1(NULL,0x8B,modregrm(2,CX,4),FLconst,4 * (1 + needframe) + shandle->Soffset + localsize); 821: c->Isib = modregrm(0,4,SP); 822: gen1(c,0x50 + CX); // PUSH ECX 823: #endif 824: } 825: 826: s = rtlsym[RTLSYM_MONITOR_HANDLER]; 827: c = gencs(c,0x68,0,FLextern,s); // PUSH offset _d_monitor_handler 828: makeitextern(s); 829: 830: #if 0 831: cs.Iop = 0xFF; 832: cs.Irm = modregrm(0,6,BPRM); 833: cs.Iflags = CFfs; 834: cs.Irex = 0; 835: cs.IFL1 = FLextern; 836: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 837: cs.IEVoffset1 = 0; 838: gen(c,&cs); // PUSH FS:__except_list 839: #else 840: useregs(mDX); 841: cs.Iop = 0x8B; 842: cs.Irm = modregrm(0,DX,BPRM); 843: cs.Iflags = CFfs; 844: cs.Irex = 0; 845: cs.IFL1 = FLextern; 846: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 847: cs.IEVoffset1 = 0; 848: c1 = gen(c1,&cs); // MOV EDX,FS:__except_list 849: 850: gen1(c,0x50 + DX); // PUSH EDX 851: #endif 852: 853: s = rtlsym[RTLSYM_MONITOR_PROLOG]; 854: desregs = ~s->Sregsaved & ALLREGS; 855: c = cat(c,getregs(desregs)); 856: c = gencs(c,0xE8,0,FLfunc,s); // CALL _d_monitor_prolog 857: 858: cs.Iop = 0x89; 859: NEWREG(cs.Irm,SP); 860: gen(c,&cs); // MOV FS:__except_list,ESP 861: 862: return cat(c1,c); 863: } 864: 865: #endif 866: 867: /************************************************* 868: * Release monitor, unhook monitor exception handler. 869: * Input: 870: * retregs registers to not destroy 871: */ 872: 873: #if MARS 874: 875: code *nteh_monitor_epilog(regm_t retregs) 876: { 877: /* 878: * CALL _d_monitor_epilog 879: * POP FS:__except_list 880: */ 881: code cs; 882: code *c; 883: code *cs1; 884: code *cs2; 885: code *cpop; 886: regm_t desregs; 887: Symbol *s; 888: 889: assert(config.flags2 & CFG2seh); // BUG: figure out how to implement for other EX's 890: 891: s = rtlsym[RTLSYM_MONITOR_EPILOG]; 892: //desregs = ~s->Sregsaved & ALLREGS; 893: desregs = 0; 894: gensaverestore(retregs & desregs,&cs1,&cs2); 895: 896: c = getregs(desregs); 897: c = gencs(c,0xE8,0,FLfunc,s); // CALL __d_monitor_epilog 898: 899: cs.Iop = 0x8F; 900: cs.Irm = modregrm(0,0,BPRM); 901: cs.Iflags = CFfs; 902: cs.Irex = 0; 903: cs.IFL1 = FLextern; 904: cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST]; 905: cs.IEVoffset1 = 0; 906: cpop = gen(NULL,&cs); // POP FS:__except_list 907: 908: c = cat4(cs1,c,cs2,cpop); 909: return c; 910: } 911: 912: #endif 913: 914: #endif 915: