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: