code *nteh_unwind(regm_t retregs,unsigned index) { code cs; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; code *cs1; code *cs2; gensaverestore(retregs & desregs,&cs1,&cs2); CodeBuilder cdb(getregs(desregs)); cs.Iop = 0x8D; cs.Irm = modregrm(2,reg,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLconst; // EBP offset of __context.prev cs.IEV1.Vint = nteh_EBPoffset_prev(); cdb.gen(&cs); // LEA ECX,contextsym cdb.genc2(0x68,0,index); // PUSH index cdb.gen1(0x50 + reg); // PUSH ECX #if MARS //cdb.gencs(0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table cdb.gencs(0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cdb.append(cod3_stackadj(NULL, -12)); #else cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cdb.append(cod3_stackadj(NULL, -8)); #endif CodeBuilder cdb1(cs1); CodeBuilder cdb2(cs2); cdb1.append(cdb, cdb2); return cdb1.finish(); }
code *nteh_unwind(regm_t retregs,unsigned index) { code *c; code cs; code *cs1; code *cs2; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; gensaverestore(retregs & desregs,&cs1,&cs2); c = getregs(desregs); cs.Iop = 0x8D; cs.Irm = modregrm(2,reg,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLconst; // EBP offset of __context.prev cs.IEV1.Vint = nteh_EBPoffset_prev(); c = gen(c,&cs); // LEA ECX,contextsym genc2(c,0x68,0,index); // PUSH index gen1(c,0x50 + reg); // PUSH ECX #if MARS //gencs(c,0xB8+AX,0,FLextern,nteh_scopetable()); // MOV EAX,&scope_table gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cod3_stackadj(c, -12); #else gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cod3_stackadj(c, -8); #endif c = cat4(cs1,c,cs2,NULL); return c; }
code *linux_unwind(regm_t retregs,unsigned index) { int i; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; code *cs1; code *cs2; gensaverestore(retregs & desregs,&cs1,&cs2); CodeBuilder cdb(getregs(desregs)); cdb.genc2(0x68,0,index); // PUSH index #if MARS // cdb.gencs(0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cdb.append(cod3_stackadj(NULL, -4)); #else cdb.gencs(0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cdb.append(cod3_stackadj(NULL, -8)); #endif CodeBuilder cdb1(cs1); CodeBuilder cdb2(cs2); cdb1.append(cdb, cdb2); return cdb1.finish(); }
code *linux_unwind(regm_t retregs,unsigned index) { code *c; code *cs1; code *cs2; int i; regm_t desregs; int reg; int local_unwind; // Shouldn't this always be CX? #if SCPP reg = AX; #else reg = CX; #endif #if MARS local_unwind = RTLSYM_D_LOCAL_UNWIND2; #else local_unwind = RTLSYM_LOCAL_UNWIND2; #endif desregs = (~getRtlsym(local_unwind)->Sregsaved & (ALLREGS)) | mask[reg]; gensaverestore(retregs & desregs,&cs1,&cs2); c = getregs(desregs); c = genc2(c,0x68,0,index); // PUSH index #if MARS // gencs(c,0x68,0,FLextern,nteh_scopetable()); // PUSH &scope_table gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __d_local_unwind2() cod3_stackadj(c, -4); #else gencs(c,0xE8,0,FLfunc,getRtlsym(local_unwind)); // CALL __local_unwind2() cod3_stackadj(c, -8); #endif c = cat4(cs1,c,cs2,NULL); return c; }
code *cdsetjmp(elem *e,regm_t *pretregs) { code cs; code *c; regm_t retregs; unsigned stackpushsave; unsigned flag; c = NULL; stackpushsave = stackpush; #if SCPP if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp)) { /* If in C++ try block If the frame that is calling setjmp has a try,catch block then the call to setjmp3 is as follows: __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata); __cpp_longjmp_unwind is a routine in the RTL. This is a stdcall routine that will deal with unwinding for CPP Frames. trylevel is the value that gets incremented at each catch, constructor invocation. funcdata is the same value that you put into EAX prior to cppframehandler getting called. */ symbol *s; s = except_gensym(); if (!s) goto L1; c = gencs(c,0x68,0,FLextern,s); // PUSH &scope_table stackpush += 4; genadjesp(c,4); c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4); // PUSH trylevel stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_CPP_LONGJMP); cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_cpp_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 3; } else #endif if (funcsym_p->Sfunc->Fflags3 & Fnteh) { /* If in NT SEH try block If the frame that is calling setjmp has a try, except block then the call to setjmp3 is as follows: __setjmp3(environment,2,__seh_longjmp_unwind,trylevel); __seth_longjmp_unwind is supplied by the RTL and is a stdcall function. It is the name that MSOFT uses, we should probably use the same one. trylevel is the value that you increment at each try and decrement at the close of the try. This corresponds to the index field of the ehrec. */ int sindex_off; sindex_off = 20; // offset of __context.sindex cs.Iop = 0xFF; cs.Irm = modregrm(2,6,BPRM); cs.Iflags = 0; cs.Irex = 0; cs.IFL1 = FLbprel; cs.IEVsym1 = nteh_contextsym(); cs.IEVoffset1 = sindex_off; c = gen(c,&cs); // PUSH scope_index stackpush += 4; genadjesp(c,4); cs.Iop = 0x68; cs.Iflags = CFoff; cs.Irex = 0; cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_LONGJMP); cs.IEVoffset2 = 0; c = gen(c,&cs); // PUSH &_seh_longjmp_unwind stackpush += 4; genadjesp(c,4); flag = 2; } else { /* If the frame calling setjmp has neither a try..except, nor a try..catch, then call setjmp3 as follows: _setjmp3(environment,0) */ L1: flag = 0; } cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = flag; c = gen(c,&cs); // PUSH flag stackpush += 4; genadjesp(c,4); c = cat(c,pushParams(e->E1,REGSIZE)); c = cat(c,getregs(~getRtlsym(RTLSYM_SETJMP3)->Sregsaved & (ALLREGS | mES))); gencs(c,0xE8,0,FLfunc,getRtlsym(RTLSYM_SETJMP3)); // CALL __setjmp3 c = cod3_stackadj(c, -(stackpush - stackpushsave)); genadjesp(c,-(stackpush - stackpushsave)); stackpush = stackpushsave; retregs = regmask(e->Ety, TYnfunc); return cat(c,fixresult(e,retregs,pretregs)); }
code *nteh_prolog() { code cs; code *c1; code *c; if (usednteh & NTEHpassthru) { /* An sindex value of -2 is a magic value that tells the * stack unwinder to skip this frame. */ assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64 | EX_OPENBSD | EX_OPENBSD64)); cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = -2; return gen(CNIL,&cs); // PUSH -2 } /* Generate instance of struct __nt_context on stack frame: [ ] // previous ebp already there push -1 // sindex mov EDX,FS:__except_list push offset FLAT:scope_table // stable (not for MARS or C++) push offset FLAT:__except_handler3 // handler push EDX // prev mov FS:__except_list,ESP sub ESP,8 // info, esp for __except support */ // useregs(mAX); // What is this for? cs.Iop = 0x68; cs.Iflags = 0; cs.Irex = 0; cs.IFL2 = FLconst; cs.IEV2.Vint = -1; c1 = gen(CNIL,&cs); // PUSH -1 if (MARS || (usednteh & NTEHcpp)) { // PUSH &framehandler cs.IFL2 = FLframehandler; #if MARS nteh_scopetable(); #endif } else { // Do stable cs.Iflags |= CFoff; cs.IFL2 = FLextern; cs.IEVsym2 = nteh_scopetable(); cs.IEVoffset2 = 0; c1 = gen(c1,&cs); // PUSH &scope_table cs.IFL2 = FLextern; cs.IEVsym2 = getRtlsym(RTLSYM_EXCEPT_HANDLER3); makeitextern(getRtlsym(RTLSYM_EXCEPT_HANDLER3)); } c = gen(NULL,&cs); // PUSH &__except_handler3 if (config.exe == EX_WIN32) { makeitextern(getRtlsym(RTLSYM_EXCEPT_LIST)); #if 0 cs.Iop = 0xFF; cs.Irm = modregrm(0,6,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; gen(c,&cs); // PUSH FS:__except_list #else useregs(mDX); cs.Iop = 0x8B; cs.Irm = modregrm(0,DX,BPRM); cs.Iflags = CFfs; cs.Irex = 0; cs.IFL1 = FLextern; cs.IEVsym1 = getRtlsym(RTLSYM_EXCEPT_LIST); cs.IEVoffset1 = 0; gen(c1,&cs); // MOV EDX,FS:__except_list gen1(c,0x50 + DX); // PUSH EDX #endif cs.Iop = 0x89; NEWREG(cs.Irm,SP); gen(c,&cs); // MOV FS:__except_list,ESP } c = cod3_stackadj(c, 8); return cat(c1,c); }