From: Julian Seward Date: Wed, 19 Jan 2005 11:49:45 +0000 (+0000) Subject: Proper support for translation cache management: when a translation is X-Git-Tag: svn/VALGRIND_3_0_1^2~614 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab71110bd42a67dd3ec2720e999a2c7487779356;p=thirdparty%2Fvalgrind.git Proper support for translation cache management: when a translation is made, record precisely the areas of guest address space from which the translation was made. This is needed to be sure we can later discard translations accurately. The new info is record in a structure called VexGuestExtents. git-svn-id: svn://svn.valgrind.org/vex/trunk@720 --- diff --git a/VEX/priv/guest-arm/gdefs.h b/VEX/priv/guest-arm/gdefs.h index 2d74e908b7..7377fcf827 100644 --- a/VEX/priv/guest-arm/gdefs.h +++ b/VEX/priv/guest-arm/gdefs.h @@ -45,13 +45,13 @@ /*---------------------------------------------------------*/ extern -IRBB* bbToIR_ARM ( UChar* armCode, - Addr64 eip, - Int* guest_bytes_read, - Bool (*byte_accessible)(Addr64), - Bool (*resteerOkFn)(Addr64), - Bool host_bigendian, - VexSubArch subarch_guest ); +IRBB* bbToIR_ARM ( UChar* armCode, + Addr64 eip, + VexGuestExtents* vge, + Bool (*byte_accessible)(Addr64), + Bool (*resteerOkFn)(Addr64), + Bool host_bigendian, + VexSubArch subarch_guest ); /* Used by the optimiser to specialise calls to helpers. */ extern diff --git a/VEX/priv/guest-arm/toIR.c b/VEX/priv/guest-arm/toIR.c index e48361f844..f107fd4ba3 100644 --- a/VEX/priv/guest-arm/toIR.c +++ b/VEX/priv/guest-arm/toIR.c @@ -161,13 +161,13 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, dumping the IR into global irbb. Returns the size, in bytes, of the basic block. */ -IRBB* bbToIR_ARM ( UChar* armCode, - Addr64 guest_pc_start, - Int* guest_bytes_read, - Bool (*byte_accessible)(Addr64), - Bool (*chase_into_ok)(Addr64), - Bool host_bigendian, - VexSubArch subarch_guest ) +IRBB* bbToIR_ARM ( UChar* armCode, + Addr64 guest_pc_start, + VexGuestExtents* vge, + Bool (*byte_accessible)(Addr64), + Bool (*chase_into_ok)(Addr64), + Bool host_bigendian, + VexSubArch subarch_guest ) { UInt delta; Int i, n_instrs, size, first_stmt_idx; @@ -179,12 +179,17 @@ IRBB* bbToIR_ARM ( UChar* armCode, /* check sanity .. */ vassert(vex_control.guest_max_insns >= 1); - vassert(vex_control.guest_max_insns < 1000); + vassert(vex_control.guest_max_insns < 500); vassert(vex_control.guest_chase_thresh >= 0); vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns); vassert(subarch_guest == VexSubArchARM_v4); + /* Start a new, empty extent. */ + vge->n_used = 1; + vge->base[0] = guest_pc_start; + vge->len[0] = 0; + /* Set up globals. */ host_is_bigendian = host_bigendian; guest_code = armCode; @@ -197,7 +202,6 @@ IRBB* bbToIR_ARM ( UChar* armCode, have so far gone. */ delta = 0; n_instrs = 0; - *guest_bytes_read = 0; while (True) { vassert(n_instrs < vex_control.guest_max_insns); @@ -237,7 +241,7 @@ IRBB* bbToIR_ARM ( UChar* armCode, } delta += size; - *guest_bytes_read += size; + vge->len[vge->n_used-1] += size; n_instrs++; DIP("\n"); @@ -261,6 +265,8 @@ IRBB* bbToIR_ARM ( UChar* armCode, vassert(irbb->next != NULL); return irbb; case Dis_Resteer: + vpanic("bbToIR_ARM: Dis_Resteer: fixme"); + /* need to add code here to start a new extent ... */ vassert(irbb->next == NULL); /* figure out a new delta to continue at. */ vassert(chase_into_ok(guest_next)); @@ -279,7 +285,7 @@ IRBB* bbToIR_ARM ( UChar* armCode, /*------------------------------------------------------------*/ /*--- Helper bits and pieces for deconstructing the ---*/ -/*--- x86 insn stream. ---*/ +/*--- ARM insn stream. ---*/ /*------------------------------------------------------------*/ /* Add a statement to the list held by "irbb". */ diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 7d3312a669..deb5e61175 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -47,13 +47,13 @@ /*---------------------------------------------------------*/ extern -IRBB* bbToIR_X86 ( UChar* x86code, - Addr64 eip, - Int* guest_bytes_read, - Bool (*byte_accessible)(Addr64), - Bool (*resteerOkFn)(Addr64), - Bool host_bigendian, - VexSubArch subarch_guest ); +IRBB* bbToIR_X86 ( UChar* x86code, + Addr64 eip, + VexGuestExtents* vge, + Bool (*byte_accessible)(Addr64), + Bool (*resteerOkFn)(Addr64), + Bool host_bigendian, + VexSubArch subarch_guest ); /* Used by the optimiser to specialise calls to helpers. */ extern diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 004bdf849d..0bac7382b3 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -227,13 +227,13 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, /* Disassemble a complete basic block, starting at eip, and dumping the ucode into cb. Returns the size, in bytes, of the basic block. */ -IRBB* bbToIR_X86 ( UChar* x86code, - Addr64 guest_eip_start, - Int* guest_bytes_read, - Bool (*byte_accessible)(Addr64), - Bool (*chase_into_ok)(Addr64), - Bool host_bigendian, - VexSubArch subarch_guest ) +IRBB* bbToIR_X86 ( UChar* x86code, + Addr64 guest_eip_start, + VexGuestExtents* vge, + Bool (*byte_accessible)(Addr64), + Bool (*chase_into_ok)(Addr64), + Bool host_bigendian, + VexSubArch subarch_guest ) { UInt delta; Int i, n_instrs, size, first_stmt_idx; @@ -245,7 +245,7 @@ IRBB* bbToIR_X86 ( UChar* x86code, /* check sanity .. */ vassert(vex_control.guest_max_insns >= 1); - vassert(vex_control.guest_max_insns < 1000); + vassert(vex_control.guest_max_insns < 500); vassert(vex_control.guest_chase_thresh >= 0); vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns); @@ -255,6 +255,11 @@ IRBB* bbToIR_X86 ( UChar* x86code, vassert((guest_eip_start >> 32) == 0); + /* Start a new, empty extent. */ + vge->n_used = 1; + vge->base[0] = guest_eip_start; + vge->len[0] = 0; + /* Set up globals. */ host_is_bigendian = host_bigendian; guest_code = x86code; @@ -266,13 +271,17 @@ IRBB* bbToIR_X86 ( UChar* x86code, have so far gone. */ delta = 0; n_instrs = 0; - *guest_bytes_read = 0; while (True) { vassert(n_instrs < vex_control.guest_max_insns); guest_next = 0; - resteerOK = n_instrs < vex_control.guest_chase_thresh; + resteerOK + = n_instrs < vex_control.guest_chase_thresh + /* we can't afford to have a resteer once we're on the last + extent slot. */ + && vge->n_used < 3; + first_stmt_idx = irbb->stmts_used; if (n_instrs > 0) { @@ -309,7 +318,7 @@ IRBB* bbToIR_X86 ( UChar* x86code, } delta += size; - *guest_bytes_read += size; + vge->len[vge->n_used-1] += size; n_instrs++; DIP("\n"); @@ -337,6 +346,11 @@ IRBB* bbToIR_X86 ( UChar* x86code, /* figure out a new delta to continue at. */ vassert(chase_into_ok(guest_next)); delta = (UInt)(guest_next - guest_eip_start); + /* we now have to start a new extent slot. */ + vge->n_used++; + vassert(vge->n_used <= 3); + vge->base[vge->n_used-1] = guest_next; + vge->len[vge->n_used-1] = 0; n_resteers++; d_resteers++; if (0 && (n_resteers & 0xFF) == 0) diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index 9cacd13381..c8feac46d3 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -164,8 +164,8 @@ VexTranslateResult LibVEX_Translate ( UChar* guest_bytes, Addr64 guest_bytes_addr, Bool (*chase_into_ok) ( Addr64 ), - /* OUT: the number of bytes actually read */ - Int* guest_bytes_read, + /* OUT: which bits of guest code actually got translated */ + VexGuestExtents* guest_extents, /* IN: a place to put the resulting code, and its size */ UChar* host_bytes, Int host_bytes_size, @@ -194,9 +194,11 @@ VexTranslateResult LibVEX_Translate ( void (*ppInstr) ( HInstr* ); void (*ppReg) ( HReg ); HInstrArray* (*iselBB) ( IRBB*, VexSubArch ); - IRBB* (*bbToIR) ( UChar*, Addr64, Int*, + IRBB* (*bbToIR) ( UChar*, Addr64, + VexGuestExtents*, Bool(*)(Addr64), - Bool(*)(Addr64), Bool, VexSubArch ); + Bool(*)(Addr64), + Bool, VexSubArch ); Int (*emit) ( UChar*, Int, HInstr* ); IRExpr* (*specHelper) ( Char*, IRExpr** ); Bool (*preciseMemExnsFn) ( Int, Int ); @@ -252,7 +254,7 @@ VexTranslateResult LibVEX_Translate ( ppReg = (void(*)(HReg)) ppHRegX86; iselBB = iselBB_X86; emit = (Int(*)(UChar*,Int,HInstr*)) emit_X86Instr; - host_is_bigendian = False; + host_is_bigendian = False; host_word_type = Ity_I32; vassert(subarch_host == VexSubArchX86_sse0 || subarch_host == VexSubArchX86_sse1 @@ -305,11 +307,11 @@ VexTranslateResult LibVEX_Translate ( "------------------------\n\n"); irbb = bbToIR ( guest_bytes, - guest_bytes_addr, - guest_bytes_read, - byte_accessible, + guest_bytes_addr, + guest_extents, + byte_accessible, chase_into_ok, - host_is_bigendian, + host_is_bigendian, subarch_guest ); if (irbb == NULL) { @@ -319,13 +321,25 @@ VexTranslateResult LibVEX_Translate ( return VexTransAccessFail; } + vassert(guest_extents->n_used >= 1 && guest_extents->n_used <= 3); + vassert(guest_extents->base[0] == guest_bytes_addr); + for (i = 0; i < guest_extents->n_used; i++) { + vassert(guest_extents->len[i] < 10000); /* sanity */ + } + /* If debugging, show the raw guest bytes for this bb. */ if (0 || (vex_traceflags & VEX_TRACE_FE)) { - UChar* p = guest_bytes; - vex_printf(". 0 %llx %d\n.", guest_bytes_addr, *guest_bytes_read ); - for (i = 0; i < *guest_bytes_read; i++) + if (guest_extents->n_used > 1) { + vex_printf("can't show code due to extents > 1\n"); + } else { + /* HACK */ + UChar* p = (UChar*)guest_bytes; + UInt guest_bytes_read = (UInt)guest_extents->len[0]; + vex_printf(". 0 %llx %d\n.", guest_bytes_addr, guest_bytes_read ); + for (i = 0; i < guest_bytes_read; i++) vex_printf(" %02x", (Int)p[i] ); - vex_printf("\n\n"); + vex_printf("\n\n"); + } } /* Sanity check the initial IR. */ @@ -414,10 +428,10 @@ VexTranslateResult LibVEX_Translate ( /* Register allocate. */ rcode = doRegisterAllocation ( vcode, available_real_regs, - n_available_real_regs, - isMove, getRegUsage, mapRegs, - genSpill, genReload, guest_sizeB, - ppInstr, ppReg ); + n_available_real_regs, + isMove, getRegUsage, mapRegs, + genSpill, genReload, guest_sizeB, + ppInstr, ppReg ); if (vex_traceflags & VEX_TRACE_RCODE) { vex_printf("\n------------------------" @@ -447,7 +461,7 @@ VexTranslateResult LibVEX_Translate ( j = (*emit)( insn_bytes, 32, rcode->arr[i] ); if (vex_traceflags & VEX_TRACE_ASM) { for (k = 0; k < j; k++) - if (insn_bytes[k] < 16) + if (insn_bytes[k] < 16) vex_printf("0%x ", (UInt)insn_bytes[k]); else vex_printf("%x ", (UInt)insn_bytes[k]); diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 84960e82ff..ead8076b4d 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -214,6 +214,7 @@ extern void LibVEX_Init ( /*--- Make a translation ---*/ /*-------------------------------------------------------*/ +/* Describes the outcome of a translation attempt. */ typedef enum { VexTransOK, @@ -222,6 +223,24 @@ typedef } VexTranslateResult; + +/* Describes precisely the pieces of guest code that a translation + covers. Now that Vex can chase across BB boundaries, the old + scheme of describing a chunk of guest code merely by its start + address and length is inadequate. + + Hopefully this struct is only 32 bytes long. Space is important as + clients will have to store one of these for each translation made. +*/ +typedef + struct { + Addr64 base[3]; + UShort len[3]; + UShort n_used; + } + VexGuestExtents; + + extern VexTranslateResult LibVEX_Translate ( /* The instruction sets we are translating from and to. */ @@ -233,8 +252,8 @@ VexTranslateResult LibVEX_Translate ( UChar* guest_bytes, Addr64 guest_bytes_addr, Bool (*chase_into_ok) ( Addr64 ), - /* OUT: the number of bytes actually read */ - Int* guest_bytes_read, + /* OUT: which bits of guest code actually got translated */ + VexGuestExtents* guest_extents, /* IN: a place to put the resulting code, and its size */ UChar* host_bytes, Int host_bytes_size, diff --git a/VEX/test_main.c b/VEX/test_main.c index c588551432..68869a1e09 100644 --- a/VEX/test_main.c +++ b/VEX/test_main.c @@ -60,9 +60,10 @@ int main ( int argc, char** argv ) UInt u, sum; Addr32 orig_addr; Int bb_number, n_bbs_done = 0; - Int orig_nbytes, trans_used, orig_used; + Int orig_nbytes, trans_used; VexTranslateResult tres; VexControl vcon; + VexGuestExtents vge; if (argc != 2) { fprintf(stderr, "usage: vex file.org\n"); @@ -124,7 +125,7 @@ int main ( int argc, char** argv ) VexArchX86, VexSubArchX86_sse2, VexArchX86, VexSubArchX86_sse2, origbuf, (Addr64)orig_addr, chase_into_not_ok, - &orig_used, + &vge, transbuf, N_TRANSBUF, &trans_used, #if 1 /* no instrumentation */ NULL, /* instrument1 */ @@ -148,12 +149,13 @@ int main ( int argc, char** argv ) if (tres != VexTransOK) printf("\ntres = %d\n", (Int)tres); assert(tres == VexTransOK); - assert(orig_used == orig_nbytes); + assert(vge.n_used == 1); + assert((UInt)(vge.len[0]) == orig_nbytes); sum = 0; for (i = 0; i < trans_used; i++) sum += (UInt)transbuf[i]; - printf ( " %6.2f ... %d\n", (double)trans_used / (double)orig_used, sum ); + printf ( " %6.2f ... %d\n", (double)trans_used / (double)vge.len[0], sum ); } fclose(f);