mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 18:56:10 +00:00
the size of VexGuestExtent to 20 bytes on a 32-bit platform. Change prototypes of x86g_dirtyhelper_loadF80le and x86g_dirtyhelper_storeF80le to give the address in the parameter list type Addr. Likewise for amd64g_dirtyhelper_loadF80le and amd64g_dirtyhelper_storeF80le. Update switchback.c - but not tested. git-svn-id: svn://svn.valgrind.org/vex/trunk@3056
807 lines
24 KiB
C
807 lines
24 KiB
C
|
|
/* HOW TO USE
|
|
|
|
13 Dec '05 - Linker no longer used (apart from mymalloc)
|
|
Simply compile and link switchback.c with test_xxx.c,
|
|
e.g. for ppc64:
|
|
$ (cd .. && make EXTRA_CFLAGS="-m64" libvex_ppc64_linux.a) && gcc -m64 -mregnames -Wall -Wshadow -Wno-long-long -Winline -O -g -o switchback switchback.c linker.c ../libvex_ppc64_linux.a test_xxx.c
|
|
|
|
Test file test_xxx.c must have an entry point called "entry",
|
|
which expects to take a single argument which is a function pointer
|
|
(to "serviceFn").
|
|
|
|
Test file may not reference any other symbols.
|
|
|
|
NOTE: POWERPC: it is critical, when using this on ppc, to set
|
|
CacheLineSize to the right value. Values we currently know of:
|
|
|
|
imac (G3): 32
|
|
G5 (ppc970): 128
|
|
|
|
ARM64:
|
|
(cd .. && make -f Makefile-gcc libvex-arm64-linux.a) \
|
|
&& $CC -Wall -O -g -o switchback switchback.c linker.c \
|
|
../libvex-arm64-linux.a test_emfloat.c
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../pub/libvex_basictypes.h"
|
|
#include "../pub/libvex_guest_x86.h"
|
|
#include "../pub/libvex_guest_amd64.h"
|
|
#include "../pub/libvex_guest_ppc32.h"
|
|
#include "../pub/libvex_guest_ppc64.h"
|
|
#include "../pub/libvex_guest_arm64.h"
|
|
#include "../pub/libvex.h"
|
|
#include "../pub/libvex_trc_values.h"
|
|
#include "linker.h"
|
|
|
|
static ULong n_bbs_done = 0;
|
|
static Int n_translations_made = 0;
|
|
|
|
|
|
#if defined(__i386__)
|
|
# define VexGuestState VexGuestX86State
|
|
# define LibVEX_Guest_initialise LibVEX_GuestX86_initialise
|
|
# define VexArch VexArchX86
|
|
# define VexSubArch VexSubArchX86_sse1
|
|
# define GuestPC guest_EIP
|
|
# define CacheLineSize 0/*irrelevant*/
|
|
|
|
#elif defined(__aarch64__) && !defined(__arm__)
|
|
# define VexGuestState VexGuestARM64State
|
|
# define LibVEX_Guest_initialise LibVEX_GuestARM64_initialise
|
|
# define VexArch VexArchARM64
|
|
# define VexSubArch VexSubArch_NONE
|
|
# define GuestPC guest_PC
|
|
# define CacheLineSize 0/*irrelevant*/
|
|
|
|
#else
|
|
# error "Unknown arch"
|
|
#endif
|
|
|
|
/* 7: show conversion into IR */
|
|
/* 6: show after initial opt */
|
|
/* 5: show after instrumentation */
|
|
/* 4: show after second opt */
|
|
/* 3: show after tree building */
|
|
/* 2: show selected insns */
|
|
/* 1: show after reg-alloc */
|
|
/* 0: show final assembly */
|
|
#define TEST_FLAGS ((1<<7)|(1<<3)|(1<<2)|(1<<1)|(1<<0))
|
|
#define DEBUG_TRACE_FLAGS ((0<<7)|(0<<6)|(0<<5)|(0<<4)| \
|
|
(0<<3)|(0<<2)|(0<<1)|(0<<0))
|
|
|
|
typedef unsigned long int Addr;
|
|
|
|
|
|
/* guest state */
|
|
ULong gstack[64000] __attribute__((aligned(16)));
|
|
VexGuestState gst;
|
|
VexControl vcon;
|
|
|
|
/* only used for the switchback transition */
|
|
/* i386: helper1 = &gst, helper2 = %EFLAGS */
|
|
/* amd64: helper1 = &gst, helper2 = %EFLAGS */
|
|
/* ppc32: helper1 = &gst, helper2 = %CR, helper3 = %XER */
|
|
/* arm64: helper1 = &gst, helper2 = 32x0:NZCV:28x0 */
|
|
HWord sb_helper1 = 0;
|
|
HWord sb_helper2 = 0;
|
|
HWord sb_helper3 = 0;
|
|
|
|
/* translation cache */
|
|
#define N_TRANS_CACHE 1000000
|
|
#define N_TRANS_TABLE 10000
|
|
|
|
ULong trans_cache[N_TRANS_CACHE];
|
|
VexGuestExtents trans_table [N_TRANS_TABLE];
|
|
ULong* trans_tableP[N_TRANS_TABLE];
|
|
|
|
Int trans_cache_used = 0;
|
|
Int trans_table_used = 0;
|
|
|
|
static Bool chase_into_ok ( void* opaque, Addr64 dst ) {
|
|
return False;
|
|
}
|
|
|
|
static UInt needs_self_check ( void* opaque, const VexGuestExtents* vge ) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* For providing services. */
|
|
static HWord serviceFn ( HWord arg1, HWord arg2 )
|
|
{
|
|
switch (arg1) {
|
|
case 0: /* EXIT */
|
|
printf("---STOP---\n");
|
|
printf("serviceFn:EXIT\n");
|
|
printf("%llu bbs simulated\n", n_bbs_done);
|
|
printf("%d translations made, %d tt bytes\n",
|
|
n_translations_made, 8*trans_cache_used);
|
|
exit(0);
|
|
case 1: /* PUTC */
|
|
putchar(arg2);
|
|
return 0;
|
|
case 2: /* MALLOC */
|
|
return (HWord)malloc(arg2);
|
|
case 3: /* FREE */
|
|
free((void*)arg2);
|
|
return 0;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
|
|
// needed for arm64 ?
|
|
static void invalidate_icache(void *ptr, unsigned long nbytes)
|
|
{
|
|
// This function, invalidate_icache, for arm64_linux,
|
|
// is copied from
|
|
// https://github.com/armvixl/vixl/blob/master/src/a64/cpu-a64.cc
|
|
// which has the following copyright notice:
|
|
/*
|
|
Copyright 2013, ARM Limited
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Neither the name of ARM Limited nor the names of its contributors may be
|
|
used to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// Ask what the I and D line sizes are
|
|
UInt cache_type_register;
|
|
// Copy the content of the cache type register to a core register.
|
|
__asm__ __volatile__ ("mrs %[ctr], ctr_el0" // NOLINT
|
|
: [ctr] "=r" (cache_type_register));
|
|
|
|
const Int kDCacheLineSizeShift = 16;
|
|
const Int kICacheLineSizeShift = 0;
|
|
const UInt kDCacheLineSizeMask = 0xf << kDCacheLineSizeShift;
|
|
const UInt kICacheLineSizeMask = 0xf << kICacheLineSizeShift;
|
|
|
|
// The cache type register holds the size of the I and D caches as a power of
|
|
// two.
|
|
const UInt dcache_line_size_power_of_two =
|
|
(cache_type_register & kDCacheLineSizeMask) >> kDCacheLineSizeShift;
|
|
const UInt icache_line_size_power_of_two =
|
|
(cache_type_register & kICacheLineSizeMask) >> kICacheLineSizeShift;
|
|
|
|
const UInt dcache_line_size_ = 1 << dcache_line_size_power_of_two;
|
|
const UInt icache_line_size_ = 1 << icache_line_size_power_of_two;
|
|
|
|
Addr start = (Addr)ptr;
|
|
// Sizes will be used to generate a mask big enough to cover a pointer.
|
|
Addr dsize = (Addr)dcache_line_size_;
|
|
Addr isize = (Addr)icache_line_size_;
|
|
|
|
// Cache line sizes are always a power of 2.
|
|
Addr dstart = start & ~(dsize - 1);
|
|
Addr istart = start & ~(isize - 1);
|
|
Addr end = start + nbytes;
|
|
|
|
__asm__ __volatile__ (
|
|
// Clean every line of the D cache containing the target data.
|
|
"0: \n\t"
|
|
// dc : Data Cache maintenance
|
|
// c : Clean
|
|
// va : by (Virtual) Address
|
|
// u : to the point of Unification
|
|
// The point of unification for a processor is the point by which the
|
|
// instruction and data caches are guaranteed to see the same copy of a
|
|
// memory location. See ARM DDI 0406B page B2-12 for more information.
|
|
"dc cvau, %[dline] \n\t"
|
|
"add %[dline], %[dline], %[dsize] \n\t"
|
|
"cmp %[dline], %[end] \n\t"
|
|
"b.lt 0b \n\t"
|
|
// Barrier to make sure the effect of the code above is visible to the rest
|
|
// of the world.
|
|
// dsb : Data Synchronisation Barrier
|
|
// ish : Inner SHareable domain
|
|
// The point of unification for an Inner Shareable shareability domain is
|
|
// the point by which the instruction and data caches of all the processors
|
|
// in that Inner Shareable shareability domain are guaranteed to see the
|
|
// same copy of a memory location. See ARM DDI 0406B page B2-12 for more
|
|
// information.
|
|
"dsb ish \n\t"
|
|
// Invalidate every line of the I cache containing the target data.
|
|
"1: \n\t"
|
|
// ic : instruction cache maintenance
|
|
// i : invalidate
|
|
// va : by address
|
|
// u : to the point of unification
|
|
"ic ivau, %[iline] \n\t"
|
|
"add %[iline], %[iline], %[isize] \n\t"
|
|
"cmp %[iline], %[end] \n\t"
|
|
"b.lt 1b \n\t"
|
|
// Barrier to make sure the effect of the code above is visible to the rest
|
|
// of the world.
|
|
"dsb ish \n\t"
|
|
// Barrier to ensure any prefetching which happened before this code is
|
|
// discarded.
|
|
// isb : Instruction Synchronisation Barrier
|
|
"isb \n\t"
|
|
: [dline] "+r" (dstart),
|
|
[iline] "+r" (istart)
|
|
: [dsize] "r" (dsize),
|
|
[isize] "r" (isize),
|
|
[end] "r" (end)
|
|
// This code does not write to memory but without the dependency gcc might
|
|
// move this code before the code is generated.
|
|
: "cc", "memory"
|
|
);
|
|
|
|
}
|
|
|
|
|
|
/* -------------------- */
|
|
/* continue execution on the real CPU (never returns) */
|
|
|
|
#if defined(__i386__)
|
|
|
|
extern void switchback_asm(void);
|
|
asm(
|
|
"switchback_asm:\n"
|
|
" movl sb_helper1, %eax\n" // eax = guest state ptr
|
|
" movl 16(%eax), %esp\n" // switch stacks
|
|
" pushl 56(%eax)\n" // push continuation addr
|
|
" movl sb_helper2, %ebx\n" // get eflags
|
|
" pushl %ebx\n" // eflags:CA
|
|
" pushl 0(%eax)\n" // EAX:eflags:CA
|
|
" movl 4(%eax), %ecx\n"
|
|
" movl 8(%eax), %edx\n"
|
|
" movl 12(%eax), %ebx\n"
|
|
" movl 20(%eax), %ebp\n"
|
|
" movl 24(%eax), %esi\n"
|
|
" movl 28(%eax), %edi\n"
|
|
" popl %eax\n"
|
|
" popfl\n"
|
|
" ret\n"
|
|
);
|
|
void switchback ( void )
|
|
{
|
|
sb_helper1 = (HWord)&gst;
|
|
sb_helper2 = LibVEX_GuestX86_get_eflags(&gst);
|
|
switchback_asm(); // never returns
|
|
}
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
extern void switchback_asm(HWord x0_gst, HWord x1_pstate);
|
|
asm(
|
|
"switchback_asm:"
|
|
" mrs x30, nzcv" "\n"
|
|
" and x30, x30, #0xFFFFFFFF0FFFFFFF" "\n"
|
|
" and x1, x1, #0x00000000F0000000" "\n"
|
|
" orr x30, x30, x1" "\n"
|
|
" msr nzcv, x30" "\n"
|
|
|
|
" ldr x30, [x0, #16 + 8*37]" "\n"
|
|
" msr tpidr_el0, x30" "\n"
|
|
|
|
" ldr x30, [x0, #16 + 8*31]" "\n"
|
|
" mov sp, x30" "\n"
|
|
|
|
" add x30, x0, #(16 + 8*38 + 16*0)" "\n"
|
|
" ldr q0, [x30], #16" "\n"
|
|
" ldr q1, [x30], #16" "\n"
|
|
" ldr q2, [x30], #16" "\n"
|
|
" ldr q3, [x30], #16" "\n"
|
|
" ldr q4, [x30], #16" "\n"
|
|
" ldr q5, [x30], #16" "\n"
|
|
" ldr q6, [x30], #16" "\n"
|
|
" ldr q7, [x30], #16" "\n"
|
|
" ldr q8, [x30], #16" "\n"
|
|
" ldr q9, [x30], #16" "\n"
|
|
" ldr q10, [x30], #16" "\n"
|
|
" ldr q11, [x30], #16" "\n"
|
|
" ldr q12, [x30], #16" "\n"
|
|
" ldr q13, [x30], #16" "\n"
|
|
" ldr q14, [x30], #16" "\n"
|
|
" ldr q15, [x30], #16" "\n"
|
|
" ldr q16, [x30], #16" "\n"
|
|
" ldr q17, [x30], #16" "\n"
|
|
" ldr q18, [x30], #16" "\n"
|
|
" ldr q19, [x30], #16" "\n"
|
|
" ldr q20, [x30], #16" "\n"
|
|
" ldr q21, [x30], #16" "\n"
|
|
" ldr q22, [x30], #16" "\n"
|
|
" ldr q23, [x30], #16" "\n"
|
|
" ldr q24, [x30], #16" "\n"
|
|
" ldr q25, [x30], #16" "\n"
|
|
" ldr q26, [x30], #16" "\n"
|
|
" ldr q27, [x30], #16" "\n"
|
|
" ldr q28, [x30], #16" "\n"
|
|
" ldr q29, [x30], #16" "\n"
|
|
" ldr q30, [x30], #16" "\n"
|
|
" ldr q31, [x30], #16" "\n"
|
|
|
|
" ldr x30, [x0, #16+8*30]" "\n"
|
|
" ldr x29, [x0, #16+8*29]" "\n"
|
|
" ldr x28, [x0, #16+8*28]" "\n"
|
|
" ldr x27, [x0, #16+8*27]" "\n"
|
|
" ldr x26, [x0, #16+8*26]" "\n"
|
|
" ldr x25, [x0, #16+8*25]" "\n"
|
|
" ldr x24, [x0, #16+8*24]" "\n"
|
|
" ldr x23, [x0, #16+8*23]" "\n"
|
|
" ldr x22, [x0, #16+8*22]" "\n"
|
|
" ldr x21, [x0, #16+8*21]" "\n"
|
|
" ldr x20, [x0, #16+8*20]" "\n"
|
|
" ldr x19, [x0, #16+8*19]" "\n"
|
|
" ldr x18, [x0, #16+8*18]" "\n"
|
|
" ldr x17, [x0, #16+8*17]" "\n"
|
|
" ldr x16, [x0, #16+8*16]" "\n"
|
|
" ldr x15, [x0, #16+8*15]" "\n"
|
|
" ldr x14, [x0, #16+8*14]" "\n"
|
|
" ldr x13, [x0, #16+8*13]" "\n"
|
|
" ldr x12, [x0, #16+8*12]" "\n"
|
|
" ldr x11, [x0, #16+8*11]" "\n"
|
|
" ldr x10, [x0, #16+8*10]" "\n"
|
|
" ldr x9, [x0, #16+8*9]" "\n"
|
|
" ldr x8, [x0, #16+8*8]" "\n"
|
|
" ldr x7, [x0, #16+8*7]" "\n"
|
|
" ldr x6, [x0, #16+8*6]" "\n"
|
|
" ldr x5, [x0, #16+8*5]" "\n"
|
|
" ldr x4, [x0, #16+8*4]" "\n"
|
|
" ldr x3, [x0, #16+8*3]" "\n"
|
|
" ldr x2, [x0, #16+8*2]" "\n"
|
|
" ldr x1, [x0, #16+8*1]" "\n"
|
|
" ldr x0, [x0, #16+8*0]" "\n"
|
|
|
|
"nop_start_point:" "\n"
|
|
" nop" "\n" // this will be converted into a relative jump
|
|
"nop_end_point:" "\n"
|
|
);
|
|
|
|
extern void nop_start_point(void);
|
|
extern void nop_end_point(void);
|
|
|
|
void switchback ( void )
|
|
{
|
|
assert(offsetof(VexGuestARM64State, guest_X0) == 16 + 8*0);
|
|
assert(offsetof(VexGuestARM64State, guest_X30) == 16 + 8*30);
|
|
assert(offsetof(VexGuestARM64State, guest_SP) == 16 + 8*31);
|
|
assert(offsetof(VexGuestARM64State, guest_TPIDR_EL0) == 16 + 8*37);
|
|
assert(offsetof(VexGuestARM64State, guest_Q0) == 16 + 8*38 + 16*0);
|
|
|
|
HWord arg0 = (HWord)&gst;
|
|
HWord arg1 = LibVEX_GuestARM64_get_nzcv(&gst);
|
|
|
|
/* Copy the entire switchback_asm procedure into writable and
|
|
executable memory. */
|
|
|
|
UChar* sa_start = (UChar*)&switchback_asm;
|
|
UChar* sa_nop_start = (UChar*)&nop_start_point;
|
|
UChar* sa_end = (UChar*)&nop_end_point;
|
|
|
|
Int i;
|
|
Int nbytes = sa_end - sa_start;
|
|
Int off_nopstart = sa_nop_start - sa_start;
|
|
if (0)
|
|
printf("nbytes = %d, nopstart = %d\n", nbytes, off_nopstart);
|
|
|
|
/* copy it into mallocville */
|
|
UChar* copy = mymalloc(nbytes);
|
|
assert(copy);
|
|
for (i = 0; i < nbytes; i++)
|
|
copy[i] = sa_start[i];
|
|
|
|
UInt* p = (UInt*)(©[off_nopstart]);
|
|
|
|
Addr addr_of_nop = (Addr)p;
|
|
Addr where_to_go = gst.guest_PC;
|
|
Long diff = ((Long)where_to_go) - ((Long)addr_of_nop);
|
|
|
|
if (0) {
|
|
printf("addr of first nop = 0x%llx\n", addr_of_nop);
|
|
printf("where to go = 0x%llx\n", where_to_go);
|
|
printf("diff = 0x%llx\n", diff);
|
|
}
|
|
|
|
if (diff < -0x8000000LL || diff >= 0x8000000LL) {
|
|
// we're hosed. Give up
|
|
printf("hosed -- offset too large\n");
|
|
assert(0);
|
|
}
|
|
|
|
/* stay sane ... */
|
|
assert(p[0] == 0xd503201f); /* nop */
|
|
|
|
/* branch to diff */
|
|
p[0] = 0x14000000 | ((diff >> 2) & 0x3FFFFFF);
|
|
|
|
invalidate_icache( copy, nbytes );
|
|
|
|
( (void(*)(HWord,HWord))copy )(arg0, arg1);
|
|
}
|
|
|
|
#else
|
|
# error "Unknown plat"
|
|
#endif
|
|
|
|
|
|
|
|
/* -------------------- */
|
|
// f holds is the host code address
|
|
// gp holds the guest state pointer to use
|
|
// res is to hold the result. Or some such.
|
|
static HWord block[2]; // f, gp;
|
|
extern HWord run_translation_asm(void);
|
|
|
|
extern void disp_chain_assisted(void);
|
|
|
|
#if defined(__aarch64__)
|
|
asm(
|
|
"run_translation_asm:" "\n"
|
|
" stp x29, x30, [sp, #-16]!" "\n"
|
|
" stp x27, x28, [sp, #-16]!" "\n"
|
|
" stp x25, x26, [sp, #-16]!" "\n"
|
|
" stp x23, x24, [sp, #-16]!" "\n"
|
|
" stp x21, x22, [sp, #-16]!" "\n"
|
|
" stp x19, x20, [sp, #-16]!" "\n"
|
|
" stp x0, xzr, [sp, #-16]!" "\n"
|
|
" adrp x0, block" "\n"
|
|
" add x0, x0, :lo12:block" "\n"
|
|
" ldr x21, [x0, #8]" "\n" // load GSP
|
|
" ldr x1, [x0, #0]" "\n" // Host address
|
|
" br x1" "\n" // go (we wind up at disp_chain_assisted)
|
|
|
|
"disp_chain_assisted:" "\n" // x21 holds the trc. Return it.
|
|
" mov x1, x21" "\n"
|
|
/* Restore int regs, but not x1. */
|
|
" ldp x0, xzr, [sp], #16" "\n"
|
|
" ldp x19, x20, [sp], #16" "\n"
|
|
" ldp x21, x22, [sp], #16" "\n"
|
|
" ldp x23, x24, [sp], #16" "\n"
|
|
" ldp x25, x26, [sp], #16" "\n"
|
|
" ldp x27, x28, [sp], #16" "\n"
|
|
" ldp x29, x30, [sp], #16" "\n"
|
|
" mov x0, x1" "\n"
|
|
" ret" "\n"
|
|
);
|
|
|
|
#elif defined(__i386__)
|
|
|
|
asm(
|
|
"run_translation_asm:\n"
|
|
" pushal\n"
|
|
" movl gp, %ebp\n"
|
|
" movl f, %eax\n"
|
|
" call *%eax\n"
|
|
" movl %eax, res\n"
|
|
" popal\n"
|
|
" ret\n"
|
|
);
|
|
|
|
#else
|
|
# error "Unknown arch"
|
|
#endif
|
|
|
|
|
|
/* Run a translation at host address 'translation' and return the TRC.
|
|
*/
|
|
HWord run_translation ( HWord translation )
|
|
{
|
|
if (0 && DEBUG_TRACE_FLAGS) {
|
|
printf(" run translation %p\n", (void*)translation );
|
|
printf(" simulated bb: %llu\n", n_bbs_done);
|
|
}
|
|
block[0] = translation;
|
|
block[1] = (HWord)&gst;
|
|
HWord trc = run_translation_asm();
|
|
n_bbs_done ++;
|
|
return trc;
|
|
}
|
|
|
|
HWord find_translation ( Addr guest_addr )
|
|
{
|
|
Int i;
|
|
HWord __res;
|
|
if (0)
|
|
printf("find translation %p ... ", (void *)(guest_addr));
|
|
for (i = 0; i < trans_table_used; i++)
|
|
if (trans_table[i].base[0] == guest_addr)
|
|
break;
|
|
if (i == trans_table_used) {
|
|
if (0) printf("none\n");
|
|
return 0; /* not found */
|
|
}
|
|
|
|
/* Move this translation one step towards the front, so finding it
|
|
next time round is just that little bit cheaper. */
|
|
if (i > 2) {
|
|
VexGuestExtents tmpE = trans_table[i-1];
|
|
ULong* tmpP = trans_tableP[i-1];
|
|
trans_table[i-1] = trans_table[i];
|
|
trans_tableP[i-1] = trans_tableP[i];
|
|
trans_table[i] = tmpE;
|
|
trans_tableP[i] = tmpP;
|
|
i--;
|
|
}
|
|
|
|
__res = (HWord)trans_tableP[i];
|
|
if (0) printf("%p\n", (void*)__res);
|
|
return __res;
|
|
}
|
|
|
|
#define N_TRANSBUF 5000
|
|
static UChar transbuf[N_TRANSBUF];
|
|
void make_translation ( Addr guest_addr, Bool verbose )
|
|
{
|
|
VexTranslateArgs vta;
|
|
VexTranslateResult tres;
|
|
VexArchInfo vex_archinfo;
|
|
Int trans_used, i, ws_needed;
|
|
|
|
memset(&vta, 0, sizeof(vta));
|
|
memset(&tres, 0, sizeof(tres));
|
|
memset(&vex_archinfo, 0, sizeof(vex_archinfo));
|
|
|
|
if (trans_table_used >= N_TRANS_TABLE
|
|
|| trans_cache_used >= N_TRANS_CACHE-1000) {
|
|
/* If things are looking to full, just dump
|
|
all the translations. */
|
|
trans_cache_used = 0;
|
|
trans_table_used = 0;
|
|
}
|
|
|
|
assert(trans_table_used < N_TRANS_TABLE);
|
|
if (0)
|
|
printf("make translation %p\n", (void *)guest_addr);
|
|
|
|
LibVEX_default_VexArchInfo(&vex_archinfo);
|
|
//vex_archinfo.subarch = VexSubArch;
|
|
//vex_archinfo.ppc_icache_line_szB = CacheLineSize;
|
|
|
|
/* */
|
|
vta.arch_guest = VexArch;
|
|
vta.archinfo_guest = vex_archinfo;
|
|
vta.arch_host = VexArch;
|
|
vta.archinfo_host = vex_archinfo;
|
|
vta.guest_bytes = (UChar*)guest_addr;
|
|
vta.guest_bytes_addr = guest_addr;
|
|
vta.chase_into_ok = chase_into_ok;
|
|
// vta.guest_extents = &vge;
|
|
vta.guest_extents = &trans_table[trans_table_used];
|
|
vta.host_bytes = transbuf;
|
|
vta.host_bytes_size = N_TRANSBUF;
|
|
vta.host_bytes_used = &trans_used;
|
|
vta.instrument1 = NULL;
|
|
vta.instrument2 = NULL;
|
|
vta.needs_self_check = needs_self_check;
|
|
vta.traceflags = verbose ? TEST_FLAGS : DEBUG_TRACE_FLAGS;
|
|
|
|
vta.disp_cp_chain_me_to_slowEP = NULL; //disp_chain_fast;
|
|
vta.disp_cp_chain_me_to_fastEP = NULL; //disp_chain_slow;
|
|
vta.disp_cp_xindir = NULL; //disp_chain_indir;
|
|
vta.disp_cp_xassisted = disp_chain_assisted;
|
|
|
|
vta.addProfInc = False;
|
|
|
|
tres = LibVEX_Translate ( &vta );
|
|
|
|
assert(tres.status == VexTransOK);
|
|
assert(tres.offs_profInc == -1);
|
|
|
|
ws_needed = (trans_used+7) / 8;
|
|
assert(ws_needed > 0);
|
|
assert(trans_cache_used + ws_needed < N_TRANS_CACHE);
|
|
n_translations_made++;
|
|
|
|
for (i = 0; i < trans_used; i++) {
|
|
HChar* dst = ((HChar*)(&trans_cache[trans_cache_used])) + i;
|
|
HChar* src = (HChar*)(&transbuf[i]);
|
|
*dst = *src;
|
|
}
|
|
|
|
#if defined(__aarch64__)
|
|
invalidate_icache( &trans_cache[trans_cache_used], trans_used );
|
|
#endif
|
|
|
|
trans_tableP[trans_table_used] = &trans_cache[trans_cache_used];
|
|
trans_table_used++;
|
|
trans_cache_used += ws_needed;
|
|
}
|
|
|
|
|
|
__attribute__((unused))
|
|
static Bool overlap ( Addr start, UInt len, VexGuestExtents* vge )
|
|
{
|
|
Int i;
|
|
for (i = 0; i < vge->n_used; i++) {
|
|
if (vge->base[i]+vge->len[i] <= start
|
|
|| vge->base[i] >= start+len) {
|
|
/* ok */
|
|
} else {
|
|
return True;
|
|
}
|
|
}
|
|
return False; /* no overlap */
|
|
}
|
|
|
|
static ULong stopAfter = 0;
|
|
static UChar* entryP = NULL;
|
|
|
|
|
|
__attribute__ ((noreturn))
|
|
static
|
|
void failure_exit ( void )
|
|
{
|
|
fprintf(stdout, "VEX did failure_exit. Bye.\n");
|
|
fprintf(stdout, "bb counter = %llu\n\n", n_bbs_done);
|
|
exit(1);
|
|
}
|
|
|
|
static
|
|
void log_bytes ( HChar* bytes, Int nbytes )
|
|
{
|
|
fwrite ( bytes, 1, nbytes, stdout );
|
|
fflush ( stdout );
|
|
}
|
|
|
|
|
|
/* run simulated code forever (it will exit by calling
|
|
serviceFn(0)). */
|
|
static void run_simulator ( void )
|
|
{
|
|
static Addr last_guest = 0;
|
|
Addr next_guest;
|
|
HWord next_host;
|
|
while (1) {
|
|
next_guest = gst.GuestPC;
|
|
|
|
if (0)
|
|
printf("\nnext_guest: 0x%x\n", (UInt)next_guest);
|
|
|
|
if (next_guest == (Addr)&serviceFn) {
|
|
|
|
/* "do" the function call to serviceFn */
|
|
# if defined(__i386__)
|
|
{
|
|
HWord esp = gst.guest_ESP;
|
|
gst.guest_EIP = *(UInt*)(esp+0);
|
|
gst.guest_EAX = serviceFn( *(UInt*)(esp+4), *(UInt*)(esp+8) );
|
|
gst.guest_ESP = esp+4;
|
|
next_guest = gst.guest_EIP;
|
|
}
|
|
# elif defined(__aarch64__)
|
|
{
|
|
gst.guest_X0 = serviceFn( gst.guest_X0, gst.guest_X1 );
|
|
gst.guest_PC = gst.guest_X30;
|
|
next_guest = gst.guest_PC;
|
|
}
|
|
# else
|
|
# error "Unknown arch"
|
|
# endif
|
|
}
|
|
|
|
next_host = find_translation(next_guest);
|
|
if (next_host == 0) {
|
|
make_translation(next_guest,False);
|
|
next_host = find_translation(next_guest);
|
|
assert(next_host != 0);
|
|
}
|
|
|
|
// Switchback
|
|
if (n_bbs_done == stopAfter) {
|
|
printf("---begin SWITCHBACK at bb:%llu---\n", n_bbs_done);
|
|
#if 1
|
|
if (last_guest) {
|
|
printf("\n*** Last run translation (bb:%llu):\n", n_bbs_done-1);
|
|
make_translation(last_guest,True);
|
|
}
|
|
#endif
|
|
#if 0
|
|
if (next_guest) {
|
|
printf("\n*** Current translation (bb:%llu):\n", n_bbs_done);
|
|
make_translation(next_guest,True);
|
|
}
|
|
#endif
|
|
printf("--- end SWITCHBACK at bb:%llu ---\n", n_bbs_done);
|
|
switchback();
|
|
assert(0); /*NOTREACHED*/
|
|
}
|
|
|
|
last_guest = next_guest;
|
|
HWord trc = run_translation(next_host);
|
|
if (0) printf("------- trc = %lu\n", trc);
|
|
if (trc != VEX_TRC_JMP_BORING) {
|
|
if (1) printf("------- trc = %lu\n", trc);
|
|
}
|
|
assert(trc == VEX_TRC_JMP_BORING);
|
|
}
|
|
}
|
|
|
|
|
|
static void usage ( void )
|
|
{
|
|
printf("usage: switchback #bbs\n");
|
|
printf(" - begins switchback for basic block #bbs\n");
|
|
printf(" - use -1 for largest possible run without switchback\n\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int main ( Int argc, HChar** argv )
|
|
{
|
|
if (argc != 2)
|
|
usage();
|
|
|
|
stopAfter = (ULong)atoll(argv[1]);
|
|
|
|
extern void entry ( void*(*service)(int,int) );
|
|
entryP = (UChar*)&entry;
|
|
|
|
if (!entryP) {
|
|
printf("switchback: can't find entry point\n");
|
|
exit(1);
|
|
}
|
|
|
|
LibVEX_default_VexControl(&vcon);
|
|
vcon.guest_max_insns=50 - 49;
|
|
vcon.guest_chase_thresh=0;
|
|
vcon.iropt_level=2;
|
|
|
|
LibVEX_Init( failure_exit, log_bytes, 1, &vcon );
|
|
LibVEX_Guest_initialise(&gst);
|
|
gst.host_EvC_COUNTER = 999999999; // so we should never get an exit
|
|
gst.host_EvC_FAILADDR = 0x5a5a5a5a5a5a5a5a;
|
|
|
|
/* set up as if a call to the entry point passing serviceFn as
|
|
the one and only parameter */
|
|
# if defined(__i386__)
|
|
gst.guest_EIP = (UInt)entryP;
|
|
gst.guest_ESP = (UInt)&gstack[32000];
|
|
*(UInt*)(gst.guest_ESP+4) = (UInt)serviceFn;
|
|
*(UInt*)(gst.guest_ESP+0) = 0x12345678;
|
|
|
|
# elif defined(__aarch64__)
|
|
gst.guest_PC = (ULong)entryP;
|
|
gst.guest_SP = (ULong)&gstack[32000];
|
|
gst.guest_X0 = (ULong)serviceFn;
|
|
HWord tpidr_el0 = 0;
|
|
__asm__ __volatile__("mrs %0, tpidr_el0" : "=r"(tpidr_el0));
|
|
gst.guest_TPIDR_EL0 = tpidr_el0;
|
|
|
|
# else
|
|
# error "Unknown arch"
|
|
# endif
|
|
|
|
printf("\n---START---\n");
|
|
|
|
#if 1
|
|
run_simulator();
|
|
#else
|
|
( (void(*)(HWord(*)(HWord,HWord))) entryP ) (serviceFn);
|
|
#endif
|
|
|
|
|
|
return 0;
|
|
}
|