From: Julian Seward Date: Thu, 12 Jan 2006 12:27:58 +0000 (+0000) Subject: Merge in function wrapping support from the FNWRAP branch. That X-Git-Tag: svn/VALGRIND_3_2_3^2~125 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=971efb683c44acc729571935d6fed5eb012a1be8;p=thirdparty%2Fvalgrind.git Merge in function wrapping support from the FNWRAP branch. That branch hereby becomes inactive. git-svn-id: svn://svn.valgrind.org/vex/trunk@1536 --- diff --git a/VEX/priv/guest-amd64/ghelpers.c b/VEX/priv/guest-amd64/ghelpers.c index 70d0ff505f..8e8c707dde 100644 --- a/VEX/priv/guest-amd64/ghelpers.c +++ b/VEX/priv/guest-amd64/ghelpers.c @@ -1965,6 +1965,8 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state ) initialise them anyway. */ vex_state->guest_TISTART = 0; vex_state->guest_TILEN = 0; + + vex_state->guest_NRADDR = 0; } diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index 1d6ec4dc39..079e10cf61 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -122,6 +122,28 @@ sto{s,sb,sw,sd,sq} xlat{,b} */ +/* "Special" instructions. + + This instruction decoder can decode three special instructions + which mean nothing natively (are no-ops as far as regs/mem are + concerned) but have meaning for supporting Valgrind. A special + instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D + 48C1C73D 48C1C733 (in the standard interpretation, that means: rolq + $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi). + Following that, one of the following 3 are allowed (standard + interpretation in parentheses): + + 4887DB (xchgq %rbx,%rbx) %RDX = client_request ( %RAX ) + 4887C9 (xchgq %rcx,%rcx) %RAX = guest_NRADDR + 4887D2 (xchgq %rdx,%rdx) call-noredir *%RAX + + Any other bytes following the 16-byte preamble are illegal and + constitute a failure in instruction decoding. This all assumes + that the preamble will never occur except in specific code + fragments designed for Valgrind to catch. + + No prefixes may precede a "Special" instruction. */ + /* Translates AMD64 code to IR. */ #include "libvex_basictypes.h" @@ -398,6 +420,8 @@ static void unimplemented ( HChar* str ) #define OFFB_TISTART offsetof(VexGuestAMD64State,guest_TISTART) #define OFFB_TILEN offsetof(VexGuestAMD64State,guest_TILEN) +#define OFFB_NRADDR offsetof(VexGuestAMD64State,guest_NRADDR) + /*------------------------------------------------------------*/ /*--- Helper bits and pieces for deconstructing the ---*/ @@ -7949,29 +7973,61 @@ DisResult disInstr_AMD64_WRK ( if (put_IP) stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) ); - /* Spot the client-request magic sequence. */ + /* Spot "Special" instructions (see comment at top of file). */ { UChar* code = (UChar*)(guest_code + delta); - /* Spot this: - C1C01D roll $29, %eax - C1C003 roll $3, %eax - C1C81B rorl $27, %eax - C1C805 rorl $5, %eax - C1C00D roll $13, %eax - C1C013 roll $19, %eax + /* Spot the 16-byte preamble: + 48C1C703 rolq $3, %rdi + 48C1C70D rolq $13, %rdi + 48C1C73D rolq $61, %rdi + 48C1C733 rolq $51, %rdi */ - if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D && - code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 && - code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B && - code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 && - code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D && - code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13 - ) { - DIP("%%edx = client_request ( %%eax )\n"); - delta += 18; - jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta); - dres.whatNext = Dis_StopHere; - goto decode_success; + if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7 + && code[ 3] == 0x03 && + code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7 + && code[ 7] == 0x0D && + code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7 + && code[11] == 0x3D && + code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7 + && code[15] == 0x33) { + /* Got a "Special" instruction preamble. Which one is it? */ + if (code[16] == 0x48 && code[17] == 0x87 + && code[18] == 0xDB /* xchgq %rbx,%rbx */) { + /* %RDX = client_request ( %RAX ) */ + DIP("%%rdx = client_request ( %%rax )\n"); + delta += 19; + jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta); + dres.whatNext = Dis_StopHere; + goto decode_success; + } + else + if (code[16] == 0x48 && code[17] == 0x87 + && code[18] == 0xC9 /* xchgq %rcx,%rcx */) { + /* %RAX = guest_NRADDR */ + DIP("%%rax = guest_NRADDR\n"); + delta += 19; + putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 )); + goto decode_success; + } + else + if (code[16] == 0x48 && code[17] == 0x87 + && code[18] == 0xD2 /* xchgq %rdx,%rdx */) { + /* call-noredir *%RAX */ + DIP("call-noredir *%%rax\n"); + delta += 19; + t1 = newTemp(Ity_I64); + assign(t1, getIRegRAX(8)); + t2 = newTemp(Ity_I64); + assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8))); + putIReg64(R_RSP, mkexpr(t2)); + storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta)); + jmp_treg(Ijk_NoRedir,t1); + dres.whatNext = Dis_StopHere; + goto decode_success; + } + /* We don't know what it is. */ + goto decode_failure; + /*NOTREACHED*/ } } diff --git a/VEX/priv/guest-generic/bb_to_IR.c b/VEX/priv/guest-generic/bb_to_IR.c index c354762b40..290691b74b 100644 --- a/VEX/priv/guest-generic/bb_to_IR.c +++ b/VEX/priv/guest-generic/bb_to_IR.c @@ -56,8 +56,10 @@ __attribute((regparm(2))) static UInt genericg_compute_adler32 ( HWord addr, HWord len ); +/* Small helpers */ +static Bool const_False ( Addr64 a ) { return False; } -/* Disassemble a complete basic block, starting at guest_IP_bbstart, +/* Disassemble a complete basic block, starting at guest_IP_start, returning a new IRBB. The disassembler may chase across basic block boundaries if it wishes and if chase_into_ok allows it. The precise guest address ranges from which code has been taken @@ -71,24 +73,29 @@ static UInt genericg_compute_adler32 ( HWord addr, HWord len ); do_self_check indicates that the caller needs a self-checking translation. - offB_TIADDR and offB_TILEN are the offsets of guest_TIADDR and - guest_TILEN. Since this routine has to work for any guest state, - without knowing what it is, those offsets have to passed in. -*/ + do_set_NRADDR indicates that the unredirected guest address for + this BB should be written to the guest's NRADDR pseudo-register. -static Bool const_False ( Addr64 a ) { return False; } + offB_TIADDR, offB_TILEN and offB_NRADDR are the offsets of + guest_TIADDR, guest_TILEN and guest_NRADDR. Since this routine has + to work for any guest state, without knowing what it is, those + offsets have to passed in. +*/ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, /*IN*/ DisOneInstrFn dis_instr_fn, /*IN*/ UChar* guest_code, /*IN*/ Addr64 guest_IP_bbstart, + /*IN*/ Addr64 guest_IP_bbstart_noredir, /*IN*/ Bool (*chase_into_ok)(Addr64), /*IN*/ Bool host_bigendian, /*IN*/ VexArchInfo* archinfo_guest, /*IN*/ IRType guest_word_type, /*IN*/ Bool do_self_check, + /*IN*/ Bool do_set_NRADDR, /*IN*/ Int offB_TISTART, - /*IN*/ Int offB_TILEN ) + /*IN*/ Int offB_TILEN, + /*IN*/ Int offB_NRADDR ) { Long delta; Int i, n_instrs, first_stmt_idx; @@ -100,6 +107,8 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, Int selfcheck_idx = 0; IRBB* irbb; Addr64 guest_IP_curr_instr; + IRConst* guest_IP_bbstart_IRConst = NULL; + IRConst* guest_IP_bbstart_noredir_IRConst = NULL; Bool (*resteerOKfn)(Addr64) = NULL; @@ -131,7 +140,23 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, delta = 0; n_instrs = 0; - /* If asked to make a self-checking translation, leave a 5 spaces + /* Guest addresses as IRConsts. Used in the two self-checks + generated. */ + if (do_self_check) { + guest_IP_bbstart_IRConst + = guest_word_type==Ity_I32 + ? IRConst_U32(toUInt(guest_IP_bbstart)) + : IRConst_U64(guest_IP_bbstart); + } + + if (do_set_NRADDR) { + guest_IP_bbstart_noredir_IRConst + = guest_word_type==Ity_I32 + ? IRConst_U32(toUInt(guest_IP_bbstart_noredir)) + : IRConst_U64(guest_IP_bbstart_noredir); + } + + /* If asked to make a self-checking translation, leave 5 spaces in which to put the check statements. We'll fill them in later when we know the length and adler32 of the area to check. */ if (do_self_check) { @@ -143,6 +168,18 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, addStmtToIRBB( irbb, IRStmt_NoOp() ); } + /* Set guest_NRADDR if asked to. This records the unredirected + guest address of this bb, so that it can later be read (and so + used by a function wrapper to get to the function itself. */ + if (do_set_NRADDR) { + /* set guest_NRADDR to guest_IP_bbstart_noredir */ + addStmtToIRBB( + irbb, + IRStmt_Put( offB_NRADDR, + IRExpr_Const(guest_IP_bbstart_noredir_IRConst)) + ); + } + /* Process instructions. */ while (True) { vassert(n_instrs < vex_control.guest_max_insns); @@ -197,7 +234,7 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, vassert(dres.whatNext == Dis_StopHere || dres.whatNext == Dis_Continue || dres.whatNext == Dis_Resteer); - vassert(dres.len >= 0 && dres.len <= 18); + vassert(dres.len >= 0 && dres.len <= 20); if (dres.whatNext != Dis_Resteer) vassert(dres.continueAt == 0); @@ -298,7 +335,6 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, if (do_self_check) { UInt len2check, adler32; - IRConst* guest_IP_bbstart_IRConst; IRTemp tistart_tmp, tilen_tmp; vassert(vge->n_used == 1); @@ -308,11 +344,6 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, adler32 = genericg_compute_adler32( (HWord)guest_code, len2check ); - guest_IP_bbstart_IRConst - = guest_word_type==Ity_I32 - ? IRConst_U32(toUInt(guest_IP_bbstart)) - : IRConst_U64(guest_IP_bbstart); - /* Set TISTART and TILEN. These will describe to the despatcher the area of guest code to invalidate should we exit with a self-check failure. */ diff --git a/VEX/priv/guest-generic/bb_to_IR.h b/VEX/priv/guest-generic/bb_to_IR.h index f30af3de3f..94d2ddef9b 100644 --- a/VEX/priv/guest-generic/bb_to_IR.h +++ b/VEX/priv/guest-generic/bb_to_IR.h @@ -154,13 +154,16 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, /*IN*/ DisOneInstrFn dis_instr_fn, /*IN*/ UChar* guest_code, /*IN*/ Addr64 guest_IP_bbstart, + /*IN*/ Addr64 guest_IP_bbstart_noredir, /*IN*/ Bool (*chase_into_ok)(Addr64), /*IN*/ Bool host_bigendian, /*IN*/ VexArchInfo* archinfo_guest, /*IN*/ IRType guest_word_type, /*IN*/ Bool do_self_check, + /*IN*/ Bool do_set_NRADDR, /*IN*/ Int offB_TISTART, - /*IN*/ Int offB_TILEN ); + /*IN*/ Int offB_TILEN, + /*IN*/ Int offB_NRADDR ); #endif /* ndef GENERIC_BB_TO_IR_H */ diff --git a/VEX/priv/guest-ppc/ghelpers.c b/VEX/priv/guest-ppc/ghelpers.c index 767381eb2c..54d1767020 100644 --- a/VEX/priv/guest-ppc/ghelpers.c +++ b/VEX/priv/guest-ppc/ghelpers.c @@ -458,10 +458,12 @@ void LibVEX_GuestPPC32_initialise ( /*OUT*/VexGuestPPC32State* vex_state ) vex_state->guest_EMWARN = EmWarn_NONE; + vex_state->guest_RESVN = 0; + vex_state->guest_TISTART = 0; vex_state->guest_TILEN = 0; - vex_state->guest_RESVN = 0; + vex_state->guest_NRADDR = 0; } @@ -606,10 +608,12 @@ void LibVEX_GuestPPC64_initialise ( /*OUT*/VexGuestPPC64State* vex_state ) vex_state->guest_EMWARN = EmWarn_NONE; + vex_state->guest_RESVN = 0; + vex_state->guest_TISTART = 0; vex_state->guest_TILEN = 0; - vex_state->guest_RESVN = 0; + vex_state->guest_NRADDR = 0; } diff --git a/VEX/priv/guest-ppc/toIR.c b/VEX/priv/guest-ppc/toIR.c index 4089c803fa..3d9b97544d 100644 --- a/VEX/priv/guest-ppc/toIR.c +++ b/VEX/priv/guest-ppc/toIR.c @@ -83,6 +83,27 @@ results would then be zeroed, too. */ +/* "Special" instructions. + + This instruction decoder can decode three special instructions + which mean nothing natively (are no-ops as far as regs/mem are + concerned) but have meaning for supporting Valgrind. A special + instruction is flagged by the 16-byte preamble 54001800 54006800 + 5400E800 54009800 (in the standard interpretation, that means: + rlwinm 0,0,3,0,0; rlwinm 0,0,13,0,0; rlwinm 0,0,29,0,0; rlwinm + 0,0,19,0,0). Following that, one of the following 3 are allowed + (standard interpretation in parentheses): + + 7C210B78 (or 1,1,1) %R3 = client_request ( %R4 ) + 7C421378 (or 2,2,2) %R3 = guest_NRADDR + 7C631B78 (or 3,3,3) branch-and-link-to-noredir %R11 + + Any other bytes following the 16-byte preamble are illegal and + constitute a failure in instruction decoding. This all assumes + that the preamble will never occur except in specific code + fragments designed for Valgrind to catch. +*/ + /* Translates PPC32/64 code to IR. */ @@ -200,7 +221,7 @@ static void* fnptr_to_fnentry( void* f ) #define OFFB_TISTART offsetofPPCGuestState(guest_TISTART) #define OFFB_TILEN offsetofPPCGuestState(guest_TILEN) #define OFFB_RESVN offsetofPPCGuestState(guest_RESVN) - +#define OFFB_NRADDR offsetofPPCGuestState(guest_NRADDR) /*------------------------------------------------------------*/ @@ -8358,8 +8379,7 @@ DisResult disInstr_PPC_WRK ( if (put_IP) putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) ); - /* Spot the client-request magic sequence. */ - // Essentially a v. unlikely sequence of noops that we can catch + /* Spot "Special" instructions (see comment at top of file). */ if (mode64) { /* Spot the magic sequence, 64-bit mode */ UChar* code = (UChar*)(&guest_code[delta]); @@ -8388,31 +8408,54 @@ DisResult disInstr_PPC_WRK ( goto decode_success; } } else { - /* Spot the magic sequence, 32-bit mode */ - UChar* code = (UChar*)(&guest_code[delta]); - - /* Spot this: - 0x7C03D808 tw 0,3,27 => trap word if (0) => nop - 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29) - 0x54001800 rlwinm 0,0, 3,0,0 => r0 = rotl(r0, 3) - 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13) - 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19) - 0x60000000 nop + UChar* code = (UChar*)(guest_code + delta); + /* Spot the 16-byte preamble: + 54001800 rlwinm 0,0,3,0,0 + 54006800 rlwinm 0,0,13,0,0 + 5400E800 rlwinm 0,0,29,0,0 + 54009800 rlwinm 0,0,19,0,0 */ - if (getUIntBigendianly(code+ 0) == 0x7C03D808 && - getUIntBigendianly(code+ 4) == 0x5400E800 && - getUIntBigendianly(code+ 8) == 0x54001800 && - getUIntBigendianly(code+12) == 0x54006800 && - getUIntBigendianly(code+16) == 0x54009800 && - getUIntBigendianly(code+20) == 0x60000000) { - DIP("%%r3 = client_request ( %%r31 )\n"); - dres.len = 24; - delta += 24; - - irbb->next = mkSzImm( ty, guest_CIA_bbstart + delta ); - irbb->jumpkind = Ijk_ClientReq; - dres.whatNext = Dis_StopHere; - goto decode_success; + if (getUIntBigendianly(code+ 0) == 0x54001800 && + getUIntBigendianly(code+ 4) == 0x54006800 && + getUIntBigendianly(code+ 8) == 0x5400E800 && + getUIntBigendianly(code+12) == 0x54009800) { + /* Got a "Special" instruction preamble. Which one is it? */ + if (getUIntBigendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) { + /* %R3 = client_request ( %R4 ) */ + DIP("r3 = client_request ( %%r4 )\n"); + delta += 20; + irbb->next = mkSzImm( ty, guest_CIA_bbstart + delta ); + irbb->jumpkind = Ijk_ClientReq; + dres.whatNext = Dis_StopHere; + goto decode_success; + } + else + if (getUIntBigendianly(code+16) == 0x7C421378 /* or 2,2,2 */) { + /* %R3 = guest_NRADDR */ + DIP("r3 = guest_NRADDR\n"); + delta += 20; + dres.len = 20; + putIReg(3, IRExpr_Get( OFFB_NRADDR, ty )); + goto decode_success; + } + else + if (getUIntBigendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) { + /* branch-and-link-to-noredir %R11 */ + DIP("branch-and-link-to-noredir r11\n"); + delta += 20; + putGST( PPC_GST_LR, mkSzImm(ty, guest_CIA_bbstart + delta) ); + irbb->next = getIReg(11); + irbb->jumpkind = Ijk_NoRedir; + dres.whatNext = Dis_StopHere; + goto decode_success; + } + /* We don't know what it is. Set opc1/opc2 so decode_failure + can print the insn following the Special-insn preamble. */ + theInstr = getUIntBigendianly(code+16); + opc1 = ifieldOPC(theInstr); + opc2 = ifieldOPClo10(theInstr); + goto decode_failure; + /*NOTREACHED*/ } } @@ -9007,7 +9050,11 @@ DisResult disInstr_PPC_WRK ( /* All decode successes end up here. */ DIP("\n"); - dres.len = 4; + if (dres.len == 0) { + dres.len = 4; + } else { + vassert(dres.len == 20); + } return dres; } diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 83f05232ca..9e50b9e278 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -2225,6 +2225,8 @@ void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state ) /* SSE2 has a 'clflush' cache-line-invalidator which uses these. */ vex_state->guest_TISTART = 0; vex_state->guest_TILEN = 0; + + vex_state->guest_NRADDR = 0; } diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 762b67d696..38c925eca9 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -122,6 +122,30 @@ way through bbs as usual. */ +/* "Special" instructions. + + This instruction decoder can decode three special instructions + which mean nothing natively (are no-ops as far as regs/mem are + concerned) but have meaning for supporting Valgrind. A special + instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D + C1C713 (in the standard interpretation, that means: roll $3, %edi; + roll $13, %edi; roll $29, %edi; roll $19, %edi). Following that, + one of the following 3 are allowed (standard interpretation in + parentheses): + + 87DB (xchgl %ebx,%ebx) %EDX = client_request ( %EAX ) + 87C9 (xchgl %ecx,%ecx) %EAX = guest_NRADDR + 87D2 (xchgl %edx,%edx) call-noredir *%EAX + + Any other bytes following the 12-byte preamble are illegal and + constitute a failure in instruction decoding. This all assumes + that the preamble will never occur except in specific code + fragments designed for Valgrind to catch. + + No prefixes may precede a "Special" instruction. +*/ + + /* Translates x86 code to IR. */ #include "libvex_basictypes.h" @@ -227,6 +251,8 @@ static IRBB* irbb; #define OFFB_TISTART offsetof(VexGuestX86State,guest_TISTART) #define OFFB_TILEN offsetof(VexGuestX86State,guest_TILEN) +#define OFFB_NRADDR offsetof(VexGuestX86State,guest_NRADDR) + /*------------------------------------------------------------*/ /*--- Helper bits and pieces for deconstructing the ---*/ @@ -7012,32 +7038,58 @@ DisResult disInstr_X86_WRK ( if (put_IP) stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) ); - /* Spot the client-request magic sequence. */ + /* Spot "Special" instructions (see comment at top of file). */ { UChar* code = (UChar*)(guest_code + delta); - /* Spot this: - C1C01D roll $29, %eax - C1C003 roll $3, %eax - C1C81B rorl $27, %eax - C1C805 rorl $5, %eax - C1C00D roll $13, %eax - C1C013 roll $19, %eax + /* Spot the 12-byte preamble: + C1C703 roll $3, %edi + C1C70D roll $13, %edi + C1C71D roll $29, %edi + C1C713 roll $19, %edi */ - if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D && - code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 && - code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B && - code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 && - code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D && - code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13 - ) { - DIP("%%edx = client_request ( %%eax )\n"); - delta += 18; - jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta); - dres.whatNext = Dis_StopHere; - goto decode_success; + if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 && + code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D && + code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D && + code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) { + /* Got a "Special" instruction preamble. Which one is it? */ + if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) { + /* %EDX = client_request ( %EAX ) */ + DIP("%%edx = client_request ( %%eax )\n"); + delta += 14; + jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta); + dres.whatNext = Dis_StopHere; + goto decode_success; + } + else + if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) { + /* %EAX = guest_NRADDR */ + DIP("%%eax = guest_NRADDR\n"); + delta += 14; + putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 )); + goto decode_success; + } + else + if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) { + /* call-noredir *%EAX */ + DIP("call-noredir *%%eax\n"); + delta += 14; + t1 = newTemp(Ity_I32); + assign(t1, getIReg(4,R_EAX)); + t2 = newTemp(Ity_I32); + assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4))); + putIReg(4, R_ESP, mkexpr(t2)); + storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta)); + jmp_treg(Ijk_NoRedir,t1); + dres.whatNext = Dis_StopHere; + goto decode_success; + } + /* We don't know what it is. */ + goto decode_failure; + /*NOTREACHED*/ } } + /* Deal with prefixes. */ /* Skip a LOCK prefix. */ /* 2005 Jan 06: the following insns are observed to sometimes have a LOCK prefix: diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index acc5a116df..44fa0c573a 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -2620,6 +2620,9 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i, case Ijk_TInval: *p++ = 0xBD; p = emit32(p, VEX_TRC_JMP_TINVAL); break; + case Ijk_NoRedir: + *p++ = 0xBD; + p = emit32(p, VEX_TRC_JMP_NOREDIR); break; case Ijk_Ret: case Ijk_Call: case Ijk_Boring: diff --git a/VEX/priv/host-ppc/hdefs.c b/VEX/priv/host-ppc/hdefs.c index e707be2818..066ba2631f 100644 --- a/VEX/priv/host-ppc/hdefs.c +++ b/VEX/priv/host-ppc/hdefs.c @@ -2942,6 +2942,7 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i, case Ijk_MapFail: trc = VEX_TRC_JMP_MAPFAIL; break; case Ijk_NoDecode: trc = VEX_TRC_JMP_NODECODE; break; case Ijk_TInval: trc = VEX_TRC_JMP_TINVAL; break; + case Ijk_NoRedir: trc = VEX_TRC_JMP_NOREDIR; break; case Ijk_Ret: case Ijk_Call: case Ijk_Boring: diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index f1a67b8fc6..a53a8c2a75 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -2179,6 +2179,9 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i, case Ijk_TInval: *p++ = 0xBD; p = emit32(p, VEX_TRC_JMP_TINVAL); break; + case Ijk_NoRedir: + *p++ = 0xBD; + p = emit32(p, VEX_TRC_JMP_NOREDIR); break; case Ijk_Sys_sysenter: *p++ = 0xBD; p = emit32(p, VEX_TRC_JMP_SYS_SYSENTER); break; diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index a649052593..c04b7da4a5 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -684,6 +684,7 @@ void ppIRJumpKind ( IRJumpKind kind ) case Ijk_NoDecode: vex_printf("NoDecode"); break; case Ijk_MapFail: vex_printf("MapFail"); break; case Ijk_TInval: vex_printf("Invalidate"); break; + case Ijk_NoRedir: vex_printf("NoRedir"); break; case Ijk_Sys_syscall: vex_printf("Sys_syscall"); break; case Ijk_Sys_int32: vex_printf("Sys_int32"); break; case Ijk_Sys_int128: vex_printf("Sys_int128"); break; diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index b649bb04db..a2986d3ac5 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -200,7 +200,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) HInstrArray* vcode; HInstrArray* rcode; Int i, j, k, out_used, guest_sizeB; - Int offB_TISTART, offB_TILEN; + Int offB_TISTART, offB_TILEN, offB_NRADDR; UChar insn_bytes[32]; IRType guest_word_type; IRType host_word_type; @@ -226,6 +226,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) offB_TISTART = 0; offB_TILEN = 0; mode64 = False; + offB_NRADDR = 0; vex_traceflags = vta->traceflags; @@ -335,12 +336,14 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) guest_layout = &x86guest_layout; offB_TISTART = offsetof(VexGuestX86State,guest_TISTART); offB_TILEN = offsetof(VexGuestX86State,guest_TILEN); + offB_NRADDR = offsetof(VexGuestX86State,guest_NRADDR); vassert(vta->archinfo_guest.subarch == VexSubArchX86_sse0 || vta->archinfo_guest.subarch == VexSubArchX86_sse1 || vta->archinfo_guest.subarch == VexSubArchX86_sse2); vassert(0 == sizeof(VexGuestX86State) % 8); - vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART ) == 4); - vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN ) == 4); + vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART) == 4); + vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN ) == 4); + vassert(sizeof( ((VexGuestX86State*)0)->guest_NRADDR ) == 4); break; case VexArchAMD64: @@ -352,10 +355,12 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) guest_layout = &amd64guest_layout; offB_TISTART = offsetof(VexGuestAMD64State,guest_TISTART); offB_TILEN = offsetof(VexGuestAMD64State,guest_TILEN); + offB_NRADDR = offsetof(VexGuestAMD64State,guest_NRADDR); vassert(vta->archinfo_guest.subarch == VexSubArch_NONE); vassert(0 == sizeof(VexGuestAMD64State) % 8); vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TISTART ) == 8); - vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN ) == 8); + vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN ) == 8); + vassert(sizeof( ((VexGuestAMD64State*)0)->guest_NRADDR ) == 8); break; case VexArchARM: @@ -367,6 +372,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) guest_layout = &armGuest_layout; offB_TISTART = 0; /* hack ... arm has bitrot */ offB_TILEN = 0; /* hack ... arm has bitrot */ + offB_NRADDR = 0; /* hack ... arm has bitrot */ vassert(vta->archinfo_guest.subarch == VexSubArchARM_v4); break; @@ -379,12 +385,14 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) guest_layout = &ppc32Guest_layout; offB_TISTART = offsetof(VexGuestPPC32State,guest_TISTART); offB_TILEN = offsetof(VexGuestPPC32State,guest_TILEN); + offB_NRADDR = offsetof(VexGuestPPC32State,guest_NRADDR); vassert(vta->archinfo_guest.subarch == VexSubArchPPC32_I || vta->archinfo_guest.subarch == VexSubArchPPC32_FI || vta->archinfo_guest.subarch == VexSubArchPPC32_VFI); vassert(0 == sizeof(VexGuestPPC32State) % 8); vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TISTART ) == 4); - vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN ) == 4); + vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN ) == 4); + vassert(sizeof( ((VexGuestPPC32State*)0)->guest_NRADDR ) == 4); break; case VexArchPPC64: @@ -426,13 +434,16 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta ) disInstrFn, vta->guest_bytes, vta->guest_bytes_addr, + vta->guest_bytes_addr_noredir, vta->chase_into_ok, host_is_bigendian, &vta->archinfo_guest, guest_word_type, vta->do_self_check, + vta->do_set_NRADDR, offB_TISTART, - offB_TILEN ); + offB_TILEN, + offB_NRADDR ); vexAllocSanityCheck(); diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 5fb9718cca..73eeb2bf13 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -345,6 +345,9 @@ typedef /* IN: should this translation be self-checking? default: False */ Bool do_self_check; + /* IN: should this translation set guest_NRADDR? */ + Bool do_set_NRADDR; + /* IN: debug: trace vex activity at various points */ Int traceflags; @@ -383,7 +386,6 @@ typedef extern VexTranslateResult LibVEX_Translate ( VexTranslateArgs* ); - /* A subtlety re interaction between self-checking translations and bb-chasing. The supplied chase_into_ok function should say NO (False) when presented with any address for which you might want to @@ -456,11 +458,19 @@ extern void LibVEX_ShowStats ( void ); ALL GUEST ARCHITECTURES ~~~~~~~~~~~~~~~~~~~~~~~ - The architecture must contain two pseudo-registers, guest_TISTART + The guest state must contain two pseudo-registers, guest_TISTART and guest_TILEN. These are used to pass the address of areas of guest code, translations of which are to be invalidated, back to the despatcher. Both pseudo-regs must have size equal to the guest word size. + + The architecture must a third pseudo-register, guest_NRADDR, also + guest-word-sized. This is used to record the unredirected guest + address at the start of a translation whose start has been + redirected. By reading this pseudo-register shortly afterwards, + the translation can find out what the corresponding no-redirection + address was. Note, this is only set for wrap-style redirects, not + for replace-style ones. */ #endif /* ndef __LIBVEX_H */ diff --git a/VEX/pub/libvex_guest_amd64.h b/VEX/pub/libvex_guest_amd64.h index 88c83547d7..785e3560b5 100644 --- a/VEX/pub/libvex_guest_amd64.h +++ b/VEX/pub/libvex_guest_amd64.h @@ -145,6 +145,14 @@ typedef ULong guest_TISTART; ULong guest_TILEN; + /* Used to record the unredirected guest address at the start of + a translation whose start has been redirected. By reading + this pseudo-register shortly afterwards, the translation can + find out what the corresponding no-redirection address was. + Note, this is only set for wrap-style redirects, not for + replace-style ones. */ + ULong guest_NRADDR; + /* Padding to make it have an 8-aligned size */ /* UInt padding; */ } diff --git a/VEX/pub/libvex_guest_ppc32.h b/VEX/pub/libvex_guest_ppc32.h index b9df3569cd..7fc41f631e 100644 --- a/VEX/pub/libvex_guest_ppc32.h +++ b/VEX/pub/libvex_guest_ppc32.h @@ -199,13 +199,21 @@ typedef /* Emulation warnings */ /* 940 */ UInt guest_EMWARN; - /* For icbi: record start and length of area to invalidate */ - /* 944 */ UInt guest_TISTART; - /* 948 */ UInt guest_TILEN; - /* For lwarx/stwcx.: 0 == no reservation exists, non-0 == a reservation exists. */ - /* 952 */ UInt guest_RESVN; + /* 944 */ UInt guest_RESVN; + + /* For icbi: record start and length of area to invalidate */ + /* 948 */ UInt guest_TISTART; + /* 952 */ UInt guest_TILEN; + + /* Used to record the unredirected guest address at the start of + a translation whose start has been redirected. By reading + this pseudo-register shortly afterwards, the translation can + find out what the corresponding no-redirection address was. + Note, this is only set for wrap-style redirects, not for + replace-style ones. */ + /* 956 */ UInt guest_NRADDR; /* Padding to make it have an 8-aligned size */ /* 956 */ UInt padding; diff --git a/VEX/pub/libvex_guest_ppc64.h b/VEX/pub/libvex_guest_ppc64.h index c03b74bf06..eee7094e2a 100644 --- a/VEX/pub/libvex_guest_ppc64.h +++ b/VEX/pub/libvex_guest_ppc64.h @@ -248,9 +248,16 @@ typedef reservation exists. */ /* 1104 */ ULong guest_RESVN; - /* Padding to make it have an 16-aligned size */ - /* 1112 */ ULong padding2; - /* 1120 */ + /* Used to record the unredirected guest address at the start of + a translation whose start has been redirected. By reading + this pseudo-register shortly afterwards, the translation can + find out what the corresponding no-redirection address was. + Note, this is only set for wrap-style redirects, not for + replace-style ones. */ + /* 1112 */ ULong guest_NRADDR; + + /* Padding to make it have an 8-aligned size */ + /* UInt padding; */ } VexGuestPPC64State; diff --git a/VEX/pub/libvex_guest_x86.h b/VEX/pub/libvex_guest_x86.h index fd98627592..e78afd3bda 100644 --- a/VEX/pub/libvex_guest_x86.h +++ b/VEX/pub/libvex_guest_x86.h @@ -208,18 +208,20 @@ typedef /* Emulation warnings */ UInt guest_EMWARN; - /* Translation-invalidation area description. Not used on x86 - (there is no invalidate-icache insn), but needed so as to - allow users of the library to uniformly assume that the guest - state contains these two fields -- otherwise there is - compilation breakage. On x86, these two fields are set to - zero by LibVEX_GuestX86_initialise and then should be ignored - forever thereafter. */ + /* For clflush: record start and length of area to invalidate */ UInt guest_TISTART; UInt guest_TILEN; + /* Used to record the unredirected guest address at the start of + a translation whose start has been redirected. By reading + this pseudo-register shortly afterwards, the translation can + find out what the corresponding no-redirection address was. + Note, this is only set for wrap-style redirects, not for + replace-style ones. */ + UInt guest_NRADDR; + /* Padding to make it have an 8-aligned size */ - /* UInt padding; */ + UInt padding; } VexGuestX86State; diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index e9cf28e2aa..130a4fe13e 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -855,6 +855,7 @@ typedef Ijk_NoDecode, /* next instruction cannot be decoded */ Ijk_MapFail, /* Vex-provided address translation failed */ Ijk_TInval, /* Invalidate translations before continuing. */ + Ijk_NoRedir, /* Jump to un-redirected guest addr */ /* Unfortunately, various guest-dependent syscall kinds. They all mean: do a syscall before continuing. */ Ijk_Sys_syscall, /* amd64 'syscall', ppc 'sc' */ diff --git a/VEX/pub/libvex_trc_values.h b/VEX/pub/libvex_trc_values.h index 757ceead25..ccba4e3cbf 100644 --- a/VEX/pub/libvex_trc_values.h +++ b/VEX/pub/libvex_trc_values.h @@ -58,6 +58,7 @@ #define VEX_TRC_JMP_TINVAL 61 /* invalidate translations before continuing */ +#define VEX_TRC_JMP_NOREDIR 81 /* jump to undirected guest addr */ #define VEX_TRC_JMP_EMWARN 63 /* deliver emulation warning before continuing */ #define VEX_TRC_JMP_CLIENTREQ 65 /* do a client req before continuing */ diff --git a/VEX/test_main.c b/VEX/test_main.c index a2a63aac41..ddc0bb14b9 100644 --- a/VEX/test_main.c +++ b/VEX/test_main.c @@ -174,6 +174,7 @@ int main ( int argc, char** argv ) vta.instrument2 = NULL; #endif vta.do_self_check = False; + vta.do_set_NRADDR = False; vta.traceflags = TEST_FLAGS; #if 1 /* x86, amd64 hosts */ vta.dispatch = (void*)0x12345678;