├── bin ├── .gitignore └── softfloat │ └── .gitignore ├── obj ├── .gitignore ├── cpu │ └── .gitignore ├── syscall │ └── .gitignore └── vdso │ └── .gitignore ├── tests ├── meta │ └── .gitignore ├── snapshot-bin │ └── .keep ├── traces-bin │ └── .gitignore ├── traces-obj │ └── .gitignore ├── traces-out │ └── .gitignore ├── traces-arm-bin │ └── .gitignore ├── traces-arm-obj │ └── .gitignore ├── traces-arm-out │ └── .gitignore ├── traces-fastxchk-out │ └── .gitignore ├── traces-i386-bin │ └── .gitignore ├── traces-i386-obj │ └── .gitignore ├── traces-i386-out │ └── .gitignore ├── traces-xchk-out │ └── .gitignore ├── busybox │ ├── busybox-armv6l │ ├── busybox-i686 │ └── busybox-x86_64 ├── traces-src │ ├── errno.c │ ├── cmdline.c │ ├── nested_call.c │ ├── strerror.c │ ├── time.c │ ├── print.c │ ├── malloc.c │ ├── getenv.c │ ├── gettext.c │ ├── uselocale.c │ ├── cmdline-many.c │ ├── strlen.c │ ├── memset.c │ ├── rand.c │ ├── sscanf.c │ ├── strstr.c │ ├── strrchr.c │ ├── fwrite.c │ ├── strcpy.c │ ├── gettimeofday.c │ ├── atoi.c │ ├── dlsym.c │ ├── memset-large.c │ ├── strchrnul.c │ ├── qsort.c │ ├── primes.c │ ├── getopt.c │ └── fp-test.c ├── opcodes │ └── x86_64 │ │ ├── prefixes.txt │ │ ├── registers.txt │ │ ├── registers-full.txt │ │ ├── fragment.c │ │ ├── gen_optest.sh │ │ └── opcodes.txt ├── snapshot-src │ ├── read-post.c │ └── threads.c ├── opcodes.sh ├── snapshot.sh ├── busybox_cmd.txt ├── bin_cmds.txt ├── traces.sh └── trace_docmd.sh ├── bitcode ├── libvex_arm_helpers.bc ├── libvex_x86_helpers.bc └── libvex_amd64_helpers.bc ├── .gitignore ├── src ├── syscall │ ├── spimsyscalls.h │ └── spimsyscalls.cc ├── usage.h ├── cpu │ ├── linux_abi.h │ ├── i386_macros.h │ ├── mips32cpustate.h │ ├── i386cpustate.h │ ├── armcpustate.h │ ├── ptshadowi386.h │ ├── linux_abi.cc │ ├── amd64cpustate.h │ ├── sc_xlate.h │ ├── ptshadowamd64.h │ ├── amd64_trampoline.s │ ├── mips32cpustate.cc │ ├── armcpustate.cc │ ├── i386syscalls.cc │ ├── amd64syscalls.cc │ ├── i386cpustate.cc │ ├── armsyscalls.cc │ └── ptshadowi386.cc ├── debugprintpass.h ├── qemu │ ├── i386signal.h │ ├── amd64signal.h │ ├── armsignal.h │ ├── translatedsyscall.h │ ├── translatedthunk.h │ └── translatedsocket.h ├── usage.cc ├── vexexecfastchk.h ├── vexexecchk.h ├── jitobjcache.h ├── directcache.h ├── ss_run.cc ├── vexxlate.h ├── jitengine.h ├── pt_xchk.cc ├── vexllvm_ss.cc ├── vexcpustate.h ├── vexjitcache.h ├── pt_run.cc ├── memlog.h ├── vexcpustate.cc ├── elf_run.cc ├── ptimgchk.h ├── vexhelpers.h ├── dump_loader.cc ├── vexfcache.h ├── memlog.cc ├── vexsb.h ├── frag_run.cc ├── fragcache.h ├── vexexecfastchk.cc ├── jitobjcache.cc ├── genllvm.h ├── vexexec.h ├── debugprintpass.cc ├── elfcore.h ├── vexjitcache.cc ├── vexhelpers.cc ├── vexfcache.cc └── vexstmt.h ├── support ├── vexops_softfloat.c └── vexops.c ├── scripts ├── stat_miner.sh ├── stack_dump.sh ├── addr2sym.py ├── build_helpers.sh ├── stat_analyzer.sh ├── mkreport.py ├── kern2guest.sh └── guest_cov.py └── README.md /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /obj/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /obj/cpu/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /obj/syscall/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /obj/vdso/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/meta/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/snapshot-bin/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bin/softfloat/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-obj/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-out/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-arm-bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-arm-obj/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-arm-out/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-fastxchk-out/.gitignore: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /tests/traces-i386-bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-i386-obj/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-i386-out/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/traces-xchk-out/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /tests/busybox/busybox-armv6l: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/tests/busybox/busybox-armv6l -------------------------------------------------------------------------------- /tests/busybox/busybox-i686: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/tests/busybox/busybox-i686 -------------------------------------------------------------------------------- /tests/busybox/busybox-x86_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/tests/busybox/busybox-x86_64 -------------------------------------------------------------------------------- /bitcode/libvex_arm_helpers.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/bitcode/libvex_arm_helpers.bc -------------------------------------------------------------------------------- /bitcode/libvex_x86_helpers.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/bitcode/libvex_x86_helpers.bc -------------------------------------------------------------------------------- /bitcode/libvex_amd64_helpers.bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyitsanthony/vexllvm/HEAD/bitcode/libvex_amd64_helpers.bc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tests/opcodes/x86_64/OP* 2 | tests/*bin/* 3 | src/._* 4 | src/cpu/._* 5 | src/syscall/._* 6 | bitcode/vexops.bc 7 | bitcode/softfloat.bc 8 | guest-* 9 | -------------------------------------------------------------------------------- /tests/traces-src/errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | printf("Error: %d\n", errno); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /tests/traces-src/cmdline.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | assert (argc == 1 && "But called with no args!"); 7 | return argc; 8 | } -------------------------------------------------------------------------------- /tests/traces-src/nested_call.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int h(void) { return getpid(); } 5 | int g(void) { return h(); } 6 | int f(void) { return g(); } 7 | 8 | int main(void) { return f(); } -------------------------------------------------------------------------------- /tests/traces-src/strerror.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | printf("Error: %s\n", strerror(10)); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/traces-src/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | time_t t; 7 | 8 | t = time(NULL); 9 | assert (t != ((time_t)-1)); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/traces-src/print.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void hello(void) { printf("hello\n"); } 4 | void goodbye(void) { printf("goodbye\n"); } 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | hello(); 9 | goodbye(); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /tests/traces-src/malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | void *m = malloc(100); 8 | assert (m != NULL); 9 | memset(m, 0, 100); 10 | 11 | return 0; 12 | } -------------------------------------------------------------------------------- /tests/traces-src/getenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int main(int argc, char* argv[]) 5 | { 6 | const char *u; 7 | u = getenv("USER"); 8 | assert (u != NULL); 9 | printf("%s\n", u); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /tests/traces-src/gettext.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | uselocale(LC_GLOBAL_LOCALE); 9 | printf("%s\n", gettext("yesexpr")); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /tests/traces-src/uselocale.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char* argv[]) 4 | { 5 | const char* cur_locale; 6 | uselocale(LC_GLOBAL_LOCALE); 7 | cur_locale = setlocale(0, NULL); 8 | printf("%s\n", cur_locale); 9 | gettext("xyz"); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /tests/opcodes/x86_64/prefixes.txt: -------------------------------------------------------------------------------- 1 | GS 2 | REX 3 | REX.B 4 | REX.R 5 | REX.RB 6 | REX.RX 7 | REX.RXB 8 | REX.W 9 | REX.WB 10 | REX.WR 11 | REX.WRB 12 | REX.WRX 13 | REX.WRXB 14 | REX.WX 15 | REX.WXB 16 | REX.X 17 | REX.XB 18 | REP 19 | REPNZ 20 | REPZ 21 | LOCK 22 | GETSEC 23 | FS -------------------------------------------------------------------------------- /tests/traces-src/cmdline-many.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | int i; 7 | for (i = 0; i < argc; i++) { 8 | assert (argv[i] != NULL); 9 | printf("argv[%d]: %s\n", i, argv[i]); 10 | } 11 | return argc; 12 | } -------------------------------------------------------------------------------- /tests/opcodes/x86_64/registers.txt: -------------------------------------------------------------------------------- 1 | %rax 2 | %rbx 3 | %rbp 4 | %rsp 5 | %r9 6 | %eax 7 | %ebp 8 | %esp 9 | %r9d 10 | %ax 11 | %bx 12 | %bp 13 | %sp 14 | %r9w 15 | %al 16 | %bl 17 | %ah 18 | %bh 19 | %r9b 20 | (%rax) 21 | $17 22 | $32 23 | $4 24 | %xmm0 25 | %xmm3 26 | %mm0 27 | %mm3 -------------------------------------------------------------------------------- /tests/traces-src/strlen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | char x[10]; 7 | int ret; 8 | x[0] = 't'; x[1] = 'e'; x[2] = 's'; x[3] = 't'; x[4] = '\0'; 9 | ret = strlen(x); 10 | assert (ret == 4 && "BAD LEN"); 11 | return ret; 12 | } -------------------------------------------------------------------------------- /tests/traces-src/memset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | uint8_t x[37]; 8 | int i; 9 | memset(x, 0xa1, sizeof(x)); 10 | for (i = 0; i < sizeof(x); i++) { 11 | assert (x[i] == 0xa1); 12 | } 13 | return 0; 14 | } -------------------------------------------------------------------------------- /tests/traces-src/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUM_LOOPS 3 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | int i; 9 | srand(1234); 10 | for (i = 0; i < NUM_LOOPS; i++) { 11 | int r; 12 | r = rand() % 10; 13 | assert (r < 10); 14 | } 15 | return 0; 16 | } -------------------------------------------------------------------------------- /tests/traces-src/sscanf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | int d; 8 | char c; 9 | 10 | sscanf("10 ", "%d", &d); 11 | assert (d == 10); 12 | sscanf("c ", "%c", &c); 13 | assert (c == 'c'); 14 | 15 | return 0; 16 | } -------------------------------------------------------------------------------- /tests/traces-src/strstr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const char test_str[] = {"abcdefabcdef"}; 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | char *s; 10 | s = strstr(test_str, "def"); 11 | assert (((intptr_t)(s - test_str)) == 3); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/traces-src/strrchr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | char x[10]; 7 | char *p; 8 | int idx; 9 | x[0] = 't'; x[1] = 'e'; x[2] = 's'; x[3] = 't'; x[4] = '\0'; 10 | p = strrchr(x, 's'); 11 | idx = p - x; 12 | assert (idx == 2); 13 | return idx; 14 | } -------------------------------------------------------------------------------- /src/syscall/spimsyscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef SPIMSYSCALLS_H 2 | #define SPIMSYSCALLS_H 3 | 4 | #include "syscall/syscalls.h" 5 | 6 | class SPIMSyscalls : public Syscalls 7 | { 8 | public: 9 | SPIMSyscalls(Guest* gs) : Syscalls(gs) {} 10 | virtual ~SPIMSyscalls(void) {} 11 | virtual uint64_t apply(SyscallParams& args); 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/traces-src/fwrite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | FILE *f; 9 | 10 | f = fopen("bogus_file", "w"); 11 | assert (f != NULL); 12 | fwrite("abc", 3, 1, f); 13 | fclose(f); 14 | unlink("bogus_file"); 15 | 16 | return 0; 17 | } -------------------------------------------------------------------------------- /tests/snapshot-src/read-post.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | int n; 10 | int fd; 11 | char x[32]; 12 | 13 | fd = open(argv[1], O_RDONLY); 14 | n = read(fd, x, 32); 15 | printf("%d\n", n); 16 | return n; 17 | } -------------------------------------------------------------------------------- /tests/traces-src/strcpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const char s1[] = "HELLO COPY THIS STRING"; 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | char s2[sizeof(s1)]; 10 | int i; 11 | 12 | strcpy(s2, s1); 13 | for (i = 0; s1[i]; i++) { 14 | assert (s2[i] == s1[i] && "CPY MISMATCH"); 15 | } 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /tests/traces-src/gettimeofday.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | struct timeval tv; 8 | int rc; 9 | time_t t; 10 | 11 | rc = gettimeofday(&tv, NULL); 12 | assert (rc == 0 && "Bad return value"); 13 | 14 | t = time(NULL); 15 | assert (tv.tv_sec <= t); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/usage.h: -------------------------------------------------------------------------------- 1 | #ifndef RES_USAGE_H 2 | #define RES_USAGE_H 3 | 4 | #include 5 | 6 | /* compute resource changes since construction of object */ 7 | class ResUsage { 8 | public: 9 | ResUsage(const std::string& n = ""); 10 | ~ResUsage(); 11 | void dump_diff(void) const; 12 | private: 13 | std::string name; 14 | struct rusage init_usage; 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /tests/traces-src/atoi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const char* s[] = {"1", "-1", "-100", "100", "999999999" }; 6 | int v[] = {1, -1, -100, 100, 999999999 }; 7 | 8 | int main(int argc, char* argv[]) 9 | { 10 | int i; 11 | for (i = 0; i < sizeof(v)/sizeof(int); i++) { 12 | assert (atoi(s[i]) == v[i]); 13 | } 14 | return 0; 15 | } -------------------------------------------------------------------------------- /src/cpu/linux_abi.h: -------------------------------------------------------------------------------- 1 | #ifndef LINUX_ABI_H 2 | #define LINUX_ABI_H 3 | 4 | class GuestABI; 5 | class Guest; 6 | 7 | class LinuxABI 8 | { 9 | public: 10 | LinuxABI() = delete; 11 | ~LinuxABI() = delete; 12 | static GuestABI* create(Guest &g); 13 | private: 14 | static const char* scregs_i386[]; 15 | static const char* scregs_amd64[]; 16 | static const char* scregs_arm[]; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /tests/traces-src/dlsym.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | void *h, *sym; 8 | void (*puts_f)(const char*); 9 | 10 | h = dlopen("/lib/libc.so.6", RTLD_LOCAL | RTLD_LAZY); 11 | assert (h != NULL); 12 | sym = dlsym(h, "puts"); 13 | assert (sym != NULL); 14 | puts_f = sym; 15 | puts_f("hello\n"); 16 | dlclose(h); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /tests/traces-src/memset-large.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MEMSET_BYTES 8100 7 | 8 | uint8_t memset_data[MEMSET_BYTES]; 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | int i; 13 | 14 | memset(memset_data, 0xa1, MEMSET_BYTES); 15 | for (i = 0; i < MEMSET_BYTES; i++) { 16 | assert (memset_data[i] == 0xa1 && "WRONG MEMSET VALUE"); 17 | } 18 | 19 | return 0; 20 | } -------------------------------------------------------------------------------- /support/vexops_softfloat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern int32_t float64_is_nan(uint64_t); 5 | extern int32_t float64_eq(uint64_t, uint64_t); 6 | extern int32_t float64_lt(uint64_t, uint64_t); 7 | 8 | uint32_t vexop_softfloat_cmpf64(uint64_t f1, uint64_t f2) 9 | { 10 | /* XXX how does this handle NaN? */ 11 | if (float64_is_nan(f1) || float64_is_nan(f2)) return Ircr_UN; 12 | if (float64_eq(f1, f2)) return Ircr_EQ; 13 | if (float64_lt(f1, f2)) return Ircr_LT; 14 | return Ircr_GT; 15 | } -------------------------------------------------------------------------------- /src/debugprintpass.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGPRINTPASS_H 2 | #define DEBUGPRINTPASS_H 3 | 4 | #include 5 | 6 | // XXX only works with JIT because of funny string handling 7 | class DebugPrintPass : public llvm::FunctionPass 8 | { 9 | public: 10 | DebugPrintPass() 11 | : llvm::FunctionPass(ID) 12 | , debug_func_ty(getFuncType()) 13 | { 14 | } 15 | 16 | bool runOnFunction(llvm::Function &f) override; 17 | 18 | private: 19 | llvm::FunctionType* getFuncType(void) const; 20 | llvm::Type *debug_func_ty; 21 | static char ID; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /tests/snapshot-src/threads.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define NUM_THR 4 5 | 6 | pthread_t thr[NUM_THR]; 7 | sem_t sem; 8 | 9 | static void* f(void* x) 10 | { 11 | sem_wait(&sem); 12 | return NULL; 13 | } 14 | 15 | int main(void) 16 | { 17 | unsigned i; 18 | 19 | sem_init(&sem, 0, 0); 20 | 21 | for (i = 0; i < NUM_THR; i++) 22 | pthread_create(&thr[i], NULL, f, NULL); 23 | 24 | sleep(5); 25 | 26 | /* release all threads */ 27 | for (i = 0; i < NUM_THR; i++) 28 | sem_post(&sem); 29 | 30 | for (i = 0; i < NUM_THR; i++) 31 | pthread_join(thr[i], NULL); 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /src/qemu/i386signal.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | linux-user/i386/target_signal.h 5 | */ 6 | #ifndef TARGET_SIGNAL_H 7 | #define TARGET_SIGNAL_H 8 | 9 | /* this struct defines a stack used during syscall handling */ 10 | 11 | typedef struct target_sigaltstack { 12 | abi_ulong ss_sp; 13 | abi_long ss_flags; 14 | abi_ulong ss_size; 15 | } target_stack_t; 16 | 17 | 18 | /* 19 | * sigaltstack controls 20 | */ 21 | #define TARGET_SS_ONSTACK 1 22 | #define TARGET_SS_DISABLE 2 23 | 24 | #define TARGET_MINSIGSTKSZ 2048 25 | #define TARGET_SIGSTKSZ 8192 26 | 27 | #endif /* TARGET_SIGNAL_H */ 28 | -------------------------------------------------------------------------------- /src/usage.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "usage.h" 4 | 5 | ResUsage::ResUsage(const std::string& n) 6 | : name(n) 7 | { 8 | int rc = getrusage(RUSAGE_SELF, &init_usage); 9 | assert(rc == 0); 10 | } 11 | 12 | void ResUsage::dump_diff(void) const 13 | { 14 | struct rusage cur_usage; 15 | int rc = getrusage(RUSAGE_SELF, &cur_usage); 16 | assert(rc == 0); 17 | int64_t diff = cur_usage.ru_maxrss - init_usage.ru_maxrss; 18 | if (!name.empty()) std::cerr << '[' << name << "] "; 19 | std::cerr << "RSS: " << ((double)diff)/1024.0 << "MB\n"; 20 | } 21 | 22 | ResUsage::~ResUsage() 23 | { 24 | dump_diff(); 25 | } 26 | -------------------------------------------------------------------------------- /tests/traces-src/strchrnul.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | static const char s1[] = {"abcdefghijklmnopqrstuvwxy"}; 7 | static const char s2[] = {"abc"}; 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | int i; 12 | 13 | for (i = 0; i < sizeof(s1); i++) { 14 | char *s; 15 | int c; 16 | c = 'a' + i; 17 | s = strchrnul(s1, c); 18 | assert (s == &s1[i]); 19 | } 20 | 21 | for (i = 0; i < sizeof(s2); i++) { 22 | char *s; 23 | int c; 24 | c = 'a' + i; 25 | s = strchrnul(s2, c); 26 | assert (s == &s2[i]); 27 | } 28 | 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /scripts/stat_miner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Use this to compute the opt-traces directory, which will contain the results 5 | # of traces with varying optimization flags 6 | # 7 | if [ -z "$TRACECC" ]; then 8 | TRACECC="gcc" 9 | fi 10 | 11 | OPTFLAGS="O1 O2 O3 O4 Os g" 12 | for optflag in $OPTFLAGS; do 13 | echo $optflag 14 | mkdir -p tests/traces-{out,bin,obj} 15 | make tests-clean 16 | TRACECC="$TRACECC" \ 17 | TRACE_CFLAGS="-$optflag" \ 18 | VEXLLVM_DUMP_XLATESTATS=1 \ 19 | make test-built-traces 20 | rm -rf opt-traces/"$optflag" 21 | mkdir -p opt-traces/"$optflag" 22 | mv tests/traces-{out,bin,obj} opt-traces/"$optflag" 23 | done -------------------------------------------------------------------------------- /src/qemu/amd64signal.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | linux-user/x86_64/target_signal.h 5 | */ 6 | 7 | #ifndef TARGET_SIGNAL_H 8 | #define TARGET_SIGNAL_H 9 | 10 | /* this struct defines a stack used during syscall handling */ 11 | 12 | typedef struct target_sigaltstack { 13 | abi_ulong ss_sp; 14 | abi_long ss_flags; 15 | abi_ulong ss_size; 16 | } target_stack_t; 17 | 18 | 19 | /* 20 | * sigaltstack controls 21 | */ 22 | #define TARGET_SS_ONSTACK 1 23 | #define TARGET_SS_DISABLE 2 24 | 25 | #define TARGET_MINSIGSTKSZ 2048 26 | #define TARGET_SIGSTKSZ 8192 27 | 28 | #endif /* TARGET_SIGNAL_H */ 29 | -------------------------------------------------------------------------------- /src/vexexecfastchk.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXEXECFASTCHK_H 2 | #define VEXEXECFASTCHK_H 3 | 4 | #include "vexexecchk.h" 5 | 6 | class PTImgChk; 7 | 8 | class VexExecFastChk : public VexExecChk 9 | { 10 | friend class VexExec; 11 | public: 12 | virtual ~VexExecFastChk(void) {} 13 | protected: 14 | VexExecFastChk(PTImgChk* gs, std::shared_ptr vx); 15 | 16 | virtual guest_ptr doVexSB(VexSB* vsb); 17 | virtual void doSysCall(VexSB* vsb); 18 | private: 19 | unsigned int pt_sc_req_c; /* syscall opcodes ptrace seen */ 20 | unsigned int pt_sc_done_c; /* syscall opcodes ptrace retired */ 21 | unsigned int crashed_pt_sc_req; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/cpu/i386_macros.h: -------------------------------------------------------------------------------- 1 | #ifndef I386_MACROS_H 2 | #define I386_MACROS_H 3 | 4 | #define ud2vexseg(y,x) do { \ 5 | (x)->Bits.LimitLow = (y).limit & 0xffff; \ 6 | (x)->Bits.BaseLow = (y).base_addr & 0xffff; \ 7 | (x)->Bits.BaseMid = ((y).base_addr >> 16) & 0xff; \ 8 | (x)->Bits.Type = 0; /* ??? */ \ 9 | (x)->Bits.Dpl = 3; \ 10 | (x)->Bits.Pres = !(y).seg_not_present; \ 11 | (x)->Bits.LimitHi = (y).limit >> 16; \ 12 | (x)->Bits.Sys = 0; \ 13 | (x)->Bits.Reserved_0 = 0; \ 14 | (x)->Bits.Default_Big = 1; \ 15 | (x)->Bits.Granularity = (y).limit_in_pages; \ 16 | (x)->Bits.BaseHi = ((y).base_addr >> 24) & 0xff; \ 17 | } while (0) 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /tests/opcodes/x86_64/registers-full.txt: -------------------------------------------------------------------------------- 1 | %rax 2 | %rbx 3 | %rcx 4 | %rdx 5 | %rdi 6 | %rsi 7 | %rbp 8 | %rsp 9 | %r8 10 | %r9 11 | %r10 12 | %r11 13 | %r12 14 | %r13 15 | %r14 16 | %r15 17 | %eax 18 | %ebx 19 | %ecx 20 | %edx 21 | %edi 22 | %esi 23 | %ebp 24 | %esp 25 | %r8d 26 | %r9d 27 | %r10d 28 | %r11d 29 | %r12d 30 | %r13d 31 | %r14d 32 | %r15d 33 | %ax 34 | %bx 35 | %cx 36 | %dx 37 | %di 38 | %si 39 | %bp 40 | %sp 41 | %r8w 42 | %r9w 43 | %r10w 44 | %r11w 45 | %r12w 46 | %r13w 47 | %r14w 48 | %r15w 49 | %al 50 | %bl 51 | %cl 52 | %dl 53 | %ah 54 | %bh 55 | %ch 56 | %dh 57 | %r8b 58 | %r9b 59 | %r10b 60 | %r11b 61 | %r12b 62 | %r13b 63 | %r14b 64 | %r15b 65 | (%rax) 66 | 17 67 | 32 68 | 4 -------------------------------------------------------------------------------- /tests/opcodes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ARCHDIR="tests/opcodes/x86_64" 4 | $ARCHDIR/gen_optest.sh 5 | 6 | for i in $ARCHDIR/OP_*; do 7 | OPCODE=`basename "$i" | sed "s/OP_//g"` 8 | if [ ! -d $ARCHDIR/OP_$OPCODE ]; then 9 | continue 10 | fi 11 | 12 | echo -n "Testing $OPCODE ..." 13 | for j in $ARCHDIR/OP_$OPCODE/*; do 14 | if [ ! -x $j ]; then 15 | continue 16 | fi 17 | 18 | "$j" &> /dev/null 19 | if [ ! $? -eq 0 ]; then 20 | # skip it if it crashes on its own 21 | continue 22 | fi 23 | 24 | echo -n "." 25 | bin/pt_xchk "$j" &> /tmp/opcoderesults.log 26 | if [ $? -ne 0 ]; then 27 | echo 28 | echo $j failed 29 | cat /tmp/opcoderesults.log 30 | fi 31 | done 32 | echo 33 | done 34 | -------------------------------------------------------------------------------- /src/cpu/mips32cpustate.h: -------------------------------------------------------------------------------- 1 | #ifndef MIPS32CPUSTATE_H 2 | #define MIPS32CPUSTATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "vexcpustate.h" 10 | 11 | class SyscallParams; 12 | 13 | class MIPS32CPUState : public VexCPUState 14 | { 15 | public: 16 | MIPS32CPUState(); 17 | ~MIPS32CPUState(); 18 | void setStackPtr(guest_ptr); 19 | guest_ptr getStackPtr(void) const; 20 | void setPC(guest_ptr); 21 | guest_ptr getPC(void) const; 22 | 23 | void print(std::ostream& os, const void*) const; 24 | 25 | static const char* abi_spim_scregs[]; 26 | }; 27 | 28 | #define ABI_SPIM_MIPS32 MIPS32CPUState::abi_spim_scregs, "R2", "R4", true 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/cpu/i386cpustate.h: -------------------------------------------------------------------------------- 1 | #ifndef I386CPUSTATE_H 2 | #define I386CPUSTATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "vexcpustate.h" 10 | 11 | class SyscallParams; 12 | 13 | class I386CPUState : public VexCPUState 14 | { 15 | public: 16 | I386CPUState(); 17 | ~I386CPUState(); 18 | void setStackPtr(guest_ptr) override; 19 | guest_ptr getStackPtr(void) const override; 20 | void setPC(guest_ptr) override; 21 | guest_ptr getPC(void) const override; 22 | 23 | void print(std::ostream& os, const void*) const override; 24 | unsigned int getStackRegOff(void) const override; 25 | 26 | void noteRegion(const char* name, guest_ptr addr) override; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/qemu/armsignal.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | linux-user/arm/target_signal.h 5 | */ 6 | #ifndef TARGET_SIGNAL_H 7 | #define TARGET_SIGNAL_H 8 | 9 | /* this struct defines a stack used during syscall handling */ 10 | 11 | typedef struct target_sigaltstack { 12 | abi_ulong ss_sp; 13 | abi_long ss_flags; 14 | abi_ulong ss_size; 15 | } target_stack_t; 16 | 17 | 18 | /* 19 | * sigaltstack controls 20 | */ 21 | #define TARGET_SS_ONSTACK 1 22 | #define TARGET_SS_DISABLE 2 23 | 24 | #define TARGET_MINSIGSTKSZ 2048 25 | #define TARGET_SIGSTKSZ 8192 26 | 27 | /* 28 | static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) 29 | { 30 | return state->regs[13]; 31 | } 32 | */ 33 | 34 | #endif /* TARGET_SIGNAL_H */ 35 | -------------------------------------------------------------------------------- /src/vexexecchk.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXEXECCHK_H 2 | #define VEXEXECCHK_H 3 | 4 | #include "vexexec.h" 5 | 6 | class PTImgChk; 7 | class SyscallsMarshalled; 8 | class VexXlate; 9 | 10 | class VexExecChk : public VexExec 11 | { 12 | friend class VexExec; 13 | public: 14 | virtual ~VexExecChk(void) {} 15 | 16 | protected: 17 | VexExecChk(PTImgChk* gs, std::shared_ptr vx = NULL); 18 | 19 | virtual guest_ptr doVexSB(VexSB* vsb); 20 | virtual void doSysCall(VexSB* vsb); 21 | void doSysCallCore(VexSB* vsb); 22 | void verifyBlockRun(VexSB* vsb); 23 | void stepSysCall(VexSB* vsb); 24 | void dumpShadow(VexSB* vsb); 25 | 26 | PTImgChk *cross_check; 27 | private: 28 | bool hit_syscall; 29 | bool is_deferred; 30 | guest_ptr deferred_bound_start; 31 | guest_ptr deferred_bound_end; 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /tests/traces-src/qsort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NUM_MEMBERS 10 6 | 7 | static int intcmp(const void* v1, const void* v2) 8 | { 9 | return *((int32_t*)v1) - *((int32_t*)v2); 10 | } 11 | 12 | static int32_t sort_array[NUM_MEMBERS]; 13 | 14 | int main(int argc, char* argv[]) 15 | { 16 | int i; 17 | srand(1234); 18 | for (i = 0; i < NUM_MEMBERS; i++) sort_array[i] = i; 19 | for (i = 0; i < NUM_MEMBERS; i++) { 20 | int r = rand() % NUM_MEMBERS; 21 | int32_t tmp; 22 | tmp = sort_array[r]; 23 | sort_array[r] = sort_array[i]; 24 | sort_array[i] = tmp; 25 | } 26 | qsort(&sort_array, NUM_MEMBERS, sizeof(int32_t), intcmp); 27 | 28 | for (i = 1; i < NUM_MEMBERS; i++) { 29 | assert (sort_array[i-1] < sort_array[i] && "NOT SORTED"); 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /scripts/stack_dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sshot="$1" 4 | if [ -z "$sshot" ]; then echo expected snapshot in arg 1; exit 1; fi 5 | if [ ! -d "$sshot" ]; then echo expected snapshot directory; exit 2; fi 6 | arch=`od -An -tx4 "$sshot"/arch | grep 00001` 7 | if [ -z "$arch" ]; then echo only x86-64 supported right now thanks; exit 3; fi 8 | 9 | # from /usr/include/valgrind/libvex_guest_amd64.h 10 | rsp=`od -tx8 -An -j48 -N8 "$sshot"/regs | xargs echo` 11 | rip=`od -tx8 -An -j184 -N8 "$sshot"/regs | xargs echo` 12 | stackbegin=`grep "\[stack\]" "$sshot"/mapinfo | cut -f1 -d'-'` 13 | 14 | off=$( expr `printf "%ld" 0x$rsp` - `printf "%ld" $stackbegin` ) 15 | 16 | od -w8 -tx8 -An -N$off "$sshot"/maps/$stackbegin | grep 0 | grep -v 00000000000 | `dirname $0`/addr2sym.py "$sshot" 17 | echo ========= 18 | echo 0x"$rip" | `dirname $0`/addr2sym.py "$sshot" -------------------------------------------------------------------------------- /src/cpu/armcpustate.h: -------------------------------------------------------------------------------- 1 | #ifndef ARMCPUSTATE_H 2 | #define ARMCPUSTATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "vexcpustate.h" 10 | 11 | class SyscallParams; 12 | 13 | class ARMCPUState : public VexCPUState 14 | { 15 | public: 16 | ARMCPUState(); 17 | ~ARMCPUState(); 18 | void setStackPtr(guest_ptr); 19 | guest_ptr getStackPtr(void) const; 20 | void setPC(guest_ptr); 21 | guest_ptr getPC(void) const; 22 | 23 | #ifdef __arm__ 24 | void setRegs( 25 | const user_regs* regs, const uint8_t* vfpregs, 26 | void* thread_area); 27 | #endif 28 | void setThreadPointer(uint32_t v); 29 | virtual void print(std::ostream& os, const void*) const; 30 | 31 | virtual unsigned int getRetOff(void) const; 32 | virtual unsigned int getStackRegOff(void) const; 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/jitobjcache.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXLLVM_JITOBJCACHE_H 2 | #define VEXLLVM_JITOBJCACHE_H 3 | 4 | #include 5 | 6 | namespace llvm { 7 | class Module; 8 | class MemoryBufferRef; 9 | } 10 | 11 | class JITObjectCache : public llvm::ObjectCache 12 | { 13 | public: 14 | virtual ~JITObjectCache() {} 15 | static std::unique_ptr create(void); 16 | 17 | void notifyObjectCompiled( 18 | const llvm::Module*, llvm::MemoryBufferRef) override; 19 | std::unique_ptr getObject( 20 | const llvm::Module* M) override; 21 | 22 | std::string getCachePath(const llvm::Module& m) const; 23 | 24 | static std::string getModuleHash(const llvm::Module& m); 25 | 26 | protected: 27 | JITObjectCache(const std::string& cd) : cache_dir(cd) {} 28 | 29 | private: 30 | llvm::SmallString<256> cache_dir; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /tests/opcodes/x86_64/fragment.c: -------------------------------------------------------------------------------- 1 | unsigned int xma[4] __attribute__((aligned(0x10))) = {0x92847232,0xAD2314DA,0xC412409A,0x0D219477 }; 2 | unsigned int xmb[4] __attribute__((aligned(0x10))) = {0x322AC6E1,0x82FFB313,0x6612788B,0x56A3B321 }; 3 | unsigned long foo = 0xF1263826472926452ULL; 4 | unsigned long bar = 0x8AB2382017B23AC12ULL; 5 | int main() { 6 | asm volatile("movdqa (%0), %%xmm0" : : "a" (&xma)); 7 | asm volatile("movdqa (%0), %%xmm3" : : "a" (&xmb)); 8 | asm volatile("nop" : : "a" (&foo), "b" (bar)); 9 | #ifdef _FRAG_UNOP 10 | asm volatile("X_UNOP REG1"); 11 | #elif _FRAG_BINOP 12 | asm volatile("X_BINOP REG1, REG2"); 13 | #elif _FRAG_TRIOPI 14 | asm volatile("X_TRIOPIMM $IMM, REG1, REG2"); 15 | #else 16 | #error No op type defined 17 | #endif 18 | asm volatile("mov %rax, %rsi"); 19 | asm volatile("mov $0xe7, %rax"); 20 | asm volatile("mov $0x3c, %rsi"); 21 | asm volatile("xor %rdi, %rdi"); 22 | asm volatile("syscall"); 23 | } -------------------------------------------------------------------------------- /tests/traces-src/primes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | //#define MAXN 100000000 /* maximum value of N */ 8 | //#define P1 1562501 /* = ceil(MAXN/64) */ 9 | //#define P2 50000000 /* = ceil(MAXN/2) */ 10 | //#define P3 5000 /* = ceil(ceil(sqrt(MAXN))/2) */ 11 | #define MAXN 500000 12 | #define P1 7813 13 | #define P2 250000 14 | #define P3 354 15 | 16 | uint32_t sieve[P1]; 17 | 18 | #define GET(b) ((sieve[(b)>>5]>>((b)&31))&1) 19 | 20 | void make() 21 | { 22 | uint32_t i, j, k; 23 | memset(sieve, 0, sizeof(sieve)); 24 | for (k = 1; k <= P3; k++) 25 | if (GET(k)==0) for(j=2*k+1,i=2*k*(k+1);i>5]|=1<<(i&31); 26 | } 27 | 28 | int isprime(int p) { return p==2 || (p>2 && (p&1)==1 && (GET((p-1)>>1)==0)); } 29 | 30 | int main() 31 | { 32 | int i, n; 33 | make(); 34 | for (n = 0, i = 0; i <= MAXN; i++) 35 | if (isprime(i)) n++; 36 | printf("The number of primes below 10^8 is %d.\n", n); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /src/directcache.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRECTCACHE_H 2 | #define DIRECTCACHE_H 3 | 4 | #include 5 | #include 6 | #include "guestmem.h" 7 | 8 | #define DC_SIZE 4096 9 | 10 | template 11 | class DirectCache 12 | { 13 | public: 14 | DirectCache(void) 15 | { 16 | memset(ents, 0, sizeof(ents)); 17 | } 18 | 19 | virtual ~DirectCache() {} 20 | 21 | void put(guest_ptr p, T* t) 22 | { 23 | unsigned int idx; 24 | idx = ptr2slot(p); 25 | ents[idx].ptr = p; 26 | ents[idx].t = t; 27 | } 28 | 29 | T* get(guest_ptr p) const 30 | { 31 | unsigned int idx; 32 | idx = ptr2slot(p); 33 | if (ents[idx].ptr == p) return ents[idx].t; 34 | return NULL; 35 | } 36 | 37 | void flush(void) { memset(ents, 0, sizeof(ents)); } 38 | private: 39 | unsigned int ptr2slot(guest_ptr p) const 40 | { 41 | uintptr_t n; 42 | n = (p.o >> 2); /* who cares about the lowest bits */ 43 | return n % DC_SIZE; 44 | } 45 | 46 | struct dc_pair 47 | { 48 | guest_ptr ptr; 49 | T* t; 50 | }; 51 | 52 | struct dc_pair ents[DC_SIZE]; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/ss_run.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "vexexec.h" 11 | #include "vexcpustate.h" 12 | #include "guestsnapshot.h" 13 | 14 | using namespace llvm; 15 | 16 | static VexExec *vexexec; 17 | 18 | void dumpIRSBs(void) 19 | { 20 | std::cerr << "DUMPING LOGS\n"; 21 | vexexec->dumpLogs(std::cerr); 22 | } 23 | 24 | int main(int argc, char* argv[], char* envp[]) 25 | { 26 | std::unique_ptr g; 27 | 28 | VexCPUState::registerCPUs(); 29 | 30 | if (argc == 1) { 31 | g = Guest::load(); 32 | if (!g) { 33 | fprintf(stderr, 34 | "%s: Couldn't load guest. " 35 | "Did you run VEXLLVM_SAVE?\n", 36 | argv[0]); 37 | } 38 | } else { 39 | g = Guest::load(argv[1]); 40 | } 41 | 42 | assert (g && "Could not load guest"); 43 | vexexec = VexExec::create(g.get()); 44 | assert (vexexec && "Could not create vexexec"); 45 | 46 | vexexec->run(); 47 | 48 | delete vexexec; 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/vexxlate.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXIFACE_H 2 | #define VEXIFACE_H 3 | 4 | #include 5 | #include 6 | 7 | extern "C" { 8 | #include 9 | #include 10 | extern void dispatch_asm_arch(void); 11 | } 12 | #include "arch.h" 13 | 14 | class VexSB; 15 | class FragCache; 16 | 17 | /* vexlate! */ 18 | class VexXlate 19 | { 20 | public: 21 | VexXlate(Arch::Arch arch); 22 | virtual ~VexXlate(); 23 | VexSB* xlate(const void* guest_bytes, uint64_t guest_addr); 24 | void dumpLog(std::ostream& os) const; 25 | 26 | enum VexXlateLogType { 27 | VX_LOG_NONE, 28 | VX_LOG_MEM, 29 | VX_LOG_STDERR 30 | /* XXX ADD MORE */ }; 31 | 32 | 33 | private: 34 | void loadLogType(void); 35 | VexSB* patchBadDecode(const void* guest_bytes, uint64_t guest_addr); 36 | 37 | VexControl vc; 38 | VexArchInfo vai_host; 39 | VexArchInfo vai_guest; 40 | VexAbiInfo vbi; 41 | VexArch arch; 42 | 43 | /* trace the frontend */ 44 | bool trace_fe; 45 | 46 | bool store_fragments; 47 | FragCache *frag_cache; 48 | 49 | int frag_log_fd; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/jitengine.h: -------------------------------------------------------------------------------- 1 | #ifndef JIT_ENGINE_H 2 | #define JIT_ENGINE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace llvm 8 | { 9 | class Function; 10 | class Module; 11 | class ExecutionEngine; 12 | } 13 | 14 | class JITMem; 15 | class JITObjectCache; 16 | 17 | class JITEngine 18 | { 19 | public: 20 | JITEngine(void); 21 | ~JITEngine(void); 22 | llvm::Function* getFunction(const std::string& func_name); 23 | llvm::Module& getModuleForNewFunction(void); 24 | void* getPointerToFunction( llvm::Function*, 25 | std::unique_ptr); 26 | void* getPointerToFunction(llvm::Function* f); 27 | void* getPointerToNamedFunction(const std::string &name); 28 | void moveModule(std::unique_ptr); 29 | private: 30 | std::unique_ptr mod_to_engine( 31 | std::unique_ptr); 32 | 33 | void runPasses(llvm::Module& m); 34 | 35 | std::unique_ptr open_mod; // unjited module 36 | 37 | static bool targets_inited; 38 | 39 | std::map func_addrs; 40 | std::unique_ptr jit_mem; 41 | std::unique_ptr jit_objcache; 42 | unsigned jit_module_c; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/pt_xchk.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "vexexecchk.h" 11 | #include "vexexecfastchk.h" 12 | #include "vexcpustate.h" 13 | #include "ptimgchk.h" 14 | 15 | static VexExec *vexexec; 16 | 17 | void dumpIRSBs(void) 18 | { 19 | std::cerr << "DUMPING LOG\n"; 20 | vexexec->dumpLogs(std::cerr); 21 | } 22 | 23 | int main(int argc, char* argv[], char* envp[]) 24 | { 25 | PTImgChk *gs; 26 | 27 | if (argc < 2) { 28 | fprintf(stderr, "Usage: %s program_path \n", argv[0]); 29 | return -1; 30 | } 31 | 32 | VexCPUState::registerCPUs(); 33 | 34 | gs = GuestPTImg::create(argc - 1, argv + 1, envp); 35 | if (getenv("VEXLLVM_XCHK_SAVE")) { 36 | fprintf(stderr, "XCHK SAVING\n"); 37 | gs->save(); 38 | } 39 | 40 | if (getenv("VEXLLVM_FASTCHK")) 41 | vexexec = VexExec::create(gs); 42 | else 43 | vexexec = VexExec::create(gs); 44 | 45 | assert (vexexec && "Could not create vexexec"); 46 | 47 | vexexec->run(); 48 | 49 | delete vexexec; 50 | delete gs; 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/vexllvm_ss.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #include "elfimg.h" 12 | #include "guestcpustate.h" 13 | #include "guestptimg.h" 14 | #include "procargs.h" 15 | 16 | void dumpIRSBs(void) { std::cerr << "DUMPING LOGS\n"; } 17 | 18 | GuestPTImg* createAttached(void) 19 | { 20 | pid_t pid = atoi(getenv("VEXLLVM_ATTACH")); 21 | auto pa = new ProcArgs(pid); 22 | return GuestPTImg::createAttached(pid, pa->getArgv()); 23 | } 24 | 25 | int main(int argc, char* argv[], char* envp[]) 26 | { 27 | GuestPTImg *gs; 28 | const char *saveas; 29 | 30 | if (argc < 2) { 31 | fprintf(stderr, "Usage: %s program_path \n", argv[0]); 32 | return -1; 33 | } 34 | 35 | if (getenv("VEXLLVM_ATTACH") != NULL) { 36 | gs = createAttached(); 37 | } else { 38 | gs = GuestPTImg::create(argc - 1, argv + 1, envp); 39 | } 40 | 41 | if ((saveas = getenv("VEXLLVM_SAVEAS"))) { 42 | fprintf(stderr, "Saving as %s...\n", saveas); 43 | gs->save(saveas); 44 | } else { 45 | fprintf(stderr, "Saving...\n"); 46 | gs->save(); 47 | } 48 | 49 | delete gs; 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/cpu/ptshadowi386.h: -------------------------------------------------------------------------------- 1 | #ifndef PTSHADOWI386_H 2 | #define PTSHADOWI386_H 3 | 4 | #include "cpu/ptimgi386.h" 5 | #include "ptshadow.h" 6 | 7 | extern "C" { 8 | #include 9 | } 10 | 11 | #define VEXSEG VexGuestX86SegDescr 12 | 13 | class PTShadowI386 : public PTImgI386, public PTShadow 14 | { 15 | public: 16 | PTShadowI386(GuestPTImg* gs, int in_pid); 17 | 18 | // shadow stuff 19 | void printUserRegs(std::ostream& os) const override; 20 | void printFPRegs(std::ostream& os) const override; 21 | void slurpRegisters(void) override; 22 | void pushRegisters(void) override { assert (false && "STUB"); } 23 | 24 | FixupDir canFixup( 25 | const std::vector& insts, 26 | bool has_memlog) const override { assert (false && "STUB"); } 27 | 28 | bool isRegMismatch(void) const override; 29 | bool isMatch(void) const override; 30 | 31 | protected: 32 | /* return true iff on trapped cpuid instruction */ 33 | bool patchCPUID(void) override; 34 | void trapCPUIDs(uint64_t bias) override; 35 | 36 | private: 37 | const VexGuestX86State& getVexState(void) const; 38 | VexGuestX86State& getVexState(void); 39 | 40 | void setupGDT(void); 41 | bool readThreadEntry(unsigned idx, VEXSEG* buf); 42 | }; 43 | #endif 44 | -------------------------------------------------------------------------------- /src/cpu/linux_abi.cc: -------------------------------------------------------------------------------- 1 | #include "guest.h" 2 | #include "guestabi.h" 3 | #include "cpu/linux_abi.h" 4 | 5 | const char* LinuxABI::scregs_i386[] = 6 | { 7 | "EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "EBP", nullptr 8 | }; 9 | #define ABI_LINUX_I386 scregs_i386, \ 10 | "EAX", /* syscall result */ \ 11 | "EBX", /* get exit code */ \ 12 | true /* 32-bit */ 13 | 14 | const char* LinuxABI::scregs_amd64[] = 15 | { 16 | "RAX", "RDI", "RSI", "RDX", "R10", "R8", "R9", nullptr 17 | }; 18 | #define ABI_LINUX_AMD64 scregs_amd64, "RAX", "RDI", false 19 | 20 | /* its possible that the actual instruction can encode 21 | something in the non-eabi case, but we are restricting 22 | ourselves to eabi for now */ 23 | const char* LinuxABI::scregs_arm[] = 24 | { 25 | "R7", "R0", "R1", "R2", "R3", "R4", "R5", nullptr 26 | }; 27 | #define ABI_LINUX_ARM scregs_arm, "R0", "R0", true 28 | 29 | GuestABI* LinuxABI::create(Guest& g) 30 | { 31 | switch (g.getArch()) { 32 | case Arch::X86_64: return new RegStrABI(g, ABI_LINUX_AMD64); 33 | case Arch::ARM: return new RegStrABI(g, ABI_LINUX_ARM); 34 | case Arch::I386: return new RegStrABI(g, ABI_LINUX_I386); 35 | default: 36 | std::cerr << "Unknown guest arch for Linux ABI?\n"; 37 | break; 38 | } 39 | return nullptr; 40 | } 41 | -------------------------------------------------------------------------------- /src/vexcpustate.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXCPUSTATE_H 2 | #define VEXCPUSTATE_H 3 | 4 | #include "guestcpustate.h" 5 | #include "arch.h" 6 | 7 | /* types of exit states we need to worry about on return */ 8 | enum GuestExitType { 9 | GE_IGNORE = 0, /* use regular control path */ 10 | GE_SIGTRAP = 1, 11 | GE_SIGSEGV = 2, 12 | GE_SIGBUS = 3, 13 | GE_EMWARN = 4, 14 | GE_SYSCALL = 5, 15 | GE_CALL = 6, 16 | GE_RETURN = 7, 17 | GE_YIELD = 8, 18 | GE_INT = 9, 19 | /* XXX ADD MORE */ }; 20 | 21 | class VexCPUState : public GuestCPUState 22 | { 23 | public: 24 | VexCPUState(const guest_ctx_field *f) 25 | : GuestCPUState(f) 26 | , exit_type(nullptr) {} 27 | 28 | static VexCPUState *create(Arch::Arch); 29 | 30 | /* byte offset into state data for exit type byte */ 31 | unsigned int getExitTypeOffset(void) const { return state_byte_c; } 32 | void setExitType(GuestExitType et) { *exit_type = (uint8_t)et; } 33 | GuestExitType getExitType(void) { return (GuestExitType)*exit_type; } 34 | 35 | uint8_t* copyOutStateData(void) { 36 | uint8_t *old = GuestCPUState::copyOutStateData(); 37 | exit_type = &state_data[state_byte_c]; 38 | return old; 39 | } 40 | 41 | static void registerCPUs(void); 42 | 43 | protected: 44 | uint8_t *exit_type; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /tests/traces-src/getopt.c: -------------------------------------------------------------------------------- 1 | /* taken from the web example-of-getopt */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int 9 | main (int argc, char **argv) 10 | { 11 | int aflag = 0; 12 | int bflag = 0; 13 | char *cvalue = NULL; 14 | int index; 15 | int c; 16 | 17 | opterr = 0; 18 | 19 | while ((c = getopt (argc, argv, "abc:")) != -1) 20 | switch (c) 21 | { 22 | case 'a': 23 | aflag = 1; 24 | break; 25 | case 'b': 26 | bflag = 1; 27 | break; 28 | case 'c': 29 | cvalue = optarg; 30 | break; 31 | case '?': 32 | if (optopt == 'c') 33 | fprintf (stderr, "Option -%c requires an argument.\n", optopt); 34 | else if (isprint (optopt)) 35 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 36 | else 37 | fprintf (stderr, 38 | "Unknown option character `\\x%x'.\n", 39 | optopt); 40 | return 1; 41 | default: 42 | abort (); 43 | } 44 | 45 | printf ("aflag = %d, bflag = %d, cvalue = %s\n", 46 | aflag, bflag, cvalue); 47 | 48 | printf ("optind=%p. &optind=%p\n", optind, &optind); 49 | assert (optind <= argc && "BAD OPT INDEX"); 50 | for (index = optind; index < argc; index++) 51 | printf ("Non-option argument %s\n", argv[index]); 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/vexjitcache.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXJITCACHE_H 2 | #define VEXJITCACHE_H 3 | 4 | #include "vexfcache.h" 5 | #include "guestmem.h" 6 | #include 7 | 8 | typedef guest_ptr (*vexfunc_t)(void* /* guest cpu state */); 9 | typedef std::map jit_map; 10 | 11 | /* if an auxiliary function is enabled, then this 12 | is the real type of the function. this allows vexexec to pass 13 | the auxiliary state into the translated code. 14 | Ideally, we should probably be hijacking the guest cpu state by 15 | expanding the tail. */ 16 | typedef guest_ptr(*vexauxfunc_t)( 17 | void* /* guest cpu state */, 18 | void* /* auxiliary state */); 19 | 20 | class JITEngine; 21 | 22 | /** 23 | * JIT caches compiled functions as well as translated superblocks 24 | */ 25 | class VexJITCache : public VexFCache 26 | { 27 | public: 28 | VexJITCache(std::shared_ptr, std::unique_ptr); 29 | virtual ~VexJITCache(void); 30 | 31 | vexfunc_t getCachedFPtr(guest_ptr guest_addr); 32 | vexfunc_t getFPtr(void* host_addr, guest_ptr guest_addr); 33 | 34 | void evict(guest_ptr guest_addr) override; 35 | void flush(void) override; 36 | void flush(guest_ptr begin, guest_ptr end) override; 37 | private: 38 | std::unique_ptr jit_engine; 39 | jit_map jit_cache; 40 | DirectCache jit_dc; 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/pt_run.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #include "elfimg.h" 12 | #include "vexexec.h" 13 | #include "vexcpustate.h" 14 | #include "guestptimg.h" 15 | #include "procargs.h" 16 | 17 | static VexExec *vexexec; 18 | 19 | void dumpIRSBs(void) 20 | { 21 | std::cerr << "DUMPING LOGS\n"; 22 | vexexec->dumpLogs(std::cerr); 23 | } 24 | 25 | GuestPTImg* createAttached(void) 26 | { 27 | ProcArgs *pa; 28 | int pid; 29 | 30 | pid = atoi(getenv("VEXLLVM_ATTACH")); 31 | pa = new ProcArgs(pid); 32 | return GuestPTImg::createAttached(pid, pa->getArgv()); 33 | } 34 | 35 | int main(int argc, char* argv[], char* envp[]) 36 | { 37 | GuestPTImg *gs; 38 | 39 | if (argc < 2) { 40 | fprintf(stderr, "Usage: %s program_path \n", argv[0]); 41 | return -1; 42 | } 43 | 44 | VexCPUState::registerCPUs(); 45 | 46 | if (getenv("VEXLLVM_ATTACH") != NULL) { 47 | gs = createAttached(); 48 | } else { 49 | gs = GuestPTImg::create(argc - 1, argv + 1, envp); 50 | } 51 | 52 | gs->patchVDSO(); 53 | 54 | vexexec = VexExec::create(gs); 55 | assert (vexexec && "Could not create vexexec"); 56 | 57 | vexexec->run(); 58 | 59 | delete vexexec; 60 | delete gs; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/cpu/amd64cpustate.h: -------------------------------------------------------------------------------- 1 | #ifndef AMD64CPUSTATE_H 2 | #define AMD64CPUSTATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "vexcpustate.h" 11 | extern "C" { 12 | #include 13 | } 14 | 15 | class SyscallParams; 16 | 17 | class AMD64CPUState : public VexCPUState 18 | { 19 | public: 20 | const static unsigned REGFILE_BYTES = 921; 21 | 22 | AMD64CPUState(); 23 | ~AMD64CPUState(); 24 | void setStackPtr(guest_ptr); 25 | guest_ptr getStackPtr(void) const; 26 | void setPC(guest_ptr); 27 | guest_ptr getPC(void) const; 28 | 29 | virtual unsigned int getFuncArgOff(unsigned int arg_num) const; 30 | virtual unsigned int getRetOff(void) const; 31 | virtual unsigned int getStackRegOff(void) const; 32 | virtual unsigned int getPCOff(void) const; 33 | 34 | virtual void resetSyscall(void); 35 | 36 | #ifdef __amd64__ 37 | void setRegs( 38 | const user_regs_struct& regs, 39 | const user_fpregs_struct& fpregs); 40 | static void setRegs( 41 | VexGuestAMD64State& v, 42 | const user_regs_struct& regs, 43 | const user_fpregs_struct& fpregs); 44 | 45 | #endif 46 | 47 | static uint64_t getRFLAGS(const VexGuestAMD64State& v); 48 | 49 | void setFSBase(uintptr_t base); 50 | uintptr_t getFSBase() const; 51 | 52 | virtual int cpu2gdb(int gdb_off) const; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/cpu/sc_xlate.h: -------------------------------------------------------------------------------- 1 | #ifndef SC_XLATE_H 2 | #define SC_XLATE_H 3 | 4 | #include "syscall/syscalls.h" 5 | 6 | #define SYSCALL_BODY(arch, call) \ 7 | bool arch##SyscallXlate::arch##_##call( \ 8 | Guest& g, \ 9 | SyscallParams& args, \ 10 | unsigned long& sc_ret) 11 | 12 | class AMD64SyscallXlate : public SyscallXlate 13 | { 14 | public: 15 | AMD64SyscallXlate() {} 16 | 17 | int translateSyscall(int sys_nr) const override; 18 | std::string getSyscallName(int sys_nr) const override; 19 | uintptr_t apply(Guest& g, SyscallParams& args) override; 20 | 21 | private: 22 | SYSCALL_HANDLER(AMD64, arch_prctl); 23 | SYSCALL_HANDLER(AMD64, arch_modify_ldt); 24 | }; 25 | 26 | class I386SyscallXlate : public SyscallXlate 27 | { 28 | public: 29 | I386SyscallXlate() {} 30 | 31 | int translateSyscall(int sys_nr) const override; 32 | std::string getSyscallName(int sys_nr) const override; 33 | uintptr_t apply(Guest& g, SyscallParams& args) override; 34 | 35 | private: 36 | SYSCALL_HANDLER(I386, mmap2); 37 | }; 38 | 39 | class ARMSyscallXlate : public SyscallXlate 40 | { 41 | public: 42 | ARMSyscallXlate() {} 43 | 44 | int translateSyscall(int sys_nr) const override; 45 | std::string getSyscallName(int sys_nr) const override; 46 | uintptr_t apply(Guest& g, SyscallParams& args) override; 47 | 48 | private: 49 | SYSCALL_HANDLER(ARM, cacheflush); 50 | SYSCALL_HANDLER(ARM, set_tls); 51 | SYSCALL_HANDLER(ARM, mmap2); 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/memlog.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMLOG_H 2 | #define MEMLOG_H 3 | 4 | #include 5 | #include "guestmem.h" 6 | 7 | namespace llvm { 8 | class StructType; 9 | class Value; 10 | class ConstantInt; 11 | class IntegerType; 12 | class PointerType; 13 | class VectorType; 14 | } 15 | 16 | 17 | class MemLog { 18 | public: 19 | MemLog() { clear(); } 20 | 21 | /* accessors for the logged data */ 22 | void clear() { memset(this, 0, sizeof(*this)); } 23 | bool wasWritten() const { return address.o != 0; } 24 | guest_ptr getAddress() const { return address; } 25 | unsigned long getSize() const { return size; } 26 | const char* getData() const { return &data[0]; } 27 | 28 | /* interface for llvm code gen to record stored */ 29 | static llvm::StructType* getType(); 30 | static void recordStore( 31 | llvm::Value* log_v, 32 | llvm::Value* addr_v, 33 | llvm::Value* data_v, 34 | unsigned int mem_slot); 35 | 36 | /* x86 specific thing... */ 37 | static const unsigned int MAX_STORE_SIZE = 128; 38 | private: 39 | /* XXX: TODO MAKE THIS A PROPER LOG!! */ 40 | guest_ptr address; 41 | unsigned long size; 42 | char data[MAX_STORE_SIZE / 8]; 43 | 44 | /* code generation cache of llvm things */ 45 | static llvm::StructType *type; 46 | static llvm::PointerType *addr_type; 47 | static llvm::IntegerType*size_type; 48 | static llvm::VectorType *data_type; 49 | static const unsigned int address_index; 50 | static const unsigned int size_index; 51 | static const unsigned int data_index; 52 | }; 53 | #endif -------------------------------------------------------------------------------- /scripts/addr2sym.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import os 5 | 6 | 7 | # symtab is a list sorted by address of (address, func_name, length) tuples 8 | def loadSyms(guestpath): 9 | symtab = [] 10 | f = open(guestpath + "/syms", 'r') 11 | # example: xdr_netobj 7f17cac14b70-7f17cac14b81 12 | for l in f: 13 | (func_name, addr_range) = l.split(' ') 14 | (addr_begin, addr_end) = addr_range.split('-') 15 | addr_begin = int('0x'+addr_begin,0) 16 | addr_end = int('0x'+addr_end,0) 17 | symtab.append((addr_begin, func_name, addr_end-addr_begin)) 18 | f.close() 19 | symtab.sort() 20 | return symtab 21 | 22 | # TODO: Binary search 23 | addr2sym_memo = (0, 'DERP DERP BAD FUNC', 1) 24 | def addr2sym(symtab, addr): 25 | global addr2sym_memo 26 | 27 | if addr < addr2sym_memo[0]+addr2sym_memo[2] and \ 28 | addr > addr2sym_memo[0]: 29 | return addr2sym_memo 30 | 31 | 32 | last_s = symtab[0] 33 | for s in symtab: 34 | if s[0] > addr: 35 | if addr < (last_s[0]+last_s[2]): 36 | addr2sym_memo = last_s 37 | return last_s 38 | return None 39 | last_s = s 40 | 41 | if last_s[0] > addr or addr > (last_s[0]+last_s[2]): 42 | return None 43 | 44 | addr2sym_memo = last_s 45 | return last_s 46 | 47 | if len(sys.argv) < 2: 48 | print 'Expect snapshot dir as arg1' 49 | sys.exit(1) 50 | 51 | 52 | 53 | guestpath=sys.argv[1] 54 | symtab = loadSyms(guestpath) 55 | 56 | for l in sys.stdin: 57 | l = l.strip() 58 | s = addr2sym(symtab, int(l,16)) 59 | if s is None: 60 | continue 61 | print l + ": " + s[1] 62 | -------------------------------------------------------------------------------- /src/cpu/ptshadowamd64.h: -------------------------------------------------------------------------------- 1 | #ifndef PTSHADOWAMD64_H 2 | #define PTSHADOWAMD64_H 3 | 4 | #include "cpu/ptimgamd64.h" 5 | #include "ptshadow.h" 6 | 7 | extern "C" { 8 | #include 9 | } 10 | 11 | 12 | class PTShadowAMD64 : public PTImgAMD64, public PTShadow 13 | { 14 | public: 15 | PTShadowAMD64(GuestPTImg* gs, int in_pid); 16 | 17 | // shadow stuff 18 | void printUserRegs(std::ostream& os) const override; 19 | void printFPRegs(std::ostream& os) const override; 20 | void slurpRegisters(void) override; 21 | void pushRegisters(void) override; 22 | 23 | FixupDir canFixup( 24 | const std::vector& insts, 25 | bool has_memlog) const override; 26 | 27 | bool isRegMismatch(void) const override; 28 | bool isMatch(void) const override; 29 | 30 | // ptimg stuff 31 | bool filterSysCall(void) override; 32 | bool doStep(guest_ptr start, guest_ptr end, bool& hit_syscall) override; 33 | void restore(void) override; 34 | 35 | static void vex2ptrace( 36 | const VexGuestAMD64State&, 37 | struct user_regs_struct&, 38 | struct user_fpregs_struct&); 39 | 40 | static void ptrace2vex( 41 | const struct user_regs_struct&, 42 | const struct user_fpregs_struct&, 43 | VexGuestAMD64State&); 44 | 45 | protected: 46 | void vex2ptrace(void); 47 | void ptrace2vex(void); 48 | 49 | // ptimg 50 | void handleBadProgress(void) override; 51 | 52 | private: 53 | const VexGuestAMD64State& getVexState(void) const; 54 | VexGuestAMD64State& getVexState(void); 55 | 56 | bool xchk_eflags; 57 | bool fixup_eflags; 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /src/vexcpustate.cc: -------------------------------------------------------------------------------- 1 | #include "cpu/amd64cpustate.h" 2 | #include "cpu/armcpustate.h" 3 | #include "cpu/i386cpustate.h" 4 | #include "cpu/mips32cpustate.h" 5 | 6 | #include "vexcpustate.h" 7 | 8 | VexCPUState* VexCPUState::create(Arch::Arch arch) 9 | { 10 | switch(arch) { 11 | case Arch::X86_64: return new AMD64CPUState(); 12 | case Arch::I386: return new I386CPUState(); 13 | case Arch::ARM: return new ARMCPUState(); 14 | case Arch::MIPS32: return new MIPS32CPUState(); 15 | default: 16 | assert(!"supported guest architecture"); 17 | } 18 | } 19 | 20 | #if defined(__amd64__) 21 | #include "cpu/ptshadowamd64.h" 22 | #include "cpu/ptshadowi386.h" 23 | #endif 24 | 25 | #ifdef __arm__ 26 | #include "cpu/ptshadowarm.h" 27 | #endif 28 | 29 | void VexCPUState::registerCPUs(void) 30 | { 31 | GuestCPUState::registerCPU( 32 | Arch::X86_64, 33 | [] { return new AMD64CPUState(); }); 34 | GuestCPUState::registerCPU( 35 | Arch::I386, 36 | [] { return new I386CPUState(); }); 37 | GuestCPUState::registerCPU( 38 | Arch::ARM, 39 | [] { return new ARMCPUState(); }); 40 | GuestCPUState::registerCPU( 41 | Arch::MIPS32, 42 | [] { return new MIPS32CPUState(); }); 43 | 44 | #if defined(__amd64__) 45 | PTShadow::registerCPU( 46 | Arch::I386, 47 | [] (GuestPTImg* gpi, int pid) { 48 | return new PTShadowI386(gpi, pid); 49 | } 50 | ); 51 | PTShadow::registerCPU( 52 | Arch::X86_64, 53 | [] (GuestPTImg* gpi, int pid) { 54 | return new PTShadowAMD64(gpi, pid); 55 | } 56 | ); 57 | #elif defined(__arm__) 58 | // pt_arch = new PTImgARM(gpi, pid); 59 | #endif 60 | 61 | } 62 | -------------------------------------------------------------------------------- /tests/opcodes/x86_64/gen_optest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ARCHDIR="tests/opcodes/x86_64" 4 | FRAGFILE="$ARCHDIR/fragment.c" 5 | OPCFLAGS="-Os" 6 | 7 | for op in `cat $ARCHDIR/opcodes.txt`; do 8 | if [ -e $ARCHDIR/OP_$op ]; then 9 | continue 10 | fi 11 | echo generating $op 12 | mkdir -p $ARCHDIR/OP_$op 13 | for r1 in `cat $ARCHDIR/registers.txt`; do 14 | sed "s/X_UNOP/$op/g;s/REG1/$r1/g" \ 15 | $FRAGFILE >"$ARCHDIR/OP_$op/$r1.c" 16 | gcc -D_FRAG_UNOP=1 "$ARCHDIR/OP_$op/$r1.c" $OPCFLAGS -o "$ARCHDIR/OP_$op/$r1" \ 17 | >/dev/null 2>&1 18 | # if [ $? -ne 0 ]; then 19 | # echo "$ARCHDIR/OP_$op/$r1 is bad" 20 | # cat "$ARCHDIR/OP_$op/$r1.c" 21 | # fi 22 | for r2 in `cat $ARCHDIR/registers.txt`; do 23 | sed "s/X_BINOP/$op/g;s/REG1/$r1/g;s/REG2/$r2/g" \ 24 | $FRAGFILE >"$ARCHDIR/OP_$op/$r1-$r2.c" 25 | gcc -D_FRAG_BINOP=1 "$ARCHDIR/OP_$op/$r1-$r2.c" $OPCFLAGS -o "$ARCHDIR/OP_$op/$r1-$r2" \ 26 | >/dev/null 2>&1 27 | # if [ $? -ne 0 ]; then 28 | # echo "$ARCHDIR/OP_$op/$r1-$r2 is bad" 29 | # cat "$ARCHDIR/OP_$op/$r1-$r2.c" 30 | # fi 31 | for imm in 0 1 2 3 4 5 6 7; do 32 | sed "s/X_TRIOPIMM/$op/g;s/REG1/$r1/g;s/REG2/$r2/g;s/IMM/$imm/g" \ 33 | $FRAGFILE >"$ARCHDIR/OP_$op/$imm-$r1-$r2.c" 34 | gcc -D_FRAG_TRIOPI=1 "$ARCHDIR/OP_$op/$imm-$r1-$r2.c" $OPCFLAGS -o "$ARCHDIR/OP_$op/$imm-$r1-$r2" \ 35 | >/dev/null 2>&1 36 | if [ $? -ne 0 ]; then 37 | # echo "$ARCHDIR/OP_$op/$imm-$r1-$r2 is bad" 38 | # cat "$ARCHDIR/OP_$op/$imm-$r1-$r2.c" 39 | break 40 | fi 41 | done 42 | done 43 | done 44 | 45 | rm "$ARCHDIR/OP_$op"/*.c 46 | done 47 | -------------------------------------------------------------------------------- /src/elf_run.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #include "elfimg.h" 12 | #include "vexexec.h" 13 | #include "vexcpustate.h" 14 | #include "guestelf.h" 15 | 16 | static VexExec *vexexec; 17 | 18 | void dumpIRSBs(void) 19 | { 20 | std::cerr << "DUMPING LOGS\n"; 21 | vexexec->dumpLogs(std::cerr); 22 | } 23 | 24 | int main(int argc, char* argv[], char* envp[]) 25 | { 26 | GuestELF *gs; 27 | ElfImg *img; 28 | 29 | if (argc < 2) { 30 | fprintf(stderr, "Usage: %s elf_path \n", argv[0]); 31 | return -1; 32 | } 33 | 34 | std::vector env; 35 | for(int i = 0; envp[i]; ++i) 36 | env.push_back(envp[i]); 37 | int skip = 0; 38 | for(;skip < argc - 1; ++skip) { 39 | std::string arg = argv[skip + 1]; 40 | if(arg.find('=') == std::string::npos) 41 | break; 42 | } 43 | for(int i = 0; i < skip; ++i) { 44 | env.push_back(argv[i + 1]); 45 | } 46 | 47 | img = ElfImg::create(argv[1+skip]); 48 | if (img == NULL) { 49 | fprintf(stderr, "%s: Could not open ELF %s\n", 50 | argv[0], argv[1+skip]); 51 | return -2; 52 | } 53 | 54 | VexCPUState::registerCPUs(); 55 | gs = new GuestELF(img); 56 | gs->setArgv(argc-1-skip, const_cast(argv+1+skip), 57 | env.size(), const_cast(&env[0])); 58 | 59 | vexexec = VexExec::create(gs); 60 | assert (vexexec && "Could not create vexexec"); 61 | 62 | vexexec->run(); 63 | 64 | delete vexexec; 65 | delete img; 66 | delete gs; 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/ptimgchk.h: -------------------------------------------------------------------------------- 1 | #ifndef PTIMGCHK_H 2 | #define PTIMGCHK_H 3 | 4 | #include 5 | #include 6 | #include "guestptimg.h" 7 | #include "ptimgarch.h" 8 | 9 | class MemLog; 10 | class SyscallsMarshalled; 11 | 12 | class PTImgChk : public GuestPTImg 13 | { 14 | public: 15 | PTImgChk( 16 | const char* binname, 17 | bool use_entry = true/* so templates work */); 18 | virtual ~PTImgChk(); 19 | 20 | void printShadow(std::ostream& os) const; 21 | 22 | void stackTraceShadow( 23 | std::ostream& os, 24 | guest_ptr b = guest_ptr(0), 25 | guest_ptr e = guest_ptr(0)); 26 | void printTraceStats(std::ostream& os); 27 | 28 | bool isMatch() const; 29 | 30 | bool fixup(const std::vector& insts); 31 | MemLog* getMemLog(void) { return mem_log; } 32 | unsigned getNumFixups(void) const { return fixup_c; } 33 | 34 | protected: 35 | virtual void handleChild(pid_t pid); 36 | void pushPage(guest_ptr p, GuestMem* = nullptr); 37 | 38 | private: 39 | bool isStackMatch(void) const; 40 | bool isMatchMemLog() const; 41 | 42 | void waitForSingleStep(void); 43 | 44 | void printMemory(std::ostream& os) const; 45 | bool printRootTrace(std::ostream& os) const; 46 | void printRootTraceDat(std::ostream& os, uint64_t dat, 47 | std::set &mptrs, 48 | std::set &cptrs) const; 49 | 50 | guest_ptr getPageMismatch(guest_ptr p) const; 51 | bool isWatchPtrMatch(void) const; 52 | 53 | void readMemLogData(char* data) const; 54 | 55 | /* guest => clobber guest; native => clobber native */ 56 | void doFixupGuest(void); 57 | void doFixupNative(void); 58 | 59 | uint64_t blocks; 60 | 61 | bool log_steps; 62 | 63 | MemLog *mem_log; 64 | bool xchk_stack; 65 | bool xchk_rootptrs; 66 | 67 | guest_ptr xchk_watchptr; 68 | 69 | unsigned fixup_c; 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /tests/snapshot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function test_argc 4 | { 5 | echo testing argc 6 | rm -rf guest-test 7 | VEXLLVM_SAVEAS=guest-test pt_run /bin/ls asdd asdasd asdsdasd 8 | 9 | if [ ! -e 'guest-test' ]; then echo no snapshot made for ls; exit 1; fi 10 | if [ ! -e 'guest-test/argc' ]; then echo no argc saved; exit 2; fi 11 | if [ ! -e 'guest-test/argv' ]; then echo no argv saved; exit 3; fi 12 | 13 | argv_c=`wc -l guest-test/argv | awk ' { print $1 } '` 14 | if [ "$argv_c" != "4" ]; then echo wrong argv count; exit 4; fi 15 | } 16 | 17 | 18 | function test_threads 19 | { 20 | echo testing threads 21 | rm -rf guest-test 22 | tests/snapshot-bin/threads & 23 | tpid="$!" 24 | sleep 1s 25 | VEXLLVM_ATTACH=$tpid VEXLLVM_SAVEAS=guest-test pt_run none 26 | kill -9 $tpid 27 | if [ ! -e guest-test/threads ]; then echo no thread dir; exit 5; fi 28 | tc=`ls guest-test/threads | wc -l` 29 | if [ "$tc" != 4 ]; then echo wrong thread count; exit 6; fi 30 | 31 | diff=`diff guest-test/threads/0 guest-test/threads/1` 32 | if [ -z "$diff" ]; then 33 | echo threads should have different contexts "(e.g. stacks)" 34 | exit 7 35 | fi 36 | } 37 | 38 | function test_readpost 39 | { 40 | rm -rf p read-post-chkpts 41 | mkfifo p 42 | tests/snapshot-bin/read-post p & 43 | rp=$! 44 | sleep 1s 45 | mkdir read-post-chkpts 46 | pushd read-post-chkpts 47 | echo $rp... 48 | pgrep read-post 49 | VEXLLVM_CHKPT_PREPOST=1 ss_chkpt $rp & 50 | sleep 1s 51 | echo "0123456789012345678901234567890" >../p 52 | ok=`od -tx8 chkpt-0001-pre/regs -j16 -N8 -An | xargs printf "%d" | grep 0` 53 | if [ -z "$ok" ]; then echo Expected sysnr=0; exit 8; fi 54 | ok=`od -tx8 chkpt-0001-post/regs -j16 -N8 -An | grep 00020` 55 | if [ -z "$ok" ]; then echo BAD read return value; exit 9; fi 56 | popd 57 | sleep 1s 58 | rm -rf p read-post-chkpts 59 | } 60 | 61 | test_argc 62 | echo ARGC OK 63 | test_threads 64 | echo THREADS OK 65 | test_readpost 66 | echo READPOST OK 67 | -------------------------------------------------------------------------------- /src/vexhelpers.h: -------------------------------------------------------------------------------- 1 | /* handlers loading the libVex helper functions for ccalls. 2 | * Also provides support for some of the more tricky ops (e.g. ctz) */ 3 | #ifndef VEXHELPERS_H 4 | #define VEXHELPERS_H 5 | 6 | #include "Sugar.h" 7 | #include "arch.h" 8 | 9 | namespace llvm 10 | { 11 | class Module; 12 | class Function; 13 | class ExecutionEngine; 14 | } 15 | 16 | typedef ptr_list_t umod_list; 17 | typedef std::list mod_list; 18 | class JITEngine; 19 | 20 | class VexHelpers 21 | { 22 | public: 23 | static std::unique_ptr create(Arch::Arch); 24 | virtual ~VexHelpers(); 25 | umod_list takeModules(void); 26 | llvm::Function* getCallHelper(const char* s); 27 | virtual llvm::Function* getHelper(const char* s) const; 28 | void moveToJITEngine(JITEngine&); 29 | void loadUserMod(const char* path); 30 | void useExternalMod(llvm::Module* m); 31 | 32 | static std::unique_ptr loadModFromPath(const char* path); 33 | protected: 34 | VexHelpers(Arch::Arch arch); 35 | virtual void loadDefaultModules(void); 36 | virtual std::unique_ptr loadMod(const char* path); 37 | private: 38 | void destroyMods(void); 39 | 40 | Arch::Arch arch; 41 | std::unique_ptr helper_mod; 42 | std::unique_ptr vexop_mod; 43 | umod_list user_mods; 44 | const char *bc_dirpath; 45 | 46 | llvm::Module *ext_mod; // owned by someone else 47 | }; 48 | 49 | class VexHelperDummy : public VexHelpers 50 | { 51 | public: 52 | VexHelperDummy(Arch::Arch a) : VexHelpers(a) 53 | {} 54 | virtual ~VexHelperDummy() {} 55 | virtual llvm::Function* getHelper(const char* s) const 56 | { 57 | /* can't be null or we'll wind up 58 | * terminating early when we hit a ccall */ 59 | return (llvm::Function*)0xb055cafe; 60 | } 61 | 62 | protected: 63 | virtual std::unique_ptr loadMod(const char* path); 64 | }; 65 | 66 | 67 | extern std::unique_ptr theVexHelpers; 68 | 69 | #endif -------------------------------------------------------------------------------- /scripts/build_helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eoux pipefail 4 | 5 | VEXDIR="$1" 6 | OUTDIR="$2" 7 | 8 | cd "$VEXDIR" 9 | ./autogen.sh 10 | ./configure CFLAGS=-O2 CXXFLAGS=-O2 --prefix=/usr 11 | make -j9 12 | 13 | cd VEX 14 | CLANGCMD="clang -emit-llvm -Wall -DHAVE_CONFIG_H -I. -I.. -I.. -I../include -I../VEX/pub -I../VEX/pub -DVGA_amd64=1 -DVGO_linux=1 -DVGP_amd64_linux=1 -DVGPV_amd64_linux_vanilla=1 -Ipriv -m64 -O2 -g -std=gnu99 -fno-stack-protector -fno-strict-aliasing -fno-builtin -fomit-frame-pointer -Wbad-function-cast -fstrict-aliasing -O2 -MT " 15 | 16 | $CLANGCMD priv/libvex_amd64_linux_a-guest_amd64_helpers.bc -MD -MP -MF priv/.deps/libvex_amd64_linux_a-guest_amd64_helpers.Tpo -c -o priv/libvex_amd64_linux_a-guest_amd64_helpers.bc priv/guest_amd64_helpers.c 17 | $CLANGCMD priv/libvex_amd64_linux_a-guest_generic_x87.bc -MD -MP -MF priv/.deps/libvex_amd64_linux_a-guest_generic_x87.Tpo -c -o priv/libvex_amd64_linux_a-guest_generic_x87.bc priv/guest_generic_x87.c 18 | llvm-link -o libvex_amd64_helpers.debug.bc priv/*.bc 19 | opt -O3 --strip -o libvex_amd64_helpers.bc libvex_amd64_helpers.debug.bc 20 | rm priv/*.bc 21 | 22 | $CLANGCMD priv/libvex_amd64_linux_a-guest_x86_helpers.bc -MD -MP -MF priv/.deps/libvex_amd64_linux_a-guest_x86_helpers.Tpo -c -o priv/libvex_amd64_linux_a-guest_x86_helpers.bc priv/guest_x86_helpers.c 23 | $CLANGCMD priv/libvex_amd64_linux_a-guest_generic_x87.bc -MD -MP -MF priv/.deps/libvex_amd64_linux_a-guest_generic_x87.Tpo -c -o priv/libvex_amd64_linux_a-guest_generic_x87.bc priv/guest_generic_x87.c 24 | llvm-link -o libvex_x86_helpers.debug.bc priv/*.bc 25 | opt -O3 --strip -o libvex_x86_helpers.bc libvex_x86_helpers.debug.bc 26 | rm priv/*.bc 27 | 28 | $CLANGCMD priv/libvex_amd64_linux_a-guest_arm_helpers.bc -MD -MP -MF priv/.deps/libvex_amd64_linux_a-guest_arm_helpers.Tpo -c -o priv/libvex_amd64_linux_a-guest_arm_helpers.bc priv/guest_arm_helpers.c 29 | opt -O3 --strip -o libvex_arm_helpers.bc priv/*.bc 30 | rm priv/*.bc 31 | 32 | mv *helpers.bc "$2"/ -------------------------------------------------------------------------------- /scripts/stat_analyzer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # analyze stats on different binaries 5 | # 6 | OPTFLAGS="O1 O2 O3 O4 Os g" 7 | if [ -z "$OPTDIR1" ]; then 8 | OPTDIR1="opt-traces" 9 | fi 10 | 11 | if [ -z "$OPTDIR2" ]; then 12 | OPTDIR2="opt-traces" 13 | fi 14 | 15 | if [ -z "$OUTMINED" ]; then 16 | OUTMINED="opt-traces/mined" 17 | fi 18 | mkdir -p $OUTMINED 19 | 20 | for a in $OPTDIR1/O2/traces-out/*.trace.err; do 21 | TESTNAME=`echo "$a" | sed "s/\//\n/g" | tail -n1` 22 | for optfl in $OPTFLAGS; do 23 | for optfl2 in $OPTFLAGS; do 24 | if [ $optfl \< $optfl2 ]; then 25 | continue 26 | fi 27 | diff $OPTDIR1/$optfl/traces-out/$TESTNAME \ 28 | $OPTDIR2/$optfl2/traces-out/$TESTNAME \ 29 | | grep STAT >$OUTMINED/$TESTNAME."$optfl"."$optfl2" 30 | 31 | if [ "$OPTDIR1" != "$OPTDIR2" ]; then 32 | diff $OPTDIR1/$optfl2/traces-out/$TESTNAME \ 33 | $OPTDIR2/$optfl/traces-out/$TESTNAME \ 34 | | grep STAT >$OUTMINED/$TESTNAME."$optfl2"."$optfl" 35 | fi 36 | done 37 | done 38 | done 39 | 40 | # merged tallies 41 | for optfl in $OPTFLAGS; do 42 | for optfl2 in $OPTFLAGS; do 43 | if [ $optfl \< $optfl2 ]; then 44 | continue 45 | fi 46 | 47 | cut -d' ' -f4 $OUTMINED/*.trace.err."$optfl"."$optfl2" | \ 48 | sort | \ 49 | uniq -c >$OUTMINED/"$optfl"."$optfl2" 50 | 51 | if [ "$OPTDIR1" != "$OPTDIR2" ]; then 52 | cut -d' ' -f4 $OUTMINED/*.trace.err."$optfl2"."$optfl" | \ 53 | sort | \ 54 | uniq -c >$OUTMINED/"$optfl2"."$optfl" 55 | fi 56 | done 57 | done 58 | 59 | #finally, summaries 60 | rm -f $OUTMINED/ops.sum 61 | for optfl in $OPTFLAGS; do 62 | for optfl2 in $OPTFLAGS; do 63 | if [ $optfl \< $optfl2 ]; then 64 | continue 65 | fi 66 | 67 | echo "$optfl.$optfl2 " `cut -f2 -d'I' $OUTMINED/"$optfl"."$optfl2" | \ 68 | sort | \ 69 | uniq | \ 70 | wc -l`>>$OUTMINED/ops.sum 71 | 72 | 73 | if [ "$OPTDIR1" != "$OPTDIR2" ]; then 74 | echo "$optfl2.$optfl " `cut -f2 -d'I' $OUTMINED/"$optfl2"."$optfl" | \ 75 | sort | \ 76 | uniq | \ 77 | wc -l`>>$OUTMINED/ops.sum 78 | fi 79 | done 80 | done -------------------------------------------------------------------------------- /src/dump_loader.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "guestptimg.h" 10 | #include 11 | #include 12 | #include 13 | 14 | void dumpIRSBs(void) {} 15 | 16 | static bool loadEntry( 17 | GuestMem* mem, 18 | pid_t pid, 19 | const char* save_arg, 20 | std::istream& is) 21 | { 22 | char line_buf[256]; 23 | 24 | is.get(line_buf, 256, '\n'); 25 | if(is.fail()) return false; 26 | is.get(); 27 | 28 | ProcMap m(mem, pid, line_buf); 29 | 30 | std::cerr << m.getBase() 31 | << " sz: " << (void*)(intptr_t)m.getByteCount() 32 | << " prot: " << std::hex << m.getProt() 33 | << " lib: " << m.getLib() 34 | << std::endl; 35 | 36 | std::ostringstream save_fname; 37 | save_fname << save_arg << "." << pid << "." << m.getBase(); 38 | 39 | char* buffer = (char*)malloc(m.getByteCount()); 40 | for(unsigned int i = 0; i < m.getByteCount(); i += sizeof(long)) { 41 | *(long*)&buffer[i] = ptrace( 42 | PTRACE_PEEKTEXT, pid, m.getBase().o + i, NULL); 43 | } 44 | std::ofstream o(save_fname.str().c_str()); 45 | o.write(buffer, m.getByteCount()); 46 | free(buffer); 47 | 48 | return true; 49 | } 50 | 51 | int main(int argc, char *argv[], char *envp[]) 52 | { 53 | if(argc < 2) { 54 | std::cerr << "Usage: " << argv[0] 55 | << " prog args ..." << std::endl; 56 | exit(1); 57 | } 58 | 59 | pid_t pid = fork(); 60 | int err; 61 | if(!pid) { 62 | ptrace(PTRACE_TRACEME, 0, NULL, NULL); 63 | char * env[] = { NULL }; 64 | err = execvpe(argv[1], &argv[1], env); 65 | assert (err != -1 && "EXECVE FAILED. NO PTIMG!"); 66 | } 67 | wait(NULL); 68 | ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL); 69 | wait(NULL); 70 | 71 | std::ostringstream map_fname; 72 | map_fname << "/proc/" << pid << "/maps"; 73 | 74 | GuestMem* mem = new GuestMem(); 75 | std::ifstream i(map_fname.str().c_str()); 76 | while (loadEntry(mem, pid, argv[1], i)); 77 | 78 | kill(pid, SIGKILL); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /src/vexfcache.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXFCACHE_H 2 | #define VEXFCACHE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "arch.h" 9 | #include "directcache.h" 10 | 11 | namespace llvm 12 | { 13 | class Function; 14 | } 15 | 16 | class VexSB; 17 | class VexXlate; 18 | 19 | typedef std::map> vexsb_map; 20 | typedef std::map func_map; 21 | 22 | // function cache of vsb's */ 23 | class VexFCache 24 | { 25 | public: 26 | /* makes own vexxlate */ 27 | VexFCache(Arch::Arch arch); 28 | /* claims ownership of vexxlate */ 29 | VexFCache(std::shared_ptr vexxlate); 30 | 31 | virtual ~VexFCache(void); 32 | 33 | llvm::Function* genFunctionByVSB(VexSB* vsb); 34 | 35 | /* do not try to free anything returned here!!! */ 36 | VexSB* getVSB(void* hostptr, guest_ptr guest_addr); 37 | llvm::Function* getFunc(void* hostptr, guest_ptr guest_addr); 38 | 39 | VexSB* getCachedVSB(guest_ptr guest_addr); 40 | llvm::Function* getCachedFunc(guest_ptr guest_addr); 41 | 42 | virtual void evict(guest_ptr guest_addr); 43 | void dumpLog(std::ostream& os) const; 44 | virtual void setMaxCache(unsigned int x); 45 | virtual void flush(void); 46 | virtual void flush(guest_ptr begin, guest_ptr end); 47 | 48 | unsigned int size(void) const { return vexsb_cache.size(); } 49 | protected: 50 | unsigned int getMaxCache(void) const { return max_cache_ents; } 51 | func_map::iterator funcBegin() { return func_cache.begin(); } 52 | func_map::iterator funcEnd() { return func_cache.end(); } 53 | func_map::iterator funcBegin(guest_ptr b) { 54 | return func_cache.lower_bound(b); } 55 | func_map::iterator funcEnd(guest_ptr e) { 56 | return func_cache.upper_bound(e); } 57 | 58 | guest_ptr selectVictimAddress(void) const; 59 | private: 60 | VexSB* allocCacheVSB(void* hostptr, guest_ptr guest_addr); 61 | 62 | bool dump_llvm; 63 | 64 | std::shared_ptr xlate; 65 | unsigned int max_cache_ents; 66 | 67 | vexsb_map vexsb_cache; 68 | DirectCache vexsb_dc; 69 | 70 | func_map func_cache; 71 | DirectCache func_dc; 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vexllvm 2 | 3 | This is a dynamic binary translator for converting machine code to LLVM IR. 4 | 5 | ## Build 6 | 7 | First, install [valgrind](https://valgrind.org) for its libvex headers. 8 | 9 | Next, build [guestlib](https://github.com/heyitsanthony/guestlib). Create a symlink `guestlib` in the root directory or specify it using by setting `GUESTLIB_PATH`. 10 | 11 | The build system is just a primitive Makefile that only needs a call to `make`. If `llvm-config` isn't in the `PATH` (e.g., gentoo, custom LLVM build), specify it: 12 | ```sh 13 | LLVMCONFIG_PATH=/usr/lib64/llvm/8/bin/llvm-config make 14 | ``` 15 | 16 | ### LLVM debugging build 17 | 18 | If debugging, it's useful to compile Release+Asserts to catch LLVM issues that wouldn't show up in a release build: 19 | ```sh 20 | cmake -DLLVM_ENABLE_RTTI=ON -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=Release ../llvm-8.0.0.src 21 | make 22 | ``` 23 | 24 | ## JIT execution 25 | 26 | ### Machine code through LLVM JIT 27 | 28 | A guest program is loaded into the host process, then JIT'd via `pt_run`: 29 | ```sh 30 | bin/pt_run /bin/ls / 31 | ``` 32 | 33 | ### Cross-checking JIT against host 34 | 35 | vexllvm can cross-check its JIT execution against host hardware to detect mismatches between JIT semantics and hardware: 36 | ```sh 37 | GUEST_STEP_GAUGE=1000 bin/pt_xchk /bin/ls / 38 | ``` 39 | 40 | ### Process snapshots 41 | 42 | Process snapshots can be saved by setting `VEXLLVM_SAVE` or `VEXLLVM_SAVEAS` environment variables, then loaded and run multiple times via `ss_run`: 43 | ```sh 44 | VEXLLVM_SAVE=1 bin/pt_run /bin/ls / 45 | bin/ss_run 46 | bin/ss_run 47 | ``` 48 | 49 | ### Nested JIT 50 | 51 | The JIT can run inside itself using `rebase` binaries which are linked at non-conflicting addresses. This is useful in cross-checking mode for discovering deep JIT bugs: 52 | ```sh 53 | VEXLLVM_SAVE=1 bin/pt_run /bin/ls / 54 | bin/pt_xchk_rebase bin/ss_run 55 | ``` 56 | 57 | ### IR debugging 58 | 59 | This dumps a trace of the vex frontend and llvm IR to stderr: 60 | ```sh 61 | VEXLLVM_DUMP_LLVM=1 VEXLLVM_DISPATCH_TRACE=stderr VEXLLVM_SB_LOG=stderr VEXLLVM_TRACE_FE=stdout bin/pt_run /bin/ls / 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /src/memlog.cc: -------------------------------------------------------------------------------- 1 | #include "genllvm.h" 2 | #include "memlog.h" 3 | #include 4 | 5 | using namespace llvm; 6 | 7 | StructType* MemLog::type = NULL; 8 | PointerType* MemLog::addr_type = NULL; 9 | IntegerType* MemLog::size_type = NULL; 10 | VectorType* MemLog::data_type = NULL; 11 | 12 | const unsigned int MemLog::address_index = 0; 13 | const unsigned int MemLog::size_index = 1; 14 | const unsigned int MemLog::data_index = 2; 15 | 16 | 17 | StructType* MemLog::getType(void) 18 | { 19 | if(type) 20 | return type; 21 | LLVMContext& gctx(getGlobalContext()); 22 | 23 | addr_type = PointerType::get( 24 | IntegerType::get(gctx, 8), 0); 25 | size_type = IntegerType::get(gctx, 26 | sizeof(unsigned long) * 8); 27 | data_type = VectorType::get( 28 | IntegerType::get(gctx, 8), MAX_STORE_SIZE / 8 ); 29 | 30 | /* add all fields to types vector from structure */ 31 | std::vector types; 32 | 33 | types.push_back(addr_type); 34 | types.push_back(size_type); 35 | types.push_back(data_type); 36 | 37 | type = StructType::get(gctx, types, "GuestMem::Log"); 38 | return type; 39 | } 40 | 41 | void MemLog::recordStore( 42 | Value* log_v, Value* addr_v, Value* data_v, unsigned int mem_slot) 43 | { 44 | IRBuilder<> *builder; 45 | Value *log_entry; 46 | LLVMContext &gctx(getGlobalContext()); 47 | unsigned bits; 48 | 49 | builder = theGenLLVM->getBuilder(); 50 | log_entry = UndefValue::get(type); 51 | log_entry = builder->CreateInsertValue( 52 | log_entry, 53 | builder->CreateIntToPtr(addr_v, addr_type), 54 | address_index); 55 | 56 | bits = data_v->getType()->getPrimitiveSizeInBits(); 57 | log_entry = builder->CreateInsertValue( 58 | log_entry, 59 | ConstantInt::get( 60 | gctx, APInt(sizeof(unsigned long) * 8, bits / 8)), 61 | size_index, 62 | "logEntryA"); 63 | 64 | data_v = builder->CreateBitCast( 65 | data_v, IntegerType::get(gctx, bits)); 66 | data_v = builder->CreateZExt( 67 | data_v, IntegerType::get(gctx, MAX_STORE_SIZE)); 68 | log_entry = builder->CreateInsertValue( 69 | log_entry, 70 | builder->CreateBitCast(data_v, data_type), 71 | data_index, "logEntryV"); 72 | 73 | StoreInst* si = builder->CreateStore(log_entry, log_v); 74 | si->setAlignment(8); 75 | } 76 | -------------------------------------------------------------------------------- /scripts/mkreport.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import time 3 | import sys 4 | import os 5 | 6 | def dump_test_list(tests): 7 | global bad_map 8 | global good_map 9 | global mismatch_map 10 | print "" 11 | for t in tests: 12 | print "" 13 | if t in bad_map: 14 | print "" 15 | elif t in good_map: 16 | print "" 17 | else: 18 | print "" 19 | if t in mismatch_map: 20 | print "" 21 | else: 22 | print "" 23 | print "" 24 | print "
TestStatus
" + t + "BADOK???MISMATCH
" 25 | 26 | if "TRACEPATH" in os.environ: 27 | testpath=os.environ["TRACEPATH"] 28 | else: 29 | testpath="tests/traces-out" 30 | 31 | if "REPORTNAME" in os.environ: 32 | reportname=os.environ["REPORTNAME"] 33 | else: 34 | reportname="TEST DUMP" 35 | 36 | 37 | bad_tests = open(testpath + "/tests.bad", "r") 38 | ok_tests = open(testpath + "/tests.ok", "r") 39 | mismatch_tests = open(testpath + '/tests.mismatch', 'r') 40 | 41 | bad_map = dict() 42 | good_map = dict() 43 | mismatch_map = dict() 44 | all_tests = [] 45 | for f in bad_tests: 46 | bad_map[f[:-1]] = True 47 | all_tests.append(f[:-1]) 48 | 49 | for f in ok_tests: 50 | good_map[f[:-1]] = True 51 | all_tests.append(f[:-1]) 52 | 53 | for f in mismatch_tests: 54 | mismatch_map[f[:-1]] = True 55 | 56 | print "GENERATED BY MKREPORT.PY" 57 | 58 | 59 | print "

" + reportname + "

Date: " + time.ctime() + "
Host: " + os.uname()[1] +"
" 60 | 61 | all_tests.sort() 62 | 63 | time.strftime("%y-%m-%d") 64 | 65 | 66 | unit_tests = filter(lambda x : "tests" in x, all_tests) 67 | bin_tests = filter(lambda x : not "tests" in x, all_tests) 68 | 69 | print "

Unit Tests:
" 70 | dump_test_list(unit_tests) 71 | print "

" 72 | 73 | print "

Bin Tests:
" 74 | dump_test_list(bin_tests) 75 | print "

" 76 | 77 | print "

Final Count:
" 78 | print "OK: " + str(len(good_map)) + "
" 79 | print "Failed: " + str(len(bad_map)) + "
" 80 | print "Mismatched: " + str(len(mismatch_map)) + "
" 81 | print "

" 82 | 83 | print "" 84 | -------------------------------------------------------------------------------- /tests/busybox_cmd.txt: -------------------------------------------------------------------------------- 1 | tests/busybox/busybox-arch adjtimex 2 | tests/busybox/busybox-arch arp 3 | tests/busybox/busybox-arch arping 4 | tests/busybox/busybox-arch awk 5 | tests/busybox/busybox-arch base64 tests/bin_cmd.txt 6 | tests/busybox/busybox-arch basename /tmp/foo 7 | tests/busybox/busybox-arch brctl show 8 | tests/busybox/busybox-arch bzip2 -kf tests/bin_cmd.txt 9 | tests/busybox/busybox-arch mv tests/bin_cmd.txt.bz2 /tmp/test.bz2 10 | tests/busybox/busybox-arch bzcat /tmp/test.txt.bz2 11 | tests/busybox/busybox-arch bunzip2 -f /tmp/test.txt.bz2 12 | tests/busybox/busybox-arch diff tests/bin_cmd.txt /tmp/test.txt 13 | tests/busybox/busybox-arch chmod -w /tmp/test.txt 14 | tests/busybox/busybox-arch rm -f /tmp/test.txt 15 | tests/busybox/busybox-arch cksum tests/bin_cmd.txt 16 | tests/busybox/busybox-arch date --date="%D %k %M" 17 | tests/busybox/busybox-arch df 18 | tests/busybox/busybox-arch dirname tests/xyz 19 | tests/busybox/busybox-arch dmesg 20 | tests/busybox/busybox-arch du 21 | tests/busybox/busybox-arch echo foo 22 | tests/busybox/busybox-arch find src -name vexexec.cc 23 | tests/busybox/busybox-arch grep arm Makefile 24 | tests/busybox/busybox-arch gzip -kf tests/bin_cmd.txt 25 | tests/busybox/busybox-arch cp tests/bin_cmd.txt.gz /tmp/test.gz 26 | tests/busybox/busybox-arch gzcar /tmp/test.txt.gz 27 | tests/busybox/busybox-arch gunzip -f /tmp/test.txt.gz 28 | tests/busybox/busybox-arch cmp tests/bin_cmd.txt /tmp/test.txt 29 | tests/busybox/busybox-arch rm -f /tmp/test.txt 30 | tests/busybox/busybox-arch hostname 31 | tests/busybox/busybox-arch ifconfig 32 | tests/busybox/busybox-arch lpq 33 | tests/busybox/busybox-arch ls 34 | tests/busybox/busybox-arch ls -al 35 | tests/busybox/busybox-arch lsmod 36 | tests/busybox/busybox-arch lspci 37 | tests/busybox/busybox-arch lsusb 38 | tests/busybox/busybox-arch md5sum tests/bin_cmd.txt 39 | tests/busybox/busybox-arch ping 127.0.0.1 40 | tests/busybox/busybox-arch pwd 41 | tests/busybox/busybox-arch route 42 | tests/busybox/busybox-arch runlevel 43 | tests/busybox/busybox-arch sed 44 | tests/busybox/busybox-arch sleep 1 45 | tests/busybox/busybox-arch sort tests/bin_cmd.txt 46 | tests/busybox/busybox-arch strings bin/elf_run 47 | tests/busybox/busybox-arch tail tests/bin_cmd.txt 48 | tests/busybox/busybox-arch uname 49 | tests/busybox/busybox-arch wc tests/bin_cmd.txt 50 | tests/busybox/busybox-arch which ls 51 | -------------------------------------------------------------------------------- /tests/bin_cmds.txt: -------------------------------------------------------------------------------- 1 | # 2 | #/usr/bin 3 | # 4 | #/usr/bin/bzz 5 | # 6 | #/usr/bin/zip 7 | /usr/bin/arch 8 | /usr/bin/llvm-objdump 9 | /usr/bin/llvm-gfortran 10 | /usr/bin/llvm-ar 11 | /usr/bin/mplayer 12 | /usr/bin/mencoder 13 | /usr/bin/lame 14 | /usr/bin/whois 15 | /usr/bin/git 16 | /usr/bin/gcc 17 | /usr/bin/cal 18 | /usr/bin/fortune 19 | /usr/bin/svn 20 | /usr/bin/file 21 | /usr/bin/free 22 | /usr/bin/stat 23 | /usr/bin/flac 24 | /usr/bin/nm 25 | /usr/bin/nasm 26 | /usr/bin/unzip 27 | /usr/bin/size 28 | /usr/bin/python2.7 <<< "print 1+1" 29 | /usr/bin/python3 <<< "print(1+1)" 30 | /usr/bin/perl <<< "print 1+1" 31 | /usr/bin/bc -l <<< "s(10)+c(10)-e(1)*l(5)" 32 | /usr/bin/ar 33 | /usr/bin/unrar 34 | /usr/bin/bison 35 | /usr/bin/convert 36 | /usr/bin/yasm 37 | #/usr/bin/gcc 38 | /usr/bin/ld 39 | /usr/bin/w 40 | /usr/bin/curl 41 | /usr/bin/ncat 42 | /usr/bin/namei 43 | /usr/bin/nmap 44 | /usr/bin/nice 45 | /usr/bin/mpck 46 | /usr/bin/objdump 47 | /usr/bin/prtstat 48 | /usr/bin/expr 49 | /usr/bin/find 50 | /usr/bin/renice 51 | /usr/bin/getopt 52 | /usr/bin/sleep 53 | /usr/bin/sox 54 | /usr/bin/uptime 55 | /usr/bin/madplay 56 | /usr/bin/mpg123 57 | /usr/bin/make 58 | /usr/bin/mp2enc 59 | /usr/bin/printf 60 | /usr/bin/truncate 61 | /usr/bin/pwdx 62 | /usr/bin/cvs 63 | /usr/bin/rpcgen 64 | /usr/bin/jpegicc 65 | /usr/bin/xvinfo 66 | /usr/bin/pidstat 67 | /usr/bin/pmap 68 | /usr/bin/lavplay 69 | /usr/bin/readelf 70 | /usr/bin/objcopy 71 | /usr/bin/id3tag 72 | /usr/bin/hmac256 73 | /usr/bin/hostn 74 | /usr/bin/whoami 75 | /usr/bin/iostat 76 | /usr/bin/mpstat 77 | /usr/bin/vmstat 78 | /usr/bin/diff 79 | /usr/bin/perf 80 | /usr/bin/rsaperf 81 | /usr/bin/oggdec 82 | /usr/bin/oggenc 83 | /usr/bin/ogginfo 84 | /usr/bin/sha256sum /usr/bin/sha256sum 85 | /usr/bin/md5sum /usr/bin/md5sum 86 | # 87 | #sbin 88 | # 89 | /sbin/arp 90 | /sbin/rtstat --count 2 91 | /sbin/ifconfig 92 | /sbin/iwlist 93 | # 94 | #bin 95 | # 96 | /bin/true 97 | /bin/false 98 | /bin/tar --help 99 | /bin/awk 100 | /bin/pwd 101 | /bin/dmesg 102 | /bin/hostname 103 | /bin/df 104 | /bin/du 105 | /bin/echo 106 | /bin/grep 107 | /bin/sed 108 | /bin/seq 109 | /bin/uname 110 | /bin/tr 111 | /bin/cut 112 | /bin/env 113 | /bin/groups 114 | /bin/ln 115 | /bin/mkdir 116 | /bin/mknod 117 | /bin/basename 118 | /bin/ls 119 | /bin/ls -lah 120 | -------------------------------------------------------------------------------- /support/vexops.c: -------------------------------------------------------------------------------- 1 | /* stupid vex count ops */ 2 | #include 3 | #include 4 | 5 | /* leading sign bits (not including topmost) */ 6 | uint32_t vexop_cls32(uint32_t v) 7 | { 8 | unsigned ret = 0; 9 | if (!(v & 0x80000000)) return 0; 10 | v <<= 1; 11 | while ((v & 0x80000000)) { 12 | ret++; 13 | v <<= 1; 14 | } 15 | return ret; 16 | } 17 | 18 | /* leading sign bits (not including topmost) */ 19 | uint64_t vexop_cls64(uint64_t v) 20 | { 21 | unsigned ret = 0; 22 | if (!(v & 0x8000000000000000)) return 0; 23 | v <<= 1; 24 | while ((v & 0x8000000000000000)) { 25 | ret++; 26 | v <<= 1; 27 | } 28 | return ret; 29 | } 30 | 31 | 32 | /* count trailing zeros-- 11100 = 2, 110 = 1, 11000 = 3 */ 33 | uint64_t vexop_ctz64(uint64_t v) 34 | { 35 | int ret = 0; 36 | if (v == 0) return 64; 37 | while ((v & 1) == 0) { 38 | ret++; 39 | v >>= 1; 40 | } 41 | return ret; 42 | } 43 | 44 | /* count leading zeros-- 00001 = 4, 01 = 1, 0001, = 3 */ 45 | uint64_t vexop_clz64(uint64_t v) 46 | { 47 | int ret = 0; 48 | if (v == 0) return 64; 49 | while ((v & (1ULL << 63ULL)) == 0) { 50 | ret++; 51 | v <<= 1; 52 | } 53 | return ret; 54 | } 55 | 56 | uint32_t vexop_ctz32(uint32_t v) 57 | { 58 | int ret = 0; 59 | if (v == 0) return 32; 60 | while ((v & 1) == 0) { 61 | ret++; 62 | v >>= 1; 63 | } 64 | return ret; 65 | } 66 | 67 | uint32_t vexop_clz32(uint32_t v) 68 | { 69 | int ret = 0; 70 | if (v == 0) return 32; 71 | while ((v & (1UL << 31UL)) == 0) { 72 | ret++; 73 | v <<= 1; 74 | } 75 | return ret; 76 | } 77 | 78 | uint32_t vexop_cmpf64(double f1, double f2) 79 | { 80 | if (f1 == f2) return Ircr_EQ; 81 | if (f1 < f2) return Ircr_LT; 82 | if (f1 > f2) return Ircr_GT; 83 | return Ircr_UN; 84 | } 85 | 86 | uint32_t vexop_cmpf32(float f1, float f2) 87 | { 88 | if (f1 == f2) return Ircr_EQ; 89 | if (f1 < f2) return Ircr_LT; 90 | if (f1 > f2) return Ircr_GT; 91 | return Ircr_UN; 92 | } 93 | 94 | double vexop_minf64(double f1, double f2) 95 | { 96 | if (f1 < f2) return f1; 97 | return f2; 98 | } 99 | 100 | float vexop_maxf32(float f1, float f2) 101 | { 102 | if (f1 > f2) return f1; 103 | return f2; 104 | } 105 | 106 | double vexop_absf64(double f) { return (f < 0) ? -f : f; } 107 | float vexop_absf32(float f) { return (f < 0) ? -f : f; } 108 | -------------------------------------------------------------------------------- /src/cpu/amd64_trampoline.s: -------------------------------------------------------------------------------- 1 | 2 | //#define XMM_BASE 224 3 | 4 | .data 5 | amd64_trampoline_pc: .long 0 6 | 7 | .text 8 | .global amd64_trampoline 9 | .type amd64_trampoline,%function 10 | .align 16 11 | 12 | /* %RDI = pointer to vex guest state */ 13 | amd64_trampoline: 14 | /* taken from libvex_guest_amd64.h, should probably use ptrace regs */ 15 | 16 | // save PC-- we'll jump to it at the end 17 | pushq %rdi 18 | movq 184(%rdi), %rax 19 | movq %rax, (amd64_trampoline_pc) 20 | 21 | // load the thread register, %fs (FIRST BUG XCHK FOUND!) 22 | // The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9. 23 | // A system-call is done via the syscall instruction. 24 | // The kernel destroys registers %rcx and %r11. 25 | // The number of the syscall has to be passed in register %rax. 26 | movq $158, %rax /* arch_prctl */ 27 | movq 208(%rdi), %rsi /* %fs value */ 28 | movq $0x1002, %rdi /* ARCH_SET_FS */ 29 | syscall 30 | 31 | popq %rdi /* restore vex state to rdi */ 32 | 33 | /* first, fake rflags */ 34 | /* we cheat and store rflags in CC_NDEP */ 35 | pushq 168(%rdi) 36 | popfq 37 | 38 | /* if I weren't so paranoid, I'd make this an aligned access */ 39 | movdqu (224+0*32)(%rdi), %xmm0 40 | movdqu (224+1*32)(%rdi), %xmm1 41 | movdqu (224+2*32)(%rdi), %xmm2 42 | movdqu (224+3*32)(%rdi), %xmm3 43 | movdqu (224+4*32)(%rdi), %xmm4 44 | movdqu (224+5*32)(%rdi), %xmm5 45 | movdqu (224+6*32)(%rdi), %xmm6 46 | movdqu (224+7*32)(%rdi), %xmm7 47 | movdqu (224+8*32)(%rdi), %xmm8 48 | movdqu (224+9*32)(%rdi), %xmm9 49 | movdqu (224+10*32)(%rdi), %xmm10 50 | movdqu (224+11*32)(%rdi), %xmm11 51 | movdqu (224+12*32)(%rdi), %xmm12 52 | movdqu (224+13*32)(%rdi), %xmm13 53 | movdqu (224+14*32)(%rdi), %xmm14 54 | movdqu (224+15*32)(%rdi), %xmm15 55 | 56 | /* XXX load old x87 FP? */ 57 | 58 | /* GPRs */ 59 | movq 16(%rdi), %rax 60 | movq 24(%rdi), %rcx 61 | movq 32(%rdi), %rdx 62 | movq 40(%rdi), %rbx 63 | movq 48(%rdi), %rsp 64 | movq 56(%rdi), %rbp 65 | movq 64(%rdi), %rsi 66 | movq 80(%rdi), %r8 67 | movq 88(%rdi), %r9 68 | movq 96(%rdi), %r10 69 | movq 104(%rdi), %r11 70 | movq 112(%rdi), %r12 71 | movq 120(%rdi), %r13 72 | movq 128(%rdi), %r14 73 | movq 136(%rdi), %r15 74 | 75 | movq 72(%rdi), %rdi /* with such knowledge, what forgiveness */ 76 | jmp *(amd64_trampoline_pc) /* Jump to raw code block address */ 77 | 78 | .size amd64_trampoline,.-amd64_trampoline 79 | -------------------------------------------------------------------------------- /tests/traces.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$RUNCMD" ]; then 4 | RUNCMD="bin/pt_run" 5 | fi 6 | 7 | if [ -z "$OUTPATH" ]; then 8 | OUTPATH="tests/traces-out" 9 | fi 10 | 11 | if [ -z "$REALPATH" ]; then 12 | REALPATH=tests/traces-bin 13 | fi 14 | if [ -z "$EMUPATH" ]; then 15 | EMUPATH=tests/traces-bin 16 | fi 17 | 18 | export REALPATH 19 | export EMUPATH 20 | export OUTPATH 21 | export RUNCMD 22 | 23 | echo "Testing traces" 24 | 25 | function oprof_shutdown 26 | { 27 | if [ -z "$TRACES_OPROFILE" ]; then 28 | return 29 | fi 30 | 31 | sudo opcontrol --shutdown 32 | } 33 | 34 | if [ ! -x tests/traces.sh ]; then 35 | echo "Should run from gitroot." 36 | fi 37 | 38 | TESTLOGS="tests.ok tests.bad tests.mismatch tests.skipped" 39 | for tl in $TESTLOGS; do 40 | rm -f $OUTPATH/$tl 41 | touch $OUTPATH/$tl 42 | done 43 | 44 | echo "Doing built-in tests" 45 | for a in $REALPATH/*; do 46 | tests/trace_docmd.sh "$a" "$EMUPATH/`basename $a`" 47 | done 48 | 49 | function test_apps 50 | { 51 | echo "Now testing apps" 52 | IFS=$'\n' 53 | for line in `cat tests/bin_cmds.txt`; 54 | do 55 | if [ -z "$line" ]; then 56 | continue 57 | fi 58 | a="$line" 59 | if [ ! -z `echo $a | grep "^#" ` ]; then 60 | continue 61 | fi 62 | 63 | binname=`echo "$a" | cut -f1 -d' '` 64 | if [ ! -x "$binname" ]; then 65 | continue 66 | fi 67 | tests/trace_docmd.sh "$a" 68 | done 69 | } 70 | 71 | function test_busybox 72 | { 73 | echo "Now testing busybox" 74 | IFS=$'\n' 75 | for line in `cat tests/busybox_cmd.txt`; 76 | do 77 | if [ -z "$line" ]; then 78 | continue 79 | fi 80 | a="$line" 81 | if [ ! -z `echo $a | grep "^#" ` ]; then 82 | continue 83 | fi 84 | 85 | b=`echo "$a" | sed s/arch/$EMUARCH/g` 86 | a=`echo "$a" | sed s/arch/$REALARCH/g` 87 | binname=`echo "$a" | cut -f1 -d' '` 88 | if [ ! -x "$binname" ]; then 89 | continue 90 | fi 91 | tests/trace_docmd.sh "$a" "$b" 92 | done 93 | } 94 | 95 | if [ -z "$ONLY_BUILTIN" ]; then 96 | test_apps 97 | fi 98 | 99 | if [ ! -z "$BUSYBOX" ]; then 100 | test_busybox 101 | fi 102 | 103 | echo "Trace tests done" \ 104 | ". OK="`wc -l $OUTPATH/tests.ok | cut -f1 -d' '` \ 105 | ". BAD="`wc -l $OUTPATH/tests.bad | cut -f1 -d' '` \ 106 | ". SKIPPED="`wc -l $OUTPATH/tests.skipped | cut -f1 -d' '` 107 | 108 | oprof_shutdown 109 | -------------------------------------------------------------------------------- /src/vexsb.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXSB_H 2 | #define VEXSB_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" { 9 | #include 10 | #include 11 | } 12 | 13 | #include "Sugar.h" 14 | #include "guestmem.h" 15 | 16 | class VexStmt; 17 | class VexStmtIMark; 18 | class VexExpr; 19 | 20 | namespace llvm 21 | { 22 | class Value; 23 | class Function; 24 | class Type; 25 | } 26 | 27 | class VexSB 28 | { 29 | public: 30 | /* may be requesting to translate a bad IRSB; return NULL */ 31 | static VexSB* create(guest_ptr guest_addr, const IRSB* in_irsb); 32 | 33 | /* empty VSB for building vex stmts manually and then load()ing them */ 34 | VexSB(guest_ptr guest_addr, unsigned int num_regs, IRType* in_types); 35 | 36 | // takes ownership 37 | void load( 38 | std::vector& stmts, IRJumpKind irjk, 39 | VexExpr* next); 40 | 41 | virtual ~VexSB(void); 42 | unsigned int getNumRegs(void) const { return reg_c; } 43 | unsigned int getNumStmts(void) const { return stmt_c; } 44 | void setRegValue(unsigned int reg_idx, llvm::Value* v); 45 | llvm::Value* getRegValue(unsigned int reg_idx) const; 46 | llvm::Type* getRegType(unsigned int reg_idx) const; 47 | llvm::Function* emit(const char* f_name = "vexsb_f"); 48 | void print(std::ostream& os) const; 49 | void printRegisters(std::ostream& os) const; 50 | static unsigned int getTypeBitWidth(IRType ty); 51 | static const char* getTypeStr(IRType ty); 52 | guest_ptr getJmp(void) const; 53 | guest_ptr getEndAddr(void) const; 54 | /* hopefully VEX only puts one syscall in each block... */ 55 | bool isSyscall(void) const { 56 | return (jump_kind == Ijk_Sys_syscall || 57 | jump_kind == Ijk_Sys_int128 || 58 | jump_kind == Ijk_Sys_sysenter); 59 | } 60 | guest_ptr getGuestAddr(void) const { return guest_addr; } 61 | unsigned int getSize(void) const 62 | { 63 | return getEndAddr().o - getGuestAddr(); 64 | } 65 | 66 | std::vector getInstExtents(void) const; 67 | 68 | protected: 69 | VexSB(guest_ptr guess_addr, const IRSB* in_irsb); 70 | private: 71 | void loadInstructions(const IRSB* irsb); 72 | void loadJump(IRJumpKind, VexExpr*); 73 | 74 | VexStmt* loadNextInstruction(const IRStmt* stmt); 75 | 76 | IRJumpKind jump_kind; 77 | VexExpr *jump_expr; 78 | guest_ptr guest_addr; 79 | unsigned int reg_c; 80 | unsigned int stmt_c; 81 | VexStmtIMark *last_imark; 82 | ptr_vec_t stmts; 83 | llvm::Value **values; 84 | IRType *types; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /scripts/kern2guest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LINUXIMG=/usr/src/linux/arch/x86/boot/compressed/vmlinux.bin 4 | 5 | if [ ! -e "$LINUXIMG" ]; then 6 | echo could not find $LINUXIMG 7 | exit 1 8 | fi 9 | cp /usr/src/linux/arch/x86/boot/compressed/vmlinux.bin ./ 10 | rm -rf guest-vmlinux 11 | mkdir -p guest-vmlinux/maps/ 12 | readelf -eW vmlinux.bin | grep LOAD | while read l; do 13 | echo $l 14 | off=`printf "%d" $(echo $l | cut -f2 -d' ')` 15 | vaddr=`echo $l | cut -f3 -d' '` 16 | vaddrbegin=`printf "%llu" $vaddr` 17 | fsz=`printf "%d" $(echo $l | cut -f5 -d' ')` 18 | msz=`printf "%d" $(echo $l | cut -f6 -d' ')` 19 | 20 | if [ "$vaddrbegin" == "0" ]; then echo 'null vaddr?? skip.'; continue; fi 21 | 22 | dd if=vmlinux.bin of=guest-vmlinux/maps/$vaddr ibs=1 count=$fsz skip=$off 23 | slack=`bc <<<"$msz - $fsz"` 24 | 25 | vaddrend=`bc -l <<<"$vaddrbegin + $msz"` 26 | printf "0x%llx-0x%llx 5 0 [kernel]\n" $vaddr $vaddrend >>guest-vmlinux/mapinfo 27 | 28 | if [ "$slack" -eq "0" ]; then continue; fi 29 | dd if=/dev/zero of=guest-vmlinux/maps/$vaddr ibs=1 seek=$fsz count=$slack 30 | 31 | done 32 | 33 | cp /usr/src/linux/System.map System.map 34 | last_addr=0 35 | last_sym="" 36 | echo Echo processing System.map. Please weight. 37 | grep ffff System.map | while read l; do 38 | cur_addr=`echo $l | cut -f1 -d' '` 39 | cur_sym=`echo $l | cut -f3 -d' '` 40 | if [ ! -z "$last_sym" ]; then 41 | e=`printf "%llu - 1" 0x$cur_addr` 42 | end_addr=`bc -l <<<"$e"` 43 | echo $last_sym $last_addr-`printf "%x" $end_addr` 44 | fi 45 | last_addr="$cur_addr" 46 | last_sym="$cur_sym" 47 | done >guest-vmlinux/syms 48 | 49 | echo Done processing System.map... 50 | 51 | #x86-64 52 | echo -e -n '\x1\x0\x0\x0' >guest-vmlinux/arch 53 | # can fake most of reg file, but need to have a stack pointer for UC to work 54 | head -c48 /dev/zero >guest-vmlinux/regs 55 | echo -e -n '\x80\xff\xff\x1\x0\x0\x0\x0' >>guest-vmlinux/regs 56 | head -c120 /dev/zero >>guest-vmlinux/regs 57 | # DFLAG must be set or vex will complain 58 | echo -e -n '\x1\x0\x0\x0\x0\x0\x0\x0' >>guest-vmlinux/regs 59 | head -c737 /dev/zero >>guest-vmlinux/regs 60 | # xxx maybe should only have 4k stack to test for stack overflows? 61 | dd if=/dev/zero of=guest-vmlinux/maps/0x1ff8000 bs=4096 count=8 62 | printf "0x%llx-0x%llx 3 0 [stack]\n" 0x1ff8000 0x02000000 >>guest-vmlinux/mapinfo 63 | 64 | #dummy fields 65 | touch guest-vmlinux/argv 66 | echo $LINUXIMG >guest-vmlinux/binpath 67 | touch guest-vmlinux/dynsyms 68 | echo -e -n '\x0\x0\x0\x0\x0\x0\x0\x0' >guest-vmlinux/entry 69 | -------------------------------------------------------------------------------- /src/frag_run.cc: -------------------------------------------------------------------------------- 1 | #include "Sugar.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "vexsb.h" 11 | #include "vexexec.h" 12 | #include "vexcpustate.h" 13 | #include "guestsnapshot.h" 14 | #include "fragcache.h" 15 | 16 | using namespace llvm; 17 | 18 | static VexExec *vexexec; 19 | 20 | void dumpIRSBs(void) 21 | { 22 | std::cerr << "DUMPING LOGS\n"; 23 | vexexec->dumpLogs(std::cerr); 24 | } 25 | 26 | int main(int argc, char* argv[]) 27 | { 28 | std::unique_ptr g; 29 | uint64_t addr; 30 | size_t sz; 31 | 32 | if (argc < 2) { 33 | fprintf(stderr, "Usage: %s addr [guest-sshot]\n", argv[0]); 34 | return -1; 35 | } 36 | 37 | sz = sscanf(argv[1], "0x%lx", &addr); 38 | if (sz != 1) { 39 | fprintf(stderr, 40 | "Failed to read address \"%s\". Want hex.\n", argv[1]); 41 | return -2; 42 | } 43 | printf("[frag-run] Fragment=%p\n", (void*)((intptr_t)addr)); 44 | 45 | VexCPUState::registerCPUs(); 46 | 47 | FragCache* fc = FragCache::create(NULL); 48 | if (fc) { 49 | char *buf; 50 | int len; 51 | buf = GuestSnapshot::readMemory( 52 | (argc >= 3) 53 | ? argv[2] 54 | : "guest-last", 55 | guest_ptr(addr), 56 | 2048); 57 | assert (buf != NULL); 58 | len = fc->findLength(buf); 59 | delete [] buf; 60 | delete fc; 61 | if (len != -1) { 62 | std::cout << 63 | "[frag-run] VSB Size=" << len << std::endl; 64 | return 0; 65 | } 66 | 67 | /* force storage */ 68 | setenv("VEXLLVM_STORE_FRAGS", "1", 1); 69 | } 70 | 71 | if (argc == 2) { 72 | g = Guest::load(); 73 | if (!g) { 74 | fprintf(stderr, 75 | "%s: Couldn't load guest. " 76 | "Did you run VEXLLVM_SAVE?\n", 77 | argv[0]); 78 | } 79 | } else { 80 | assert (argc >= 3); 81 | g = Guest::load(argv[2]); 82 | } 83 | 84 | assert (g && "Could not load guest"); 85 | vexexec = VexExec::create(g.get()); 86 | assert (vexexec && "Could not create vexexec"); 87 | 88 | g->getCPUState()->setPC(guest_ptr(addr)); 89 | // vexexec->beginStepping(); 90 | // bool ok_step = vexexec->stepVSB(); 91 | // std::cout << "[frag-run] OK-STEP=" << ok_step << std::endl; 92 | const VexSB* vsb = vexexec->getCachedVSB(guest_ptr(addr)); 93 | if (vsb != NULL) { 94 | std::cout << "[frag-run] VSB Size=" << vsb->getSize() << std::endl; 95 | } 96 | 97 | delete vexexec; 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /src/fragcache.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXLLVM_FRAGCACHE_H 2 | #define VEXLLVM_FRAGCACHE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef struct fchash_rec { 11 | unsigned char md[SHA_DIGEST_LENGTH]; 12 | uint16_t len; 13 | } fchash_rec; 14 | 15 | /* pending record-- integer marks return code given */ 16 | typedef std::pair fchash_p_rec; 17 | #define FCHASH_NOTFOUND -1 18 | #define FCHASH_COLLISION -2 19 | class FCHash 20 | { 21 | public: 22 | static FCHash* create(const char* fname); 23 | virtual ~FCHash(); 24 | int lookup(const void* guest_bytes, unsigned int max_len=1024) const; 25 | void add(const void* guest_bytes, unsigned int len); 26 | protected: 27 | FCHash(const char* fname); 28 | 29 | private: 30 | void flush(void); 31 | struct fchash_rec* findHashRec(const unsigned char* md) const; 32 | int findHash(const unsigned char* md) const; 33 | int findHashInFile(const unsigned char* md) const; 34 | int findHashInPending(const unsigned char* md) const; 35 | void mmapFD(void); 36 | int fd; 37 | unsigned int f_mmap_sz; 38 | void *f_mmap; 39 | std::list pending; 40 | }; 41 | 42 | class FCFile 43 | { 44 | public: 45 | static FCFile* create(const char* fname, unsigned int len); 46 | static FCFile* open(const char* fname, unsigned int len); 47 | bool contains(const void* guest_bytes) const; 48 | void add(const void* guest_bytes); 49 | virtual ~FCFile(); 50 | void flush(void); 51 | unsigned int getFragSize() const { return len; } 52 | protected: 53 | FCFile(const char* fname, unsigned int len); 54 | private: 55 | bool containsFile(const void* guest_bytes) const; 56 | bool containsBuffer(const void* guest_bytes) const; 57 | void sort(void); 58 | void mmapFd(void); 59 | 60 | std::string fname; 61 | unsigned int len; 62 | 63 | int fd; 64 | unsigned int f_mmap_sz; 65 | char *f_mmap; 66 | 67 | std::vector buffer; 68 | }; 69 | 70 | class FragCache 71 | { 72 | public: 73 | static FragCache* create(const char* dirname); 74 | virtual ~FragCache(void); 75 | bool addFragment(const void* guest_bytes, unsigned int len); 76 | int findLength(const void* guest_bytes); 77 | protected: 78 | FragCache(const char* dirname); 79 | private: 80 | FCFile* getFCFile(unsigned int len) const; 81 | std::string getCacheFileName(unsigned int) const; 82 | bool loadCacheFile(unsigned int len) const; 83 | void loadDir(void); 84 | 85 | mutable std::vector cachetab; 86 | std::string dirname; 87 | FCHash *fchash; 88 | bool ok; 89 | }; 90 | 91 | #endif -------------------------------------------------------------------------------- /src/qemu/translatedsyscall.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | linux-user/arm/syscall.c 5 | 6 | *** NOTE: these are the header includes so we can namespace several **** 7 | *** includes of the syscall.c file (one per arch) **** 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | //#include 46 | #include 47 | #include 48 | #include 49 | #ifdef TARGET_GPROF 50 | #include 51 | #endif 52 | #ifdef CONFIG_EVENTFD 53 | #include 54 | #endif 55 | #ifdef CONFIG_EPOLL 56 | #include 57 | #endif 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #if defined(CONFIG_FIEMAP) 68 | #include 69 | #endif 70 | #include 71 | #include 72 | #ifdef CONFIG_INOTIFY 73 | #include 74 | #endif 75 | #if defined(__NR_mq_open) 76 | #include 77 | #endif 78 | /* using the platform one which apparently was prob with qemu 79 | for people with older kernels... */ 80 | #include 81 | /* this one if for the signal handling code */ 82 | #include 83 | 84 | /* i am bitch! i must include EVERYTHING because of this sycall emulation */ 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | 91 | 92 | 93 | /* Translation table for bitmasks... */ 94 | typedef struct bitmask_transtbl { 95 | unsigned int x86_mask; 96 | unsigned int x86_bits; 97 | unsigned int alpha_mask; 98 | unsigned int alpha_bits; 99 | } bitmask_transtbl; 100 | -------------------------------------------------------------------------------- /tests/trace_docmd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$RUNCMD" ]; then 4 | echo "RUNCMD not set. Try RUNCMD=bin/pt_trace" 5 | fi 6 | 7 | 8 | if [ -z "$OUTPATH" ]; then 9 | echo "OUTPATH not set. Try OUTPATH=tests/traces-out" 10 | fi 11 | 12 | REAL=$1 13 | if [ -z "$2" ]; then 14 | EMU=$1 15 | else 16 | EMU=$2 17 | fi 18 | TRACE_ADDR_LINES=1000 19 | OPROF_SAMPLERATE=1000000 20 | 21 | function oprof_start 22 | { 23 | if [ -z "$TRACES_OPROFILE" ]; then 24 | return 25 | fi 26 | sudo opcontrol --start --vmlinux=/usr/src/linux/vmlinux --event=CPU_CLK_UNHALTED:${OPROF_SAMPLERATE}:0:1:1 27 | } 28 | 29 | function oprof_stop 30 | { 31 | if [ -z "$TRACES_OPROFILE" ]; then 32 | return 33 | fi 34 | sudo opcontrol --dump 35 | sudo opreport -g -a -s sample --symbols "$RUNCMD" >$FPREFIX.oprof 36 | sudo opcontrol --stop 37 | sudo opcontrol --reset 38 | } 39 | 40 | function run_trace_bin 41 | { 42 | oprof_start 43 | time "$RUNCMD" $EMU >"$FPREFIX.trace.out" 2>"$FPREFIX.trace.err" 44 | oprof_stop 45 | } 46 | 47 | function run_real_bin 48 | { 49 | $REAL >"$FPREFIX.real.out" 2>"$FPREFIX.real.err" 50 | } 51 | 52 | function dump_addrs 53 | { 54 | grep "^[ ]*0x" $FPREFIX.trace.err >$FPREFIX.trace.addrs 55 | objdump -d `echo $a | cut -f1 -d' '` >"$FPREFIX".objdump 56 | for addr in `tail -n$TRACE_ADDR_LINES $FPREFIX.trace.addrs`; do 57 | cat "$FPREFIX".objdump | grep `echo $addr | cut -f2 -d'x'` | grep "^0" 58 | done >$FPREFIX.trace.funcs 59 | tail $FPREFIX.trace.funcs 60 | } 61 | 62 | function do_trace 63 | { 64 | BINNAME=`echo $a | cut -f1 -d' ' | sed "s/\//\n/g" | tail -n1` 65 | BINPATH=`echo $a | cut -f1 -d' '` 66 | CMDHASH=`echo "$a" | md5sum | cut -f1 -d' '` 67 | FPREFIX=$OUTPATH/$BINNAME.$CMDHASH 68 | 69 | if [ ! -x $BINPATH ]; then 70 | echo "Skipping: $BINNAME" 71 | echo "$a">>$OUTPATH/tests.skipped 72 | return 73 | fi 74 | 75 | echo -n "Testing: $a..." 76 | 77 | run_trace_bin "$a" 2>"$FPREFIX.trace.time" 78 | run_real_bin "$a" 79 | 80 | grep -v "VEXLLVM" $FPREFIX.trace.out >$FPREFIX.trace.stripped.out 81 | 82 | retval=`grep "Exitcode" "$FPREFIX.trace.err" | cut -f2` 83 | assertval=`grep "Assertion" "$FPREFIX.trace.err" | grep "failed"` 84 | mismatch=`diff -q -w -B $FPREFIX.trace.stripped.out $FPREFIX.real.out` 85 | 86 | echo "$retval" >"${FPREFIX}.trace.ret" 87 | if [ -z "$retval" ] || [ ! -z "$assertval" ]; then 88 | echo "FAILED (bin: $BINNAME)." 89 | # dump_addrs 90 | echo "$a">>$OUTPATH/tests.bad 91 | else 92 | t=`cat $FPREFIX.trace.time | grep -i real | awk '{ print $2 }' ` 93 | echo -n "OK. $t" 94 | echo "$a">>$OUTPATH/tests.ok 95 | 96 | if [ ! -z "$mismatch" ]; then 97 | echo " (mismatched)" 98 | echo "$a">>$OUTPATH/tests.mismatch 99 | else 100 | echo "" 101 | fi 102 | fi 103 | } 104 | 105 | a="$REAL" 106 | do_trace 107 | -------------------------------------------------------------------------------- /src/vexexecfastchk.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "guestcpustate.h" 4 | #include "vexexecfastchk.h" 5 | #include "vexsb.h" 6 | #include "memlog.h" 7 | #include "ptimgchk.h" 8 | 9 | VexExecFastChk::VexExecFastChk(PTImgChk* gs, std::shared_ptr vx) 10 | : VexExecChk(gs, vx), 11 | pt_sc_req_c(0), 12 | pt_sc_done_c(0) 13 | { 14 | } 15 | 16 | guest_ptr VexExecFastChk::doVexSB(VexSB* vsb) 17 | { 18 | MemLog *ml; 19 | guest_ptr new_ip; 20 | 21 | cross_check->getPTArch()->breakpointSysCalls( 22 | vsb->getGuestAddr(), 23 | vsb->getEndAddr()); 24 | if ((ml = cross_check->getMemLog())) { 25 | ml->clear(); 26 | return VexExec::doVexSBAux(vsb, ml); 27 | } else { 28 | new_ip = VexExec::doVexSB(vsb); 29 | } 30 | 31 | gs->getCPUState()->setPC(new_ip); 32 | 33 | return new_ip; 34 | } 35 | 36 | #if __amd64__ 37 | extern "C" { 38 | #include 39 | } 40 | #include "cpu/ptimgamd64.h" 41 | #endif 42 | 43 | void VexExecFastChk::doSysCall(VexSB* vsb) 44 | { 45 | #if __amd64__ 46 | VexGuestAMD64State* state; 47 | PTImgAMD64 *pt_arch; 48 | bool matched; 49 | guest_ptr bp_addr; 50 | 51 | pt_arch = static_cast(cross_check->getPTArch()); 52 | state = (VexGuestAMD64State*)gs->getCPUState()->getStateData(); 53 | /* shadow process has seen k syscall opcodes (and executed k); 54 | * vexllvm process has seen k+1 syscall opcodes (and executed k) 55 | */ 56 | 57 | /* scoot shadow process up to k+1 syscall opcodes, executed k */ 58 | bp_addr = pt_arch->stepToBreakpoint(); 59 | pt_sc_req_c++; 60 | 61 | /* vexllvm state expects to be past syscall, we are currently 62 | * on it. Temporarily move vexllvm back to be on syscall. */ 63 | state->guest_RIP -= 2; 64 | /* In addition, vexllvm has set its RCX to the next RIP. 65 | * VexExecChk doesn't care about this since it only checks after 66 | * the syscall is complete. */ 67 | user_regs_struct regs; 68 | 69 | pt_arch->getRegs(regs); 70 | regs.rcx = state->guest_RCX; 71 | pt_arch->setRegs(regs); 72 | cross_check->resetBreakpoint(bp_addr); 73 | 74 | /* OK to check for match now-- fixups done */ 75 | matched = cross_check->isMatch(); 76 | if (!matched) { 77 | /* instead of dying, we want to be smarter here by 78 | * restarting the process, fastforwarding to last OK 79 | * syscall, then finally single step up to bad syscall. */ 80 | fprintf(stderr, "MISMATCH: BEGINNING OF SYSCALL\n"); 81 | dumpShadow(vsb); 82 | assert (0 == 1 && "FIXME LATER"); 83 | } 84 | 85 | /* restore vexllvm IP to *after* syscall */ 86 | state->guest_RIP += 2; 87 | 88 | doSysCallCore(vsb); 89 | 90 | pt_sc_done_c++; 91 | 92 | /* now both should be equal and at the instruction immediately following 93 | * the breaking syscall */ 94 | if (!cross_check->isMatch()) { 95 | fprintf(stderr, "MISMATCH: END OF SYSCALL.\n"); 96 | dumpShadow(vsb); 97 | } 98 | 99 | cross_check->setBreakpoint(bp_addr); 100 | #else 101 | assert (0 == 1 && "ARCH STUB"); 102 | #endif 103 | } 104 | -------------------------------------------------------------------------------- /src/jitobjcache.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "jitobjcache.h" 14 | 15 | using namespace llvm; 16 | 17 | std::unique_ptr JITObjectCache::create(void) 18 | { 19 | SmallString<256> dir; 20 | const char *udir; 21 | 22 | udir = getenv("VEXLLVM_JITCACHE_PATH"); 23 | if (udir == nullptr) 24 | return nullptr; 25 | 26 | if (udir[0] == '\0') { 27 | sys::fs::current_path(dir); 28 | sys::path::append(dir, "vexllvm_jit_cache"); 29 | } else { 30 | dir = udir; 31 | } 32 | 33 | if ( !sys::fs::exists(dir.str()) && 34 | sys::fs::create_directory(dir.str())) 35 | { 36 | std::cerr << "Unable to create cache directory\n"; 37 | return nullptr; 38 | } 39 | 40 | return std::unique_ptr(new JITObjectCache(dir.str())); 41 | } 42 | 43 | static const char hex[] = {"0123456789abcdef"}; 44 | std::string JITObjectCache::getModuleHash(const Module& m) 45 | { 46 | std::stringstream ss, ss2; 47 | unsigned char md[SHA_DIGEST_LENGTH]; 48 | auto rfs(std::make_unique(ss)); 49 | 50 | m.print(*rfs, nullptr); 51 | rfs = nullptr; 52 | 53 | auto s = ss.str(); 54 | SHA((const unsigned char*)s.c_str(), s.size(), md); 55 | 56 | ss2 << "jit:"; 57 | for (unsigned i = 0; i < sizeof(md); i++) 58 | ss2 << hex[md[i] & 0xf] << hex[(md[i] & 0xf0) >> 4]; 59 | 60 | return ss2.str(); 61 | } 62 | 63 | void JITObjectCache::notifyObjectCompiled(const Module *m, MemoryBufferRef obj) 64 | { 65 | auto p = getCachePath(*m); 66 | if (p.empty() || sys::fs::exists(p)) { 67 | // don't clobber if it already exists... 68 | return; 69 | } 70 | 71 | std::error_code err; 72 | raw_fd_ostream ir_obj_os(p.c_str(), err, sys::fs::FA_Read | sys::fs::FA_Write); 73 | ir_obj_os << obj.getBuffer(); 74 | } 75 | 76 | std::string JITObjectCache::getCachePath(const Module& m) const 77 | { 78 | const std::string mod_id = m.getModuleIdentifier(); 79 | 80 | if (mod_id.compare(0, 4, "jit:") != 0) { 81 | return ""; 82 | } 83 | 84 | SmallString<256> IRCacheFile = cache_dir; 85 | sys::path::append(IRCacheFile, mod_id.substr(4)); 86 | return IRCacheFile.str(); 87 | } 88 | 89 | std::unique_ptr JITObjectCache::getObject(const Module* m) 90 | { 91 | auto p = getCachePath(*m); 92 | if (!sys::fs::exists(p)) { 93 | // This file isn't in our cache 94 | return nullptr; 95 | } 96 | 97 | // JIT will want to write into this buffer, and we don't want that 98 | // because the file has probably just been mmapped. Instead make 99 | // a copy. The filed-based buffer will release on out of scope. 100 | auto ir_obj_buf = MemoryBuffer::getFile(p.c_str(), -1, false); 101 | assert(ir_obj_buf); 102 | auto mbr = ir_obj_buf->get()->getMemBufferRef(); 103 | return MemoryBuffer::getMemBufferCopy(mbr.getBuffer()); 104 | } 105 | -------------------------------------------------------------------------------- /src/genllvm.h: -------------------------------------------------------------------------------- 1 | #ifndef GENLLVM_H 2 | #define GENLLVM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern "C" { 10 | #include 11 | #include 12 | } 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | class Guest; 19 | 20 | struct guest_ctx_field; 21 | 22 | class GenLLVM 23 | { 24 | public: 25 | GenLLVM(const Guest& gs, const char* modname = "vexllvm"); 26 | virtual ~GenLLVM(void) {} 27 | 28 | llvm::IRBuilder<>* getBuilder(void) { return builder.get(); } 29 | llvm::Module& getModule(void) { return *mod; } 30 | std::unique_ptr takeModule(const char* new_name = nullptr); 31 | 32 | static llvm::Type* vexTy2LLVM(IRType ty); 33 | 34 | llvm::Value* readCtx(unsigned int byteOff, IRType ty); 35 | llvm::Value* readCtx( 36 | unsigned int byteOff, int bias, int len, llvm::Value* ix, 37 | llvm::Type* t); 38 | llvm::Value* writeCtx(unsigned int byteOff, llvm::Value* v); 39 | llvm::Value* writeCtx( 40 | unsigned int byteOff, int bias, int len, 41 | llvm::Value* ix, llvm::Value* v); 42 | llvm::Value* getCtxByteGEP(unsigned int byteOff, llvm::Type* ty); 43 | llvm::Value* getCtxTyGEP(llvm::Value* tyOff, llvm::Type* ty); 44 | llvm::Value* getCtxBase(void) const { return cur_guest_ctx; } 45 | 46 | void markLinked(); 47 | llvm::Value* getLinked(); 48 | 49 | void store(llvm::Value* addr, llvm::Value* data); 50 | llvm::Value* load(llvm::Value* addr_v, IRType vex_type); 51 | llvm::Value* load(llvm::Value* addr_v, llvm::Type* ty); 52 | void beginBB(const char* name); 53 | llvm::Function* endBB(llvm::Value*); 54 | void setExitType(uint8_t exit_type); 55 | llvm::Value* to16x8i(llvm::Value*) const; 56 | llvm::Value* to32x8i(llvm::Value*) const; 57 | void memFence(void); 58 | void setFakeSysReads(void) { fake_vsys_reads = true; } 59 | 60 | void setUseReloc(bool v) { use_reloc = v; } 61 | 62 | static llvm::LLVMContext& getContext() { return llvm_ctx; } 63 | private: 64 | llvm::Type* getGuestTy(void); 65 | void mkFuncTy(void); 66 | 67 | const Guest &guest; 68 | llvm::Type *guestCtxTy; 69 | 70 | std::unique_ptr> builder; 71 | std::unique_ptr mod; 72 | llvm::FunctionType *funcTy; 73 | 74 | /* current state data */ 75 | typedef std::map< 76 | std::pair, 77 | llvm::Value* 78 | > gepbyte_map_t; 79 | typedef std::map ctxcast_map_t; 80 | 81 | gepbyte_map_t gepbyte_map; 82 | ctxcast_map_t ctxcast_map; 83 | 84 | llvm::Value* cur_guest_ctx; 85 | llvm::Value* cur_memory_log; 86 | unsigned int memlog_slot; 87 | 88 | llvm::Function* cur_f; 89 | llvm::BasicBlock* entry_bb; 90 | bool log_last_store; 91 | 92 | bool fake_vsys_reads; 93 | bool use_reloc; 94 | 95 | static unsigned int mod_c; 96 | 97 | static llvm::LLVMContext llvm_ctx; 98 | }; 99 | 100 | llvm::LLVMContext& getGlobalContext(); 101 | 102 | extern std::unique_ptr theGenLLVM; 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /src/vexexec.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXEXEC_H 2 | #define VEXEXEC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "vexjitcache.h" 13 | #include "guestmem.h" 14 | #include "guestcpustate.h" 15 | 16 | class Guest; 17 | class Syscalls; 18 | class VexXlate; 19 | class VexSB; 20 | class SyscallParams; 21 | class VexXlate; 22 | 23 | namespace llvm 24 | { 25 | class ExecutionEngine; 26 | class Function; 27 | } 28 | 29 | 30 | typedef std::list > vexexec_traces; 31 | typedef std::stack vexexec_addrs; 32 | typedef std::set exit_func_set; 33 | 34 | class VexExec 35 | { 36 | public: 37 | template 38 | static T* create(U* in_gs, std::shared_ptr in_xlate = NULL) 39 | { 40 | T *ve; 41 | 42 | setupStatics(in_gs); 43 | 44 | ve = new T(in_gs, in_xlate); 45 | if (ve->getGuest() == NULL) { 46 | delete ve; 47 | return NULL; 48 | } 49 | ve->gs->getCPUState()->setPC(ve->gs->getEntryPoint()); 50 | 51 | return ve; 52 | } 53 | 54 | virtual ~VexExec(void); 55 | const Guest* getGuest(void) const { return gs; } 56 | const vexexec_traces& getTraces(void) const { return trace; } 57 | void run(void); 58 | void dumpLogs(std::ostream& os) const; 59 | unsigned int getSBExecutedCount(void) const { return sb_executed_c; } 60 | const VexSB* getCachedVSB(guest_ptr p) const; 61 | 62 | void beginStepping(void); 63 | bool stepVSB(void); 64 | 65 | guest_ptr getNextAddr(void) const { return next_addr; } 66 | 67 | virtual void setSyscalls(std::unique_ptr in_sc); 68 | protected: 69 | VexExec(Guest* gs, std::shared_ptr in_xlate = NULL); 70 | virtual guest_ptr doVexSB(VexSB* vsb); 71 | guest_ptr doVexSBAux(VexSB* vsb, void* aux); 72 | 73 | virtual void doSysCall(VexSB* vsb); 74 | virtual void doTrap(VexSB* vsb) {} 75 | void doSysCall(VexSB* vsb, SyscallParams& sp); 76 | static void setupStatics(Guest* in_gs); 77 | void setExit(int ec) { exited = true; exit_code = ec; } 78 | 79 | Guest *gs; 80 | std::unique_ptr sc; 81 | VexFCache *f_cache; 82 | guest_ptr next_addr; 83 | 84 | private: 85 | VexSB* getSBFromGuestAddr(guest_ptr elfptr); 86 | const VexSB* doNextSB(void); 87 | 88 | std::unique_ptr jit_cache; 89 | static VexExec *exec_context; 90 | static void signalHandler(int sig, siginfo_t* si, void* raw_context); 91 | void flushTamperedCode(guest_ptr start, guest_ptr end); 92 | 93 | int call_depth; 94 | 95 | /* stats */ 96 | unsigned int sb_executed_c; 97 | 98 | /* dump current state before executing BB */ 99 | /* defined by env var VEXLLVM_DUMP_STATES */ 100 | bool dump_current_state; 101 | 102 | bool exited; 103 | int exit_code; 104 | 105 | enum TraceConf { TRACE_OFF, TRACE_LOG, TRACE_STDERR }; 106 | TraceConf trace_conf; 107 | vexexec_traces trace; 108 | unsigned int trace_c; 109 | 110 | bool save_core; 111 | 112 | std::shared_ptr xlate; 113 | std::pair to_flush; 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/syscall/spimsyscalls.cc: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | } 4 | #include "spimsyscalls.h" 5 | #include "guest.h" 6 | #include "guestcpustate.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #define SPIM_PRINT_INT 1 12 | #define SPIM_PRINT_FLOAT 2 13 | #define SPIM_PRINT_DOUBLE 3 14 | #define SPIM_PRINT_STRING 4 15 | #define SPIM_READ_INT 5 16 | #define SPIM_READ_FLOAT 6 17 | #define SPIM_READ_DOUBLE 7 18 | #define SPIM_READ_STRING 8 19 | #define SPIM_SBRK 9 20 | #define SPIM_EXIT 10 21 | #define SPIM_PRINT_CHAR 11 22 | #define SPIM_READ_CHAR 12 23 | #define SPIM_OPEN 13 24 | #define SPIM_READ 14 25 | #define SPIM_WRITE 15 26 | #define SPIM_CLOSE 16 27 | #define SPIM_EXIT2 17 28 | 29 | 30 | uint64_t SPIMSyscalls::apply(SyscallParams& args) 31 | { 32 | VexGuestMIPS32State* s; 33 | 34 | s = (VexGuestMIPS32State*)guest->getCPUState()->getStateData(); 35 | 36 | // std::cerr << "[SPIMSys] Call=" << args.getSyscall() << '\n'; 37 | 38 | switch (args.getSyscall()) { 39 | case SPIM_PRINT_INT: std::cout << args.getArg(0); break; 40 | case SPIM_PRINT_FLOAT: { 41 | float f; 42 | memcpy(&f, &s->guest_f12, sizeof(f)); 43 | std::cout << f; 44 | break; 45 | } 46 | case SPIM_PRINT_DOUBLE: { 47 | double d; 48 | memcpy(&d, &s->guest_f12, sizeof(d)); 49 | std::cout << d; 50 | break; 51 | } 52 | case SPIM_PRINT_STRING: 53 | std::cout << (char*)args.getArgPtr(0); 54 | break; 55 | 56 | case SPIM_READ_INT: { 57 | uint32_t i; 58 | std::cin >> i; 59 | s->guest_r2 = i; 60 | return s->guest_r2; 61 | } 62 | 63 | case SPIM_READ_FLOAT: { 64 | float f; 65 | std::cin >> f; 66 | memcpy(&s->guest_f0, &f, sizeof(f)); 67 | break; 68 | } 69 | case SPIM_READ_DOUBLE: { 70 | double d; 71 | std::cin >> d; 72 | memcpy(&s->guest_f0, &d, sizeof(d)); 73 | break; 74 | } 75 | case SPIM_READ_STRING: { 76 | char *b = (char*)args.getArgPtr(0); 77 | do { 78 | b[0] = '\0'; 79 | if (!std::cin.getline(b, args.getArg(1))) 80 | break; 81 | } while (b[0] == '\n' || b[0] == '\0'); 82 | break; 83 | } 84 | case SPIM_SBRK: { 85 | guest_ptr p(guest->getMem()->brk()); 86 | guest->getMem()->sbrk(p + args.getArg(0)); 87 | return p; 88 | } 89 | case SPIM_EXIT: 90 | exited = true; 91 | return args.getArg(0); 92 | case SPIM_PRINT_CHAR: 93 | std::cout << (char*)args.getArg(0); 94 | break; 95 | case SPIM_READ_CHAR: { 96 | char c; 97 | std::cin >> c; 98 | return c; 99 | } 100 | case SPIM_OPEN: 101 | return open((char*)args.getArgPtr(0), O_RDONLY); 102 | case SPIM_READ: 103 | return read( 104 | args.getArg(0), 105 | (char*)args.getArgPtr(1), 106 | args.getArg(2)); 107 | case SPIM_WRITE: 108 | return write( 109 | args.getArg(0), 110 | (char*)args.getArgPtr(1), 111 | args.getArg(2)); 112 | case SPIM_CLOSE: 113 | close(args.getArg(0)); 114 | return 0; 115 | case SPIM_EXIT2: 116 | exited = true; 117 | return s->guest_r4; 118 | default: 119 | std::cerr 120 | << "[sysSPIM] Unknown syscall " 121 | << args.getSyscall() 122 | << '\n'; 123 | } 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/debugprintpass.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "genllvm.h" 10 | #include "debugprintpass.h" 11 | 12 | char DebugPrintPass::ID; 13 | 14 | using namespace llvm; 15 | 16 | static void debug_print(const char* s, uint64_t v) 17 | { 18 | std::cerr << s << ": " << v << '\n'; 19 | } 20 | 21 | bool DebugPrintPass::runOnFunction(Function &f) 22 | { 23 | Instruction* last_inst = nullptr; 24 | std::set> debug_insts; 25 | 26 | assert (debug_func_ty); 27 | 28 | for (auto& bb : f) { 29 | for (auto& i : bb) { 30 | unsigned sz = i.getType()->getPrimitiveSizeInBits(); 31 | if (last_inst) { 32 | // inserting before phi node will break 33 | // the verifier if more than two phi nodes 34 | if (!dyn_cast(&i)) 35 | debug_insts.insert( 36 | std::make_pair(last_inst, &i)); 37 | last_inst = nullptr; 38 | } 39 | if (sz == 0 || sz > 64) { 40 | continue; 41 | } 42 | last_inst = &i; 43 | } 44 | } 45 | 46 | auto i64ty = IntegerType::get(getGlobalContext(), 64); 47 | auto i8ty = IntegerType::get(getGlobalContext(), 8); 48 | auto fptr_ty = PointerType::get(debug_func_ty, 0); 49 | auto str_ty = PointerType::get(i8ty, 0); 50 | 51 | for (auto& p : debug_insts) { 52 | auto i_print = p.first; 53 | auto i_after = p.second; 54 | IRBuilder<> builder(i_after); 55 | std::string o; 56 | raw_string_ostream ss(o); 57 | 58 | ss << f.getName().str() << ':'; 59 | i_print->print(ss); 60 | 61 | // XXX: leaky 62 | auto instr_str = ss.str(); 63 | char *jit_str = strdup(instr_str.c_str()); 64 | 65 | /* call this */ 66 | auto fptr = builder.CreateIntToPtr( 67 | ConstantInt::get(i64ty, (uint64_t)&debug_print), 68 | fptr_ty); 69 | 70 | /* pass in this string */ 71 | auto sint = builder.CreateIntToPtr( 72 | ConstantInt::get(i64ty, (uint64_t)jit_str), str_ty); 73 | 74 | /* pass in this value */ 75 | unsigned sz = i_print->getType()->getPrimitiveSizeInBits(); 76 | Value *v64 = (sz == 64) ? i_print : nullptr; 77 | 78 | if (!v64) { 79 | auto ity = IntegerType::get(getGlobalContext(), sz); 80 | v64 = i_print; 81 | if (v64->getType()->isVectorTy()) { 82 | v64 = builder.CreateBitCast(v64, ity); 83 | } else if (v64->getType()->isFloatTy()) { 84 | v64 = builder.CreateBitCast(v64, ity); 85 | } 86 | v64 = builder.CreateZExt(v64, i64ty); 87 | } 88 | 89 | if (v64->getType() != i64ty) { 90 | v64 = builder.CreateBitCast(v64, i64ty); 91 | } 92 | 93 | std::vector args(2); 94 | args[0] = sint; 95 | args[1] = v64; 96 | builder.CreateCall(fptr, args); 97 | } 98 | 99 | return !debug_insts.empty(); 100 | } 101 | 102 | FunctionType* DebugPrintPass::getFuncType(void) const 103 | { 104 | std::vector f_args; 105 | // u8* = str 106 | f_args.push_back(PointerType::get( 107 | IntegerType::get(getGlobalContext(), 8), 108 | 0)); 109 | // 64-bit value from instruction computation 110 | f_args.push_back(IntegerType::get(getGlobalContext(), 64)); 111 | 112 | // void debug_print(u8*, u64) 113 | return FunctionType::get( 114 | Type::getVoidTy(getGlobalContext()), 115 | f_args, 116 | false); 117 | } 118 | -------------------------------------------------------------------------------- /src/cpu/mips32cpustate.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sugar.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "guest.h" 9 | #include "mips32cpustate.h" 10 | extern "C" { 11 | #include 12 | } 13 | 14 | #define state2mips32() ((VexGuestMIPS32State*)(state_data)) 15 | 16 | const char* MIPS32CPUState::abi_spim_scregs[] = 17 | { "R2", "R4", "R5", "R6", "R7", "R8", "R9", NULL}; 18 | 19 | #define reg_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestMIPS32State, guest_##x), true } 20 | #define reg_field_ent(x) reg_field_ent_w_n(x, sizeof(((VexGuestMIPS32State*)0)->guest_##x), 1) 21 | #define raw_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestMIPS32State, x), true } 22 | #define raw_field_ent(x) raw_field_ent_w_n(x, sizeof((VexGuestMIPS32State*)0)->x, 1) 23 | 24 | 25 | static struct guest_ctx_field mips32_fields[] = 26 | { 27 | raw_field_ent(host_EvC_FAILADDR), 28 | raw_field_ent(host_EvC_COUNTER), 29 | 30 | { "R", 4, 32, offsetof(VexGuestMIPS32State, guest_r0), true }, 31 | reg_field_ent(PC), 32 | reg_field_ent(HI), 33 | reg_field_ent(LO), 34 | { "F", 8, 32, offsetof(VexGuestMIPS32State, guest_f0), true }, 35 | 36 | reg_field_ent(FIR), 37 | reg_field_ent(FCCR), 38 | reg_field_ent(FEXR), 39 | reg_field_ent(FENR), 40 | reg_field_ent(FCSR), 41 | 42 | reg_field_ent(ULR), 43 | reg_field_ent(EMNOTE), 44 | 45 | reg_field_ent(CMSTART), 46 | reg_field_ent(CMLEN), 47 | reg_field_ent(NRADDR), 48 | 49 | reg_field_ent(COND), 50 | 51 | reg_field_ent(DSPControl), 52 | { "AC", 8, 4, offsetof(VexGuestMIPS32State, guest_ac0), true }, 53 | 54 | reg_field_ent(CP0_status), 55 | reg_field_ent(CP0_Config5), 56 | reg_field_ent(LLaddr), 57 | reg_field_ent(LLdata), 58 | { "W", 16, 32, offsetof(VexGuestMIPS32State, guest_w0), true }, 59 | reg_field_ent(MSACSR), 60 | raw_field_ent(_padding3), 61 | /* END VEX STRUCTURE */ 62 | {0} /* time to stop */ 63 | }; 64 | 65 | MIPS32CPUState::MIPS32CPUState() 66 | : VexCPUState(mips32_fields) 67 | { 68 | state_byte_c = sizeof(VexGuestMIPS32State); 69 | state_data = new uint8_t[state_byte_c+1]; 70 | memset(state_data, 0, state_byte_c+1); 71 | exit_type = &state_data[state_byte_c]; 72 | } 73 | 74 | MIPS32CPUState::~MIPS32CPUState() { delete [] state_data; } 75 | 76 | void MIPS32CPUState::setPC(guest_ptr ip) { state2mips32()->guest_PC = ip; } 77 | 78 | guest_ptr MIPS32CPUState::getPC(void) const 79 | { return guest_ptr(state2mips32()->guest_PC); } 80 | 81 | void MIPS32CPUState::setStackPtr(guest_ptr stack_ptr) 82 | { state2mips32()->guest_r29 = (uint64_t)stack_ptr; } 83 | 84 | guest_ptr MIPS32CPUState::getStackPtr(void) const 85 | { return guest_ptr(state2mips32()->guest_r29); } 86 | 87 | void MIPS32CPUState::print(std::ostream& os, const void* regctx) const 88 | { 89 | const VexGuestMIPS32State *s; 90 | 91 | s = (const VexGuestMIPS32State*)regctx; 92 | #define PRINT_REG(X) os << #X": " << (void*)(uintptr_t)s->guest_##X << "\n"; 93 | 94 | for (int i = 0; i < 32; i++) { 95 | os 96 | << "r" << i << ": " 97 | << (void*)((long)(((const uint32_t*)&s->guest_r0))[i]) 98 | << '\n'; 99 | } 100 | 101 | PRINT_REG(PC); 102 | PRINT_REG(HI); 103 | PRINT_REG(LO); 104 | 105 | for (int i = 0; i < 32; i++) { 106 | os 107 | << "f" << i << ": " 108 | << (void*)((long)(((const uint32_t*)&s->guest_f0)[i])) 109 | << '\n'; 110 | } 111 | 112 | PRINT_REG(FIR); 113 | PRINT_REG(FCCR); 114 | PRINT_REG(FEXR); 115 | PRINT_REG(FENR); 116 | PRINT_REG(FCSR); 117 | } -------------------------------------------------------------------------------- /src/elfcore.h: -------------------------------------------------------------------------------- 1 | #ifndef ELFCORE_H 2 | #define ELFCORE_H 3 | 4 | 5 | #define PRSTATUS_REGS_SIZE (27*8) 6 | 7 | struct elf_siginfo 8 | { 9 | int si_signo; /* signal number */ 10 | int si_code; /* extra code */ 11 | int si_errno; /* errno */ 12 | }; 13 | 14 | 15 | 16 | struct prstatus 17 | { 18 | struct elf_siginfo pr_info; 19 | uint16_t pr_cursig; 20 | uint64_t pr_sigpend; 21 | uint64_t pr_sighold; 22 | pid_t pr_pid; 23 | pid_t pr_ppid; 24 | pid_t pr_pgrp; 25 | pid_t pr_sid; 26 | struct timeval pr_utime; 27 | struct timeval pr_stime; 28 | struct timeval pr_cutime; 29 | struct timeval pr_cstime; 30 | struct 31 | { 32 | uint64_t pr_reg[PRSTATUS_REGS_SIZE / sizeof (uint64_t)]; 33 | } 34 | #ifdef ALIGN_PR_REG 35 | __attribute__ ((aligned (ALIGN_PR_REG))) 36 | #endif 37 | ; 38 | int32_t pr_fpvalid; 39 | }; 40 | 41 | typedef struct prstatus prstatus_t; 42 | 43 | 44 | #ifndef _SYS_UCONTEXT_H 45 | #define _SYS_UCONTEXT_H 1 46 | 47 | #include 48 | #include 49 | 50 | /* We need the signal context definitions even if they are not used 51 | included in . */ 52 | #include 53 | 54 | #ifdef __x86_64__ 55 | 56 | /* Type for general register. */ 57 | __extension__ typedef long long int greg_t; 58 | 59 | /* Number of general registers. */ 60 | #define EC_NGREG 23 61 | 62 | /* Container for all general registers. */ 63 | typedef greg_t gregset_t[EC_NGREG]; 64 | 65 | 66 | struct _libc_fpxreg 67 | { 68 | unsigned short int significand[4]; 69 | unsigned short int exponent; 70 | unsigned short int padding[3]; 71 | }; 72 | 73 | struct _libc_xmmreg 74 | { 75 | __uint32_t element[4]; 76 | }; 77 | 78 | struct _libc_fpstate 79 | { 80 | /* 64-bit FXSAVE format. */ 81 | __uint16_t cwd; 82 | __uint16_t swd; 83 | __uint16_t ftw; 84 | __uint16_t fop; 85 | __uint64_t rip; 86 | __uint64_t rdp; 87 | __uint32_t mxcsr; 88 | __uint32_t mxcr_mask; 89 | struct _libc_fpxreg _st[8]; 90 | struct _libc_xmmreg _xmm[16]; 91 | __uint32_t padding[24]; 92 | }; 93 | 94 | /* Structure to describe FPU registers. */ 95 | typedef struct _libc_fpstate *fpregset_t; 96 | 97 | #else /* !__x86_64__ */ 98 | 99 | /* Type for general register. */ 100 | typedef int greg_t; 101 | 102 | /* Number of general registers. */ 103 | #define EC_NGREG 19 104 | 105 | /* Container for all general registers. */ 106 | typedef greg_t gregset_t[EC_NGREG]; 107 | 108 | 109 | /* Definitions taken from the kernel headers. */ 110 | struct _libc_fpreg 111 | { 112 | unsigned short int significand[4]; 113 | unsigned short int exponent; 114 | }; 115 | 116 | struct _libc_fpstate 117 | { 118 | unsigned long int cw; 119 | unsigned long int sw; 120 | unsigned long int tag; 121 | unsigned long int ipoff; 122 | unsigned long int cssel; 123 | unsigned long int dataoff; 124 | unsigned long int datasel; 125 | struct _libc_fpreg _st[8]; 126 | unsigned long int status; 127 | }; 128 | 129 | /* Structure to describe FPU registers. */ 130 | typedef struct _libc_fpstate *fpregset_t; 131 | 132 | #endif /* !__x86_64__ */ 133 | 134 | #endif /* sys/ucontext.h */ 135 | 136 | 137 | typedef greg_t elf_greg_t; 138 | typedef gregset_t elf_gregset_t; 139 | typedef fpregset_t elf_fpregset_t; 140 | //typedef fpxregset_t elf_fpxregset_t; 141 | 142 | #define ELF_PRARGSZ (80) /* Number of chars for args */ 143 | 144 | struct elf_prpsinfo 145 | { 146 | char pr_state; /* numeric process state */ 147 | char pr_sname; /* char for pr_state */ 148 | char pr_zomb; /* zombie */ 149 | char pr_nice; /* nice val */ 150 | unsigned long pr_flag; /* flags */ 151 | uid_t pr_uid; 152 | gid_t pr_gid; 153 | pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; 154 | /* Lots missing */ 155 | char pr_fname[16]; /* filename of executable */ 156 | char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ 157 | }; 158 | 159 | typedef struct elf_prpsinfo prpsinfo_t; 160 | 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /src/vexjitcache.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Sugar.h" 7 | #include "vexjitcache.h" 8 | #include "jitengine.h" 9 | #include "genllvm.h" 10 | 11 | using namespace llvm; 12 | 13 | VexJITCache::VexJITCache(std::shared_ptr xlate, 14 | std::unique_ptr je) 15 | : VexFCache(xlate) 16 | , jit_engine(std::move(je)) 17 | { 18 | } 19 | 20 | VexJITCache::~VexJITCache(void) 21 | { 22 | flush(); 23 | } 24 | 25 | vexfunc_t VexJITCache::getCachedFPtr(guest_ptr guest_addr) 26 | { 27 | vexfunc_t *fptr; 28 | 29 | fptr = jit_dc.get(guest_addr); 30 | if (fptr) return (vexfunc_t)fptr; 31 | 32 | auto it = jit_cache.find(guest_addr); 33 | if (it == jit_cache.end()) return NULL; 34 | 35 | fptr = (vexfunc_t*)(*it).second; 36 | jit_dc.put(guest_addr, fptr); 37 | 38 | return (vexfunc_t)fptr; 39 | } 40 | 41 | /** 42 | * Since the JIT is really slow, do exit analysis to find extra 43 | * functions to put in the genLLVM module. 44 | * 45 | * Don't generate all the functions (too much extra work). 46 | * 5.5s => 4.9s 47 | */ 48 | #define FETCH_EXITS 1 49 | 50 | #ifdef FETCH_EXITS 51 | static std::set get_ret_addrs(Function *f) 52 | { 53 | std::set ret; 54 | 55 | for (auto& bb : *f) { 56 | for (auto& ii : bb) { 57 | auto ri = dyn_cast(&ii); 58 | if (!ri) continue; 59 | 60 | auto ci = dyn_cast(ri->getReturnValue()); 61 | if (!ci) continue; 62 | 63 | ret.insert(guest_ptr(ci->getZExtValue())); 64 | } 65 | } 66 | 67 | return ret; 68 | } 69 | #endif 70 | 71 | vexfunc_t VexJITCache::getFPtr(void* host_addr, guest_ptr guest_addr) 72 | { 73 | Function *llvm_f; 74 | vexfunc_t ret_f; 75 | 76 | ret_f = getCachedFPtr(guest_addr); 77 | if (ret_f) return ret_f; 78 | 79 | llvm_f = getFunc(host_addr, guest_addr); 80 | assert (llvm_f != NULL && "Could not get function"); 81 | 82 | #ifdef FETCH_EXITS 83 | std::set> fnames; 84 | std::set complete, workset; 85 | std::queue s; 86 | 87 | workset.insert(llvm_f); 88 | s.push(llvm_f); 89 | if (host_addr == (void*)guest_addr.o) 90 | while (!workset.empty()) { 91 | auto f = s.front(); 92 | 93 | s.pop(); 94 | 95 | auto addrs = get_ret_addrs(f); 96 | for (auto & addr : addrs) { 97 | if (jit_cache.count(addr)) 98 | continue; 99 | 100 | auto new_f = getFunc((void*)addr.o, addr); 101 | if (workset.count(new_f) || complete.count(new_f)) 102 | continue; 103 | if (!new_f) 104 | continue; 105 | 106 | fnames.insert( 107 | std::make_pair( 108 | addr, 109 | new_f->getName().str())); 110 | workset.insert(new_f); 111 | s.push(new_f); 112 | } 113 | 114 | workset.erase(f); 115 | complete.insert(f); 116 | 117 | if (complete.size() + workset.size() > 2) 118 | break; 119 | } 120 | #endif 121 | 122 | ret_f = (vexfunc_t)jit_engine->getPointerToFunction( 123 | llvm_f, 124 | theGenLLVM->takeModule()); 125 | assert (ret_f != NULL && "Could not JIT"); 126 | 127 | #ifdef FETCH_EXITS 128 | for (auto &p : fnames) { 129 | auto vf = jit_engine->getPointerToNamedFunction(p.second); 130 | jit_cache[p.first] = (vexfunc_t)vf; 131 | } 132 | #endif 133 | 134 | jit_cache[guest_addr] = ret_f; 135 | jit_dc.put(guest_addr, (vexfunc_t*)ret_f); 136 | 137 | return ret_f; 138 | } 139 | 140 | void VexJITCache::evict(guest_ptr guest_addr) 141 | { 142 | Function *f; 143 | if ((f = getCachedFunc(guest_addr)) != NULL) { 144 | delete f; 145 | } 146 | jit_cache.erase(guest_addr); 147 | jit_dc.put(guest_addr, NULL); 148 | VexFCache::evict(guest_addr); 149 | } 150 | 151 | void VexJITCache::flush(void) 152 | { 153 | jit_cache.clear(); 154 | jit_dc.flush(); 155 | VexFCache::flush(); 156 | } 157 | 158 | void VexJITCache::flush(guest_ptr begin, guest_ptr end) 159 | { 160 | foreach (it, funcBegin(begin), funcEnd(end)) { 161 | jit_cache.erase(it->first); 162 | jit_dc.put(it->first, NULL); 163 | } 164 | VexFCache::flush(begin, end); 165 | } 166 | -------------------------------------------------------------------------------- /src/cpu/armcpustate.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Sugar.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sc_xlate.h" 10 | #include "armcpustate.h" 11 | extern "C" { 12 | #include 13 | } 14 | 15 | struct ExtVexGuestARMState 16 | { 17 | VexGuestARMState guest_vex; 18 | unsigned int guest_LINKED; 19 | }; 20 | #define state2arm() ((VexGuestARMState*)(state_data)) 21 | #define state2arm_ext() ((ExtVexGuestARMState*)(state_data)) 22 | 23 | #define reg_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestARMState, guest_##x), true } 24 | #define reg_field_ent(x) reg_field_ent_w_n(x, sizeof(((VexGuestARMState*)0)->guest_##x), 1) 25 | #define raw_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestARMState, x), true } 26 | #define raw_field_ent(x) raw_field_ent_w_n(x, sizeof((VexGuestARMState*)0)->x, 1) 27 | 28 | /* ripped from libvex_guest_arm */ 29 | static struct guest_ctx_field arm_fields[] = 30 | { 31 | raw_field_ent(host_EvC_FAILADDR), 32 | raw_field_ent(host_EvC_COUNTER), 33 | {"R", 4, 16, offsetof(VexGuestARMState, guest_R0), true}, 34 | 35 | reg_field_ent(CC_OP), 36 | reg_field_ent(CC_DEP1), 37 | reg_field_ent(CC_DEP2), 38 | reg_field_ent(CC_NDEP), 39 | reg_field_ent(QFLAG32), 40 | reg_field_ent(GEFLAG0), 41 | reg_field_ent(GEFLAG1), 42 | reg_field_ent(GEFLAG2), 43 | reg_field_ent(GEFLAG3), 44 | reg_field_ent(EMNOTE), 45 | reg_field_ent(CMSTART), 46 | reg_field_ent(CMLEN), 47 | 48 | /* unredirected guest addr at start of translation whose 49 | * start has been redirected */ 50 | reg_field_ent(NRADDR), 51 | reg_field_ent(IP_AT_SYSCALL), 52 | 53 | 54 | {"D", 8, 32, offsetof(VexGuestARMState, guest_D0), true}, 55 | reg_field_ent(FPSCR), 56 | 57 | reg_field_ent(TPIDRURO), 58 | reg_field_ent(TPIDRURW), 59 | 60 | reg_field_ent(ITSTATE), 61 | 62 | /* END VEX STRUCTURE */ 63 | /* we set this when load linked happens 64 | clear it when a later store conditional 65 | should fail */ 66 | { "LINKED", 4, 1, sizeof(VexGuestARMState), true}, 67 | {0} /* time to stop */ 68 | }; 69 | 70 | ARMCPUState::ARMCPUState(void) 71 | : VexCPUState(arm_fields) 72 | { 73 | state_byte_c = sizeof(ExtVexGuestARMState); 74 | state_data = new uint8_t[state_byte_c+1]; 75 | memset(state_data, 0, state_byte_c+1); 76 | exit_type = &state_data[state_byte_c]; 77 | xlate = std::make_unique(); 78 | } 79 | 80 | ARMCPUState::~ARMCPUState() 81 | { 82 | delete [] state_data; 83 | } 84 | 85 | void ARMCPUState::setPC(guest_ptr ip) { state2arm()->guest_R15T = ip; } 86 | 87 | guest_ptr ARMCPUState::getPC(void) const { 88 | /* todo is this right, do we need to mask the low 89 | bits that control whether its in thumb mode or not? */ 90 | return guest_ptr(state2arm()->guest_R15T); 91 | } 92 | 93 | void ARMCPUState::setStackPtr(guest_ptr stack_ptr) 94 | { state2arm()->guest_R13 = stack_ptr; } 95 | 96 | guest_ptr ARMCPUState::getStackPtr(void) const 97 | { return guest_ptr(state2arm()->guest_R13); } 98 | 99 | 100 | void ARMCPUState::setThreadPointer(uint32_t v) 101 | { state2arm()->guest_TPIDRURO = v; } 102 | 103 | void ARMCPUState::print(std::ostream& os, const void* regctx) const 104 | { 105 | const ExtVexGuestARMState* s; 106 | const uint32_t *gpr_base; 107 | 108 | s = (const ExtVexGuestARMState*)regctx; 109 | gpr_base = &s->guest_vex.guest_R0; 110 | for (int i = 0; i < 16; i++) { 111 | os << "R" << i << ": " 112 | << (void*)((long)gpr_base[i]) << std::endl; 113 | } 114 | 115 | const unsigned long long *vpr_base = &s->guest_vex.guest_D0; 116 | for (int i = 0; i < 16; i++) { 117 | os 118 | << "D" << i << ": " 119 | << (void*)vpr_base[i] << std::endl; 120 | } 121 | os << "FPCSR: " << (void*)((long)s->guest_vex.guest_FPSCR) << "\n"; 122 | /* tls */ 123 | os << "TPIDRURO: "<< (void*)((long)s->guest_vex.guest_TPIDRURO)<<"\n"; 124 | os << "LINKED: " << (void*)((long)s->guest_LINKED) << "\n"; 125 | } 126 | 127 | #ifdef __arm__ 128 | void ARMCPUState::setRegs( 129 | const user_regs* regs, const uint8_t* vfpregs, 130 | void* thread_area) 131 | { 132 | memcpy(&state2arm()->guest_R0, regs, 16*4); 133 | memcpy(&state2arm()->guest_D0, vfpregs, 32*8/*fpreg*/+4/*fpscr*/); 134 | 135 | state2arm()->guest_TPIDRURO = (long)thread_area; 136 | //TODO: some kind of flags, checking but i don't yet understand this 137 | //mess of broken apart state. 138 | } 139 | #endif 140 | 141 | unsigned int ARMCPUState::getStackRegOff(void) const 142 | { 143 | return offsetof(VexGuestARMState, guest_R13); 144 | } 145 | 146 | unsigned int ARMCPUState::getRetOff(void) const 147 | { 148 | return offsetof(VexGuestARMState, guest_R0); 149 | } 150 | 151 | -------------------------------------------------------------------------------- /src/qemu/translatedthunk.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | thunk.h 5 | */ 6 | /* 7 | * Generic thunking code to convert data between host and target CPU 8 | * 9 | * Copyright (c) 2003 Fabrice Bellard 10 | * 11 | * This library is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public 13 | * License as published by the Free Software Foundation; either 14 | * version 2 of the License, or (at your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | * Lesser General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU Lesser General Public 22 | * License along with this library; if not, see . 23 | */ 24 | #ifndef THUNK_H 25 | #define THUNK_H 26 | 27 | #include 28 | 29 | /* types enums definitions */ 30 | 31 | typedef enum argtype { 32 | TYPE_NULL, 33 | TYPE_CHAR, 34 | TYPE_SHORT, 35 | TYPE_INT, 36 | TYPE_LONG, 37 | TYPE_ULONG, 38 | TYPE_PTRVOID, /* pointer on unknown data */ 39 | TYPE_LONGLONG, 40 | TYPE_ULONGLONG, 41 | TYPE_PTR, 42 | TYPE_ARRAY, 43 | TYPE_STRUCT, 44 | } argtype; 45 | 46 | #define MK_PTR(type) TYPE_PTR, type 47 | #define MK_ARRAY(type, size) TYPE_ARRAY, (argtype)size, (argtype)type 48 | #define MK_STRUCT(id) TYPE_STRUCT, (argtype)id 49 | 50 | #define THUNK_TARGET 0 51 | #define THUNK_HOST 1 52 | 53 | typedef struct { 54 | /* standard struct handling */ 55 | const argtype *field_types; 56 | int nb_fields; 57 | int *field_offsets[2]; 58 | /* special handling */ 59 | void (*convert[2])(void *dst, const void *src); 60 | int size[2]; 61 | int align[2]; 62 | const char *name; 63 | } StructEntry; 64 | 65 | /* Translation table for bitmasks... */ 66 | typedef struct bitmask_transtbl { 67 | unsigned int x86_mask; 68 | unsigned int x86_bits; 69 | unsigned int alpha_mask; 70 | unsigned int alpha_bits; 71 | } bitmask_transtbl; 72 | 73 | void thunk_register_struct(int id, const char *name, const argtype *types); 74 | void thunk_register_struct_direct(int id, const char *name, 75 | const StructEntry *se1); 76 | const argtype *thunk_convert(void *dst, const void *src, 77 | const argtype *type_ptr, int to_host); 78 | #ifndef NO_THUNK_TYPE_SIZE 79 | 80 | extern StructEntry struct_entries[]; 81 | 82 | int thunk_type_size_array(const argtype *type_ptr, int is_host); 83 | int thunk_type_align_array(const argtype *type_ptr, int is_host); 84 | 85 | static inline int thunk_type_size(const argtype *type_ptr, int is_host) 86 | { 87 | int type, size; 88 | const StructEntry *se; 89 | 90 | type = *type_ptr; 91 | switch(type) { 92 | case TYPE_CHAR: 93 | return 1; 94 | case TYPE_SHORT: 95 | return 2; 96 | case TYPE_INT: 97 | return 4; 98 | case TYPE_LONGLONG: 99 | case TYPE_ULONGLONG: 100 | return 8; 101 | case TYPE_LONG: 102 | case TYPE_ULONG: 103 | case TYPE_PTRVOID: 104 | case TYPE_PTR: 105 | if (is_host) { 106 | return HOST_LONG_SIZE; 107 | } else { 108 | return TARGET_ABI_BITS / 8; 109 | } 110 | break; 111 | case TYPE_ARRAY: 112 | size = type_ptr[1]; 113 | return size * thunk_type_size_array(type_ptr + 2, is_host); 114 | case TYPE_STRUCT: 115 | se = struct_entries + type_ptr[1]; 116 | return se->size[is_host]; 117 | default: 118 | return -1; 119 | } 120 | } 121 | 122 | static inline int thunk_type_align(const argtype *type_ptr, int is_host) 123 | { 124 | int type; 125 | const StructEntry *se; 126 | 127 | type = *type_ptr; 128 | switch(type) { 129 | case TYPE_CHAR: 130 | return 1; 131 | case TYPE_SHORT: 132 | return 2; 133 | case TYPE_INT: 134 | return 4; 135 | case TYPE_LONGLONG: 136 | case TYPE_ULONGLONG: 137 | return 8; 138 | case TYPE_LONG: 139 | case TYPE_ULONG: 140 | case TYPE_PTRVOID: 141 | case TYPE_PTR: 142 | if (is_host) { 143 | return HOST_LONG_SIZE; 144 | } else { 145 | return TARGET_ABI_BITS / 8; 146 | } 147 | break; 148 | case TYPE_ARRAY: 149 | return thunk_type_align_array(type_ptr + 2, is_host); 150 | case TYPE_STRUCT: 151 | se = struct_entries + type_ptr[1]; 152 | return se->align[is_host]; 153 | default: 154 | return -1; 155 | } 156 | } 157 | 158 | #endif /* NO_THUNK_TYPE_SIZE */ 159 | 160 | unsigned int target_to_host_bitmask(unsigned int x86_mask, 161 | const bitmask_transtbl * trans_tbl); 162 | unsigned int host_to_target_bitmask(unsigned int alpha_mask, 163 | const bitmask_transtbl * trans_tbl); 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /src/vexhelpers.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include "Sugar.h" 11 | #include "genllvm.h" 12 | 13 | #include "jitengine.h" 14 | #include "vexhelpers.h" 15 | 16 | #define VEXOP_BC_FILE "vexops.bc" 17 | 18 | using namespace llvm; 19 | 20 | std::unique_ptr theVexHelpers; 21 | extern void vexop_setup_fp(VexHelpers* vh); 22 | 23 | VexHelpers::VexHelpers(Arch::Arch in_arch) 24 | : arch(in_arch) 25 | , ext_mod(nullptr) 26 | { 27 | /* env not set => assume running from git root */ 28 | bc_dirpath = getenv("VEXLLVM_HELPER_PATH"); 29 | if (bc_dirpath == nullptr || strlen(bc_dirpath) == 0) 30 | bc_dirpath = "bitcode"; 31 | } 32 | 33 | void VexHelpers::loadDefaultModules(void) 34 | { 35 | char path_buf[512]; 36 | 37 | const char* helper_file = nullptr; 38 | switch(arch) { 39 | case Arch::X86_64: helper_file = "libvex_amd64_helpers.bc"; break; 40 | case Arch::I386: helper_file = "libvex_x86_helpers.bc"; break; 41 | case Arch::ARM: helper_file = "libvex_arm_helpers.bc"; break; 42 | case Arch::MIPS32: break; /* no useful helpers for mips */ 43 | default: 44 | assert(!"known arch for helpers"); 45 | } 46 | 47 | if (helper_file) { 48 | snprintf(path_buf, 512, "%s/%s", bc_dirpath, helper_file); 49 | helper_mod = loadMod(path_buf); 50 | } 51 | 52 | snprintf(path_buf, 512, "%s/%s", bc_dirpath, VEXOP_BC_FILE); 53 | vexop_mod = loadMod(path_buf); 54 | 55 | vexop_setup_fp(this); 56 | 57 | assert (vexop_mod && (helper_file == nullptr || helper_mod)); 58 | } 59 | 60 | std::unique_ptr VexHelpers::create(Arch::Arch arch) 61 | { 62 | auto vh = new VexHelpers(arch); 63 | vh->loadDefaultModules(); 64 | return std::unique_ptr(vh); 65 | } 66 | 67 | std::unique_ptr VexHelpers::loadMod(const char* path) 68 | { return loadModFromPath(path); } 69 | 70 | std::unique_ptr VexHelpers::loadModFromPath(const char* path) 71 | { 72 | SMDiagnostic diag; 73 | auto ret_mod = llvm::parseIRFile(path, diag, getGlobalContext()); 74 | if (ret_mod == nullptr) { 75 | std::string s(diag.getMessage()); 76 | std::cerr 77 | << "Error Parsing Bitcode File '" 78 | << path << "': " << s << '\n'; 79 | } 80 | assert (ret_mod && "Couldn't parse bitcode mod"); 81 | auto err = ret_mod->materializeAll(); 82 | if (err) { 83 | std::cerr << "Materialize failed... " << std::endl; 84 | assert (0 == 1 && "BAD MOD"); 85 | } 86 | return ret_mod; 87 | } 88 | 89 | umod_list VexHelpers::takeModules(void) 90 | { 91 | umod_list l; 92 | while (!user_mods.empty()) { 93 | auto m = (user_mods.front()).release(); 94 | user_mods.pop_front(); 95 | l.emplace_back(m); 96 | } 97 | if (helper_mod) l.emplace_back(std::move(helper_mod)); 98 | l.emplace_back(std::move(vexop_mod)); 99 | return l; 100 | } 101 | 102 | void VexHelpers::loadUserMod(const char* path) 103 | { 104 | char pathbuf[512]; 105 | 106 | assert ((strlen(path)+strlen(bc_dirpath)) < 512); 107 | snprintf(pathbuf, 512, "%s/%s", bc_dirpath, path); 108 | 109 | auto m = loadMod(pathbuf); 110 | assert (m != nullptr && "Could not load user module"); 111 | user_mods.push_back(std::move(m)); 112 | } 113 | 114 | void VexHelpers::destroyMods(void) 115 | { 116 | helper_mod = nullptr; 117 | vexop_mod = nullptr; 118 | user_mods.clear(); 119 | } 120 | 121 | VexHelpers::~VexHelpers() 122 | { 123 | destroyMods(); 124 | } 125 | 126 | Function* VexHelpers::getCallHelper(const char* s) 127 | { 128 | auto &mod = theGenLLVM->getModule(); 129 | auto in_mod_f = mod.getFunction(s); 130 | if (!in_mod_f) { 131 | auto f = getHelper(s); 132 | if (!f) { 133 | return nullptr; 134 | } 135 | in_mod_f = Function::Create( 136 | f->getFunctionType(), 137 | Function::ExternalLinkage, 138 | s, 139 | mod); 140 | } 141 | return in_mod_f; 142 | } 143 | 144 | Function* VexHelpers::getHelper(const char* s) const 145 | { 146 | Function *f; 147 | 148 | if (ext_mod) { 149 | return ext_mod->getFunction(s); 150 | } 151 | 152 | /* TODO why not start using a better algorithm sometime */ 153 | if (helper_mod && (f = helper_mod->getFunction(s))) return f; 154 | 155 | assert (vexop_mod); 156 | if ((f = vexop_mod->getFunction(s))) return f; 157 | 158 | for (auto &m : user_mods) { 159 | if ((f = m->getFunction(s))) 160 | return f; 161 | } 162 | 163 | return nullptr; 164 | } 165 | 166 | void VexHelpers::moveToJITEngine(JITEngine& je) 167 | { 168 | if (helper_mod) 169 | je.moveModule( 170 | std::unique_ptr( 171 | CloneModule(*helper_mod))); 172 | if (vexop_mod) 173 | je.moveModule( 174 | std::unique_ptr( 175 | CloneModule(*vexop_mod))); 176 | } 177 | 178 | std::unique_ptr VexHelperDummy::loadMod(const char* path) 179 | { 180 | fprintf(stderr, "FAILING LOAD MOD %s\n", path); 181 | return nullptr; 182 | } 183 | 184 | void VexHelpers::useExternalMod(Module* m) 185 | { 186 | assert (ext_mod == nullptr); 187 | destroyMods(); 188 | ext_mod = m; 189 | } 190 | -------------------------------------------------------------------------------- /src/cpu/i386syscalls.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef __arm__ 5 | #include 6 | #endif 7 | #include 8 | #include 9 | #include "Sugar.h" 10 | 11 | #include "guest.h" 12 | #include "cpu/sc_xlate.h" 13 | #include "cpu/i386cpustate.h" 14 | 15 | 16 | /* this header loads all of the system headers outside of the namespace */ 17 | #include "qemu/translatedsyscall.h" 18 | 19 | #ifndef PAGE_SIZE 20 | #define PAGE_SIZE 4096 21 | #endif 22 | 23 | static GuestMem* g_mem = NULL; 24 | static std::vector g_to_delete; 25 | 26 | namespace I386 { 27 | /* this will hold the last mapping that was changed during the syscall 28 | ... hopefully there is only one... */ 29 | 30 | /* we have to define a few platform specific types, non platform 31 | specific interface code goes in the translatedutil.h */ 32 | #define TARGET_I386 33 | #define TARGET_ABI_BITS 32 34 | #define TARGET_ABI32 35 | #define abi_long int 36 | #define abi_ulong unsigned int 37 | #define target_ulong abi_ulong 38 | #define target_long abi_long 39 | #define HOST_PAGE_ALIGN(x) \ 40 | ((uintptr_t)x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) 41 | #define cpu_to_uname_machine(...) "i386" 42 | /* Maximum number of LDT entries supported. */ 43 | #define TARGET_LDT_ENTRIES 8192 44 | /* The size of each LDT entry. */ 45 | #define TARGET_LDT_ENTRY_SIZE 8 46 | 47 | /* memory mapping requires wrappers based on the host address 48 | space limitations */ 49 | /* oh poo, this needs to record mappings... they don't right now */ 50 | #define mmap_find_vma(s, l) mmap_find_vma_flags(s, l, MAP_32BIT) 51 | 52 | /* our implementations of stuff ripped out of the qemu files */ 53 | #include "qemu/translatedutil.h" 54 | /* generic type conversion utility routines */ 55 | #include "qemu/translatedthunk.h" 56 | /* terminal io definitions that are plaform dependent */ 57 | #include "qemu/i386termbits.h" 58 | /* platform dependent signals */ 59 | #include "qemu/i386signal.h" 60 | /* structure and flag definitions that are platform independent */ 61 | #include "qemu/translatedsyscalldefs.h" 62 | /* we need load our platform specific stuff as well */ 63 | #include "qemu/i386syscallnumbers.h" 64 | /* this constructs all of our syscall translation code */ 65 | #include "qemu/translatedsyscall.c" 66 | /* this constructs all of our syscall translation code */ 67 | #include "qemu/translatedsignal.c" 68 | /* this has some tables and such used for type conversion */ 69 | #include "qemu/translatedthunk.c" 70 | 71 | std::vector g_host_to_guest_syscalls(512); 72 | std::vector g_guest_to_host_syscalls(512); 73 | std::vector g_guest_syscall_names(512); 74 | bool syscall_mapping_init() { 75 | foreach(it, g_host_to_guest_syscalls.begin(), 76 | g_host_to_guest_syscalls.end()) *it = -1; 77 | foreach(it, g_guest_to_host_syscalls.begin(), 78 | g_guest_to_host_syscalls.end()) *it = -1; 79 | for(unsigned sys_nr = 0; 80 | sys_nr < g_guest_syscall_names.size(); ++sys_nr) 81 | { 82 | std::ostringstream o; 83 | o << sys_nr; 84 | g_guest_syscall_names[sys_nr] = o.str(); 85 | } 86 | #define SYSCALL_RELATION(name, host, guest) \ 87 | g_host_to_guest_syscalls[host] = guest; \ 88 | g_guest_to_host_syscalls[guest] = host; 89 | #define GUEST_SYSCALL(name, guest) \ 90 | g_guest_syscall_names[guest] = #name; 91 | #include "syscall/syscallsmapping.h" 92 | return true; 93 | } 94 | bool dummy_syscall_mapping = syscall_mapping_init(); 95 | } 96 | 97 | 98 | int I386SyscallXlate::translateSyscall(int sys_nr) const { 99 | if((unsigned)sys_nr > I386::g_guest_to_host_syscalls.size()) 100 | return -1; 101 | 102 | int host_sys_nr = I386::g_guest_to_host_syscalls[sys_nr]; 103 | return host_sys_nr; 104 | } 105 | 106 | std::string I386SyscallXlate::getSyscallName(int sys_nr) const { 107 | if((unsigned)sys_nr > I386::g_guest_syscall_names.size()) { 108 | std::ostringstream o; 109 | o << sys_nr; 110 | return o.str(); 111 | } 112 | 113 | return I386::g_guest_syscall_names[sys_nr]; 114 | } 115 | 116 | SYSCALL_BODY(I386, mmap2) 117 | { 118 | guest_ptr m; 119 | sc_ret = g.getMem()->mmap(m, 120 | guest_ptr(args.getArg(0)), 121 | args.getArg(1), 122 | args.getArg(2), 123 | args.getArg(3), 124 | args.getArg(4), 125 | args.getArg(5) * PAGE_SIZE); 126 | if(sc_ret == 0) 127 | sc_ret = m; 128 | return true; 129 | } 130 | 131 | uintptr_t I386SyscallXlate::apply(Guest& g, SyscallParams& args) 132 | { 133 | uintptr_t sc_ret = 0; 134 | 135 | sc_ret = ~sc_ret; 136 | 137 | /* special syscalls that we handle per arch, these 138 | generally supersede any pass through or translated 139 | behaviors, but they can just alter the args and let 140 | the other mechanisms finish the job */ 141 | switch (args.getSyscall()) { 142 | case TARGET_NR_mmap2: 143 | if(I386_mmap2(g, args, (unsigned long&)sc_ret)) 144 | return sc_ret; 145 | break; 146 | default: 147 | break; 148 | } 149 | 150 | if (tryPassthrough(g, args, sc_ret)) return sc_ret; 151 | 152 | g_mem = g.getMem(); 153 | sc_ret = I386::do_syscall(NULL, 154 | args.getSyscall(), 155 | args.getArg(0), 156 | args.getArg(1), 157 | args.getArg(2), 158 | args.getArg(3), 159 | args.getArg(4), 160 | args.getArg(5)); 161 | 162 | foreach(it, g_to_delete.begin(), g_to_delete.end()) 163 | delete [] *it; 164 | g_to_delete.clear(); 165 | 166 | return sc_ret; 167 | } -------------------------------------------------------------------------------- /src/vexfcache.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Sugar.h" 10 | #include "vexsb.h" 11 | #include "vexxlate.h" 12 | #include "vexfcache.h" 13 | 14 | using namespace llvm; 15 | 16 | VexFCache::VexFCache(Arch::Arch arch) 17 | : xlate(std::make_shared(arch)), 18 | max_cache_ents(~0) /* don't evict by default */ 19 | { 20 | dump_llvm = (getenv("VEXLLVM_DUMP_LLVM")) ? true : false; 21 | } 22 | 23 | VexFCache::VexFCache(std::shared_ptr in_xlate) 24 | : xlate(in_xlate), 25 | max_cache_ents(~0) 26 | { 27 | assert (xlate != NULL); 28 | dump_llvm = (getenv("VEXLLVM_DUMP_LLVM")) ? true : false; 29 | } 30 | 31 | VexFCache::~VexFCache(void) 32 | { 33 | flush(); 34 | } 35 | 36 | void VexFCache::setMaxCache(unsigned int x) 37 | { 38 | if (x < max_cache_ents) flush(); 39 | max_cache_ents = x; 40 | } 41 | 42 | /* XXX: be smarter; random eviction is stupid */ 43 | guest_ptr VexFCache::selectVictimAddress(void) const 44 | { 45 | int choice = rand() % vexsb_cache.size(); 46 | guest_ptr evict_addr(0); 47 | 48 | for (const auto &p : vexsb_cache) { 49 | if (!choice) { 50 | evict_addr = p.second->getGuestAddr(); 51 | break; 52 | } 53 | choice--; 54 | } 55 | 56 | assert (evict_addr && "0 evict addr?"); 57 | return evict_addr; 58 | } 59 | 60 | VexSB* VexFCache::getVSB(void* hostptr, guest_ptr guest_addr) 61 | { 62 | VexSB* vsb; 63 | 64 | vsb = getCachedVSB(guest_addr); 65 | if (vsb) return vsb; 66 | 67 | return allocCacheVSB(hostptr, guest_addr); 68 | } 69 | 70 | VexSB* VexFCache::allocCacheVSB(void* hostptr, guest_ptr guest_addr) 71 | { 72 | VexSB* vsb; 73 | 74 | vsb = xlate->xlate(hostptr, guest_addr); 75 | if (vsb == NULL) 76 | return NULL; 77 | 78 | if (vexsb_cache.size() == max_cache_ents) 79 | evict(selectVictimAddress()); 80 | assert (vexsb_cache.size() < max_cache_ents); 81 | 82 | vexsb_cache[guest_addr] = std::unique_ptr(vsb); 83 | vexsb_dc.put(guest_addr, vsb); 84 | return vsb; 85 | } 86 | 87 | VexSB* VexFCache::getCachedVSB(guest_ptr guest_addr) 88 | { 89 | VexSB *vsb; 90 | vexsb_map::const_iterator it; 91 | 92 | // lookup in direct cache 93 | vsb = vexsb_dc.get(guest_addr); 94 | if (vsb) return vsb; 95 | 96 | // lookup in slower cache 97 | it = vexsb_cache.find(guest_addr); 98 | if (it == vexsb_cache.end()) return NULL; 99 | 100 | // replace in direct cache 101 | vsb = it->second.get(); 102 | vexsb_dc.put(guest_addr, vsb); 103 | return vsb; 104 | } 105 | 106 | Function* VexFCache::getCachedFunc(guest_ptr guest_addr) 107 | { 108 | Function *func; 109 | func_map::const_iterator it; 110 | 111 | func = func_dc.get(guest_addr); 112 | if (func) return func; 113 | 114 | it = func_cache.find(guest_addr); 115 | if (it == func_cache.end()) return NULL; 116 | 117 | func = (*it).second; 118 | func_dc.put(guest_addr, func); 119 | return func; 120 | } 121 | 122 | Function* VexFCache::getFunc(void* hostptr, guest_ptr guest_addr) 123 | { 124 | Function* ret_f; 125 | VexSB* vsb; 126 | 127 | ret_f = getCachedFunc(guest_addr); 128 | if (ret_f) return ret_f; 129 | 130 | vsb = getVSB(hostptr, guest_addr); 131 | if (vsb == NULL) 132 | return NULL; 133 | 134 | ret_f = genFunctionByVSB(vsb); 135 | return ret_f; 136 | } 137 | 138 | Function* VexFCache::genFunctionByVSB(VexSB* vsb) 139 | { 140 | Function *f; 141 | char emitstr[512]; 142 | 143 | /* not in caches, generate */ 144 | sprintf(emitstr, "sb_%p", (void*)vsb->getGuestAddr().o); 145 | f = vsb->emit(emitstr); 146 | assert (f && "FAILED TO EMIT FUNC??"); 147 | 148 | func_cache[vsb->getGuestAddr()] = f; 149 | func_dc.put(vsb->getGuestAddr(), f); 150 | 151 | if (dump_llvm) 152 | f->print(errs()); 153 | 154 | return f; 155 | } 156 | 157 | void VexFCache::evict(guest_ptr guest_addr) 158 | { 159 | VexSB *vsb; 160 | Function *func; 161 | 162 | if ((func = getCachedFunc(guest_addr)) != NULL) { 163 | func_cache.erase(guest_addr); 164 | func_dc.put(guest_addr, NULL); 165 | func->eraseFromParent(); 166 | } 167 | 168 | if ((vsb = getCachedVSB(guest_addr)) != NULL) { 169 | vexsb_dc.put(guest_addr, NULL); 170 | vexsb_cache.erase(guest_addr); 171 | } 172 | } 173 | 174 | void VexFCache::dumpLog(std::ostream& os) const 175 | { 176 | xlate->dumpLog(os); 177 | } 178 | 179 | void VexFCache::flush(void) 180 | { 181 | vexsb_cache.clear(); 182 | 183 | vexsb_dc.flush(); 184 | 185 | // for (auto &p : func_cache) p.second->eraseFromParent(); 186 | func_cache.clear(); 187 | func_dc.flush(); 188 | } 189 | 190 | void VexFCache::flush(guest_ptr begin, guest_ptr end) 191 | { 192 | std::list delete_addrs; 193 | 194 | /* delete VSBs that fall in range */ 195 | foreach (it, 196 | vexsb_cache.lower_bound(begin), vexsb_cache.upper_bound(end)) 197 | { 198 | delete_addrs.push_back(it->first); 199 | } 200 | 201 | foreach (it, delete_addrs.begin(), delete_addrs.end()) { 202 | vexsb_dc.put(*it, NULL); 203 | vexsb_cache.erase(*it); 204 | } 205 | delete_addrs.clear(); 206 | 207 | /* delete funcs that fall in range */ 208 | foreach (it, 209 | func_cache.lower_bound(begin), func_cache.upper_bound(end)) 210 | { 211 | delete_addrs.push_back(it->first); 212 | it->second->eraseFromParent(); 213 | } 214 | 215 | foreach (it, delete_addrs.begin(), delete_addrs.end()) { 216 | func_cache.erase(*it); 217 | func_dc.put(*it, NULL); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/cpu/amd64syscalls.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifndef __arm__ 5 | #include 6 | #endif 7 | #include 8 | #include 9 | #include "Sugar.h" 10 | 11 | #include "guest.h" 12 | #include "guestmem.h" 13 | #include "cpu/sc_xlate.h" 14 | #include "amd64cpustate.h" 15 | 16 | /* this header loads all of the system headers outside of the namespace */ 17 | #include "qemu/translatedsyscall.h" 18 | 19 | static GuestMem* g_mem = NULL; 20 | static std::vector g_to_delete; 21 | 22 | namespace AMD64 { 23 | /* this will hold the last mapping that was changed during the syscall 24 | ... hopefully there is only one... */ 25 | 26 | /* we have to define a few platform specific types, non platform 27 | specific interface code goes in the translatedutil.h */ 28 | #define TARGET_X86_64 29 | #define TARGET_I386 30 | #define TARGET_ABI_BITS 64 31 | #define TARGET_ABI64 32 | #define abi_long long 33 | #define abi_ulong unsigned long 34 | #define target_ulong abi_ulong 35 | #define target_long abi_long 36 | #define HOST_PAGE_ALIGN(x) \ 37 | ((uintptr_t)x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) 38 | #define cpu_to_uname_machine(...) "x86_64" 39 | /* Maximum number of LDT entries supported. */ 40 | #define TARGET_LDT_ENTRIES 8192 41 | /* The size of each LDT entry. */ 42 | #define TARGET_LDT_ENTRY_SIZE 8 43 | 44 | /* memory mapping requires wrappers based on the host address 45 | space limitations */ 46 | /* oh poo, this needs to record mappings... they don't right now */ 47 | #define mmap_find_vma(s, l) mmap_find_vma_flags(s, l, MAP_32BIT) 48 | 49 | /* our implementations of stuff ripped out of the qemu files */ 50 | #include "qemu/translatedutil.h" 51 | /* generic type conversion utility routines */ 52 | #include "qemu/translatedthunk.h" 53 | /* terminal io definitions that are plaform dependent */ 54 | #include "qemu/amd64termbits.h" 55 | /* platform dependent signals */ 56 | #include "qemu/amd64signal.h" 57 | /* structure and flag definitions that are platform independent */ 58 | #include "qemu/translatedsyscalldefs.h" 59 | /* we need load our platform specific stuff as well */ 60 | #include "qemu/amd64syscallnumbers.h" 61 | /* this constructs all of our syscall translation code */ 62 | #include "qemu/translatedsyscall.c" 63 | /* this constructs all of our syscall translation code */ 64 | #include "qemu/translatedsignal.c" 65 | /* this has some tables and such used for type conversion */ 66 | #include "qemu/translatedthunk.c" 67 | 68 | std::vector g_host_to_guest_syscalls(512); 69 | std::vector g_guest_to_host_syscalls(512); 70 | std::vector g_guest_syscall_names(512); 71 | bool syscall_mapping_init() { 72 | foreach(it, g_host_to_guest_syscalls.begin(), 73 | g_host_to_guest_syscalls.end()) *it = -1; 74 | foreach(it, g_guest_to_host_syscalls.begin(), 75 | g_guest_to_host_syscalls.end()) *it = -1; 76 | for(unsigned sys_nr = 0; 77 | sys_nr < g_guest_syscall_names.size(); ++sys_nr) 78 | { 79 | std::ostringstream o; 80 | o << sys_nr; 81 | g_guest_syscall_names[sys_nr] = o.str(); 82 | } 83 | #define SYSCALL_RELATION(name, host, guest) \ 84 | g_host_to_guest_syscalls[host] = guest; \ 85 | g_guest_to_host_syscalls[guest] = host; 86 | #define GUEST_SYSCALL(name, guest) \ 87 | g_guest_syscall_names[guest] = #name; 88 | #include "syscall/syscallsmapping.h" 89 | return true; 90 | } 91 | bool dummy_syscall_mapping = syscall_mapping_init(); 92 | } 93 | 94 | 95 | int AMD64SyscallXlate::translateSyscall(int sys_nr) const { 96 | if((unsigned)sys_nr > AMD64::g_guest_to_host_syscalls.size()) 97 | return -1; 98 | 99 | int host_sys_nr = AMD64::g_guest_to_host_syscalls[sys_nr]; 100 | return host_sys_nr; 101 | } 102 | 103 | std::string AMD64SyscallXlate::getSyscallName(int sys_nr) const { 104 | if((unsigned)sys_nr > AMD64::g_guest_syscall_names.size()) { 105 | std::ostringstream o; 106 | o << sys_nr; 107 | return o.str(); 108 | } 109 | 110 | return AMD64::g_guest_syscall_names[sys_nr]; 111 | } 112 | 113 | /* XXX fucking arm */ 114 | #ifdef __arm__ 115 | #define SYS_arch_prctl 158 116 | #define ARCH_SET_FS 0x1002 117 | #define ARCH_GET_FS 0x1003 118 | #endif 119 | 120 | uintptr_t AMD64SyscallXlate::apply(Guest& g, SyscallParams& args) 121 | { 122 | unsigned long sc_ret = ~0UL; 123 | 124 | /* special syscalls that we handle per arch, these 125 | generally supersede any pass through or translated 126 | behaviors, but they can just alter the args and let 127 | the other mechanisms finish the job */ 128 | switch (args.getSyscall()) { 129 | case SYS_arch_prctl: 130 | if(AMD64_arch_prctl(g, args, sc_ret)) 131 | return sc_ret; 132 | break; 133 | default: 134 | break; 135 | } 136 | 137 | if (tryPassthrough(g, args, (uintptr_t&)sc_ret)) return sc_ret; 138 | 139 | g_mem = g.getMem(); 140 | sc_ret = AMD64::do_syscall(NULL, 141 | args.getSyscall(), 142 | args.getArg(0), 143 | args.getArg(1), 144 | args.getArg(2), 145 | args.getArg(3), 146 | args.getArg(4), 147 | args.getArg(5)); 148 | 149 | foreach(it, g_to_delete.begin(), g_to_delete.end()) 150 | delete [] *it; 151 | g_to_delete.clear(); 152 | 153 | return sc_ret; 154 | } 155 | 156 | SYSCALL_BODY(AMD64, arch_prctl) 157 | { 158 | auto cpu_state = (AMD64CPUState*)g.getCPUState(); 159 | if(args.getArg(0) == ARCH_GET_FS) { 160 | sc_ret = cpu_state->getFSBase(); 161 | } else if(args.getArg(0) == ARCH_SET_FS) { 162 | cpu_state->setFSBase(args.getArg(1)); 163 | sc_ret = 0; 164 | } else { 165 | /* nothing else is supported by VEX */ 166 | sc_ret = -EPERM; 167 | } 168 | return true; 169 | } -------------------------------------------------------------------------------- /src/qemu/translatedsocket.h: -------------------------------------------------------------------------------- 1 | /* FROM 2 | qemu.git 3 | eb47d7c5d96060040931c42773ee07e61e547af9 4 | linux-user/socket.h 5 | */ 6 | 7 | #if defined(TARGET_MIPS) 8 | // MIPS special values for constants 9 | 10 | /* 11 | * For setsockopt(2) 12 | * 13 | * This defines are ABI conformant as far as Linux supports these ... 14 | */ 15 | #define TARGET_SOL_SOCKET 0xffff 16 | 17 | #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */ 18 | #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ 19 | #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send 20 | SIGPIPE when they die. */ 21 | #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */ 22 | #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of 23 | broadcast messages. */ 24 | #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable 25 | socket to transmit pending data. */ 26 | #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */ 27 | #if 0 28 | To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ 29 | #endif 30 | 31 | #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */ 32 | #define TARGET_SO_STYLE SO_TYPE /* Synonym */ 33 | #define TARGET_SO_ERROR 0x1007 /* get error status and clear */ 34 | #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */ 35 | #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */ 36 | #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ 37 | #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ 38 | #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ 39 | #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ 40 | #define TARGET_SO_ACCEPTCONN 0x1009 41 | 42 | /* linux-specific, might as well be the same as on i386 */ 43 | #define TARGET_SO_NO_CHECK 11 44 | #define TARGET_SO_PRIORITY 12 45 | #define TARGET_SO_BSDCOMPAT 14 46 | 47 | #define TARGET_SO_PASSCRED 17 48 | #define TARGET_SO_PEERCRED 18 49 | 50 | /* Security levels - as per NRL IPv6 - don't actually do anything */ 51 | #define TARGET_SO_SECURITY_AUTHENTICATION 22 52 | #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 53 | #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 54 | 55 | #define TARGET_SO_BINDTODEVICE 25 56 | 57 | /* Socket filtering */ 58 | #define TARGET_SO_ATTACH_FILTER 26 59 | #define TARGET_SO_DETACH_FILTER 27 60 | 61 | #define TARGET_SO_PEERNAME 28 62 | #define TARGET_SO_TIMESTAMP 29 63 | #define SCM_TIMESTAMP SO_TIMESTAMP 64 | 65 | #define TARGET_SO_PEERSEC 30 66 | #define TARGET_SO_SNDBUFFORCE 31 67 | #define TARGET_SO_RCVBUFFORCE 33 68 | 69 | /** sock_type - Socket types 70 | * 71 | * Please notice that for binary compat reasons MIPS has to 72 | * override the enum sock_type in include/linux/net.h, so 73 | * we define ARCH_HAS_SOCKET_TYPES here. 74 | * 75 | * @SOCK_DGRAM - datagram (conn.less) socket 76 | * @SOCK_STREAM - stream (connection) socket 77 | * @SOCK_RAW - raw socket 78 | * @SOCK_RDM - reliably-delivered message 79 | * @SOCK_SEQPACKET - sequential packet socket 80 | * @SOCK_PACKET - linux specific way of getting packets at the dev level. 81 | * For writing rarp and other similar things on the user level. 82 | */ 83 | enum sock_type { 84 | TARGET_SOCK_DGRAM = 1, 85 | TARGET_SOCK_STREAM = 2, 86 | TARGET_SOCK_RAW = 3, 87 | TARGET_SOCK_RDM = 4, 88 | TARGET_SOCK_SEQPACKET = 5, 89 | TARGET_SOCK_DCCP = 6, 90 | TARGET_SOCK_PACKET = 10, 91 | }; 92 | 93 | #define TARGET_SOCK_MAX (SOCK_PACKET + 1) 94 | 95 | #else 96 | 97 | /* For setsockopt(2) */ 98 | #define TARGET_SOL_SOCKET 1 99 | 100 | #define TARGET_SO_DEBUG 1 101 | #define TARGET_SO_REUSEADDR 2 102 | #define TARGET_SO_TYPE 3 103 | #define TARGET_SO_ERROR 4 104 | #define TARGET_SO_DONTROUTE 5 105 | #define TARGET_SO_BROADCAST 6 106 | #define TARGET_SO_SNDBUF 7 107 | #define TARGET_SO_RCVBUF 8 108 | #define TARGET_SO_SNDBUFFORCE 32 109 | #define TARGET_SO_RCVBUFFORCE 33 110 | #define TARGET_SO_KEEPALIVE 9 111 | #define TARGET_SO_OOBINLINE 10 112 | #define TARGET_SO_NO_CHECK 11 113 | #define TARGET_SO_PRIORITY 12 114 | #define TARGET_SO_LINGER 13 115 | #define TARGET_SO_BSDCOMPAT 14 116 | /* To add :#define TARGET_SO_REUSEPORT 15 */ 117 | #if defined(TARGET_PPC) 118 | #define TARGET_SO_RCVLOWAT 16 119 | #define TARGET_SO_SNDLOWAT 17 120 | #define TARGET_SO_RCVTIMEO 18 121 | #define TARGET_SO_SNDTIMEO 19 122 | #define TARGET_SO_PASSCRED 20 123 | #define TARGET_SO_PEERCRED 21 124 | #else 125 | #define TARGET_SO_PASSCRED 16 126 | #define TARGET_SO_PEERCRED 17 127 | #define TARGET_SO_RCVLOWAT 18 128 | #define TARGET_SO_SNDLOWAT 19 129 | #define TARGET_SO_RCVTIMEO 20 130 | #define TARGET_SO_SNDTIMEO 21 131 | #endif 132 | 133 | /* Security levels - as per NRL IPv6 - don't actually do anything */ 134 | #define TARGET_SO_SECURITY_AUTHENTICATION 22 135 | #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 136 | #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 137 | 138 | #define TARGET_SO_BINDTODEVICE 25 139 | 140 | /* Socket filtering */ 141 | #define TARGET_SO_ATTACH_FILTER 26 142 | #define TARGET_SO_DETACH_FILTER 27 143 | 144 | #define TARGET_SO_PEERNAME 28 145 | #define TARGET_SO_TIMESTAMP 29 146 | #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP 147 | 148 | #define TARGET_SO_ACCEPTCONN 30 149 | 150 | #define TARGET_SO_PEERSEC 31 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /tests/opcodes/x86_64/opcodes.txt: -------------------------------------------------------------------------------- 1 | PAND 2 | ADC 3 | ADD 4 | ADDPD 5 | ADDPS 6 | ADDSD 7 | ADDSS 8 | ADDSUBPD 9 | ADDSUBPS 10 | AND 11 | ANDNPD 12 | ANDNPS 13 | ANDPD 14 | ANDPS 15 | BLENDPS 16 | BSF 17 | BSR 18 | BSWAP 19 | BT 20 | BTC 21 | BTR 22 | BTS 23 | CALL 24 | CALLF 25 | CBW 26 | CLC 27 | CLD 28 | CLFLUSH 29 | CLI 30 | CLTS 31 | CMC 32 | CMOVB 33 | CMOVBE 34 | CMOVL 35 | CMOVLE 36 | CMOVNB 37 | CMOVNBE 38 | CMOVNL 39 | CMOVNLE 40 | CMOVNO 41 | CMOVNP 42 | CMOVNS 43 | CMOVNZ 44 | CMOVO 45 | CMOVP 46 | CMOVS 47 | CMOVZ 48 | CMP 49 | CMPPD 50 | CMPPS 51 | CMPS 52 | CMPSD 53 | CMPSS 54 | CMPXCHG 55 | CMPXCHG8B 56 | COMISD 57 | COMISS 58 | CPUID 59 | CRC32 60 | CVTDQ2PD 61 | CVTDQ2PS 62 | CVTPD2DQ 63 | CVTPD2PI 64 | CVTPD2PS 65 | CVTPI2PD 66 | CVTPI2PS 67 | CVTPS2DQ 68 | CVTPS2PD 69 | CVTPS2PI 70 | CVTSD2SI 71 | CVTSD2SS 72 | CVTSI2SD 73 | CVTSI2SS 74 | CVTSS2SD 75 | CVTSS2SI 76 | CVTTPD2DQ 77 | CVTTPD2PI 78 | CVTTPS2DQ 79 | CVTTPS2PI 80 | CVTTSD2SI 81 | CVTTSS2SI 82 | CWD 83 | DEC 84 | DIV 85 | DIVPD 86 | DIVPS 87 | DIVSD 88 | DIVSS 89 | DPPD 90 | DPPS 91 | ENTER 92 | EXTRACTPS 93 | FABS 94 | FADD 95 | FADDP 96 | FBLD 97 | FBSTP 98 | FCHS 99 | FCLEX 100 | FCMOVB 101 | FCMOVBE 102 | FCMOVE 103 | FCMOVNB 104 | FCMOVNBE 105 | FCMOVNE 106 | FCMOVNU 107 | FCMOVU 108 | FCOM 109 | FCOMI 110 | FCOMIP 111 | FCOMP 112 | FCOMPP 113 | FCOS 114 | FDECSTP 115 | FDIV 116 | FDIVP 117 | FDIVR 118 | FDIVRP 119 | FFREE 120 | FIADD 121 | FICOM 122 | FICOMP 123 | FIDIV 124 | FIDIVR 125 | FILD 126 | FIMUL 127 | FINCSTP 128 | FINIT 129 | FIST 130 | FISTP 131 | FISTTP 132 | FISUB 133 | FISUBR 134 | FLD 135 | FLD1 136 | FLDCW 137 | FLDENV 138 | FLDL2E 139 | FLDL2T 140 | FLDLG2 141 | FLDLN2 142 | FLDPI 143 | FLDZ 144 | FMUL 145 | FMULP 146 | FNCLEX 147 | FNDISI 148 | FNENI 149 | FNINIT 150 | FNOP 151 | FNSAVE 152 | FNSETPM 153 | FNSTCW 154 | FNSTENV 155 | FNSTSW 156 | FPATAN 157 | FPREM 158 | FPREM1 159 | FPTAN 160 | FRNDINT 161 | FRSTOR 162 | FSAVE 163 | FSCALE 164 | FSIN 165 | FSINCOS 166 | FSQRT 167 | FST 168 | FSTCW 169 | FSTENV 170 | FSTP 171 | FSTSW 172 | FSUB 173 | FSUBP 174 | FSUBR 175 | FSUBRP 176 | FTST 177 | FUCOM 178 | FUCOMI 179 | FUCOMIP 180 | FUCOMP 181 | FUCOMPP 182 | FWAIT 183 | FXAM 184 | FXCH 185 | FXRSTOR 186 | FXSAVE 187 | FXTRACT 188 | FYL2X 189 | FYL2XP1 190 | HADDPS 191 | HINT_NOP 192 | HLT 193 | HSUBPD 194 | HSUBPS 195 | IDIV 196 | IMUL 197 | IN 198 | INC 199 | INS 200 | INSERTPS 201 | INT 202 | INT 203 | INT1 204 | INTO 205 | INVD 206 | INVEPT 207 | INVLPG 208 | INVVPID 209 | IRET 210 | JB 211 | JBE 212 | JECXZ 213 | JL 214 | JLE 215 | JMP 216 | JMPE 217 | JMPF 218 | JNB 219 | JNBE 220 | JNL 221 | JNLE 222 | JNO 223 | JNP 224 | JNS 225 | JNZ 226 | JO 227 | JP 228 | JS 229 | JZ 230 | LAR 231 | LDDQU 232 | LDMXCSR 233 | LEA 234 | LEAVE 235 | LFENCE 236 | LFS 237 | LGDT 238 | LGS 239 | LIDT 240 | LLDT 241 | LMSW 242 | LODS 243 | LOOP 244 | LOOPNZ 245 | LOOPZ 246 | LSL 247 | LSS 248 | LTR 249 | MASKMOVQ 250 | MAXPD 251 | MAXPS 252 | MAXSD 253 | MAXSS 254 | MFENCE 255 | MINPD 256 | MINPS 257 | MINSD 258 | MINSS 259 | MONITOR 260 | MOV 261 | MOVAPD 262 | MOVAPS 263 | MOVBE 264 | MOVD 265 | MOVDDUP 266 | MOVDQ2Q 267 | MOVDQA 268 | MOVDQU 269 | MOVHLPS 270 | MOVHPD 271 | MOVHPS 272 | MOVLHPS 273 | MOVLPD 274 | MOVLPS 275 | MOVMSKPD 276 | MOVMSKPS 277 | MOVNTDQ 278 | MOVNTI 279 | MOVNTPD 280 | MOVNTPS 281 | MOVNTQ 282 | MOVQ 283 | MOVQ2DQ 284 | MOVS 285 | MOVSD 286 | MOVSHDUP 287 | MOVSLDUP 288 | MOVSS 289 | MOVSX 290 | MOVSXD 291 | MOVUPD 292 | MOVUPS 293 | MOVZX 294 | MPSADBW 295 | MUL 296 | MULPD 297 | MULPS 298 | MULSD 299 | MULSS 300 | MWAIT 301 | NEG 302 | NOP 303 | NOT 304 | OR 305 | ORPD 306 | ORPS 307 | OUT 308 | OUTS 309 | PACKSSDW 310 | PACKSSWB 311 | PACKUSWB 312 | PADDB 313 | PADDD 314 | PADDQ 315 | PADDSB 316 | PADDSW 317 | PADDUSB 318 | PADDUSW 319 | PADDW 320 | PALIGNR 321 | PANDN 322 | PAUSE 323 | PAVGB 324 | PAVGW 325 | PBLENDW 326 | PCMPEQB 327 | PCMPEQD 328 | PCMPEQW 329 | PCMPESTRI 330 | PCMPESTRM 331 | PCMPGTB 332 | PCMPGTD 333 | PCMPGTW 334 | PCMPISTRI 335 | PCMPISTRM 336 | PEXTRB 337 | PEXTRD 338 | PEXTRW 339 | PINSRB 340 | PINSRD 341 | PINSRW 342 | PMADDWD 343 | PMAXSW 344 | PMAXUB 345 | PMINSW 346 | PMINUB 347 | PMOVMSKB 348 | PMULHUW 349 | PMULHW 350 | PMULLW 351 | PMULUDQ 352 | POP 353 | POPCNT 354 | POPF 355 | POR 356 | PREFETCHNTA 357 | PREFETCHT0 358 | PREFETCHT1 359 | PREFETCHT2 360 | PSADBW 361 | PSHUFD 362 | PSHUFHW 363 | PSHUFLW 364 | PSHUFW 365 | PSLLD 366 | PSLLDQ 367 | PSLLQ 368 | PSLLW 369 | PSRAD 370 | PSRAW 371 | PSRLD 372 | PSRLDQ 373 | PSRLQ 374 | PSRLW 375 | PSUBB 376 | PSUBD 377 | PSUBQ 378 | PSUBSB 379 | PSUBSW 380 | PSUBUSB 381 | PSUBUSW 382 | PSUBW 383 | PUNPCKHBW 384 | PUNPCKHDQ 385 | PUNPCKHQDQ 386 | PUNPCKHWD 387 | PUNPCKLBW 388 | PUNPCKLDQ 389 | PUNPCKLQDQ 390 | PUNPCKLWD 391 | PUSH 392 | PUSHF 393 | PXOR 394 | RCL 395 | RCPPS 396 | RCPSS 397 | RCR 398 | RDMSR 399 | RDPMC 400 | RDTSC 401 | RDTSCP 402 | RETF 403 | RETN 404 | ROL 405 | ROR 406 | ROUNDPD 407 | ROUNDPS 408 | ROUNDSD 409 | ROUNDSS 410 | RSM 411 | RSQRTPS 412 | RSQRTSS 413 | SAL 414 | SAR 415 | SBB 416 | SCAS 417 | SETB 418 | SETBE 419 | SETL 420 | SETLE 421 | SETNB 422 | SETNBE 423 | SETNL 424 | SETNLE 425 | SETNO 426 | SETNP 427 | SETNS 428 | SETNZ 429 | SETO 430 | SETP 431 | SETS 432 | SETZ 433 | SFENCE 434 | SGDT 435 | SHL 436 | SHLD 437 | SHR 438 | SHRD 439 | SHUFPD 440 | SHUFPS 441 | SIDT 442 | SLDT 443 | SMSW 444 | SQRTPD 445 | SQRTPS 446 | SQRTSD 447 | SQRTSS 448 | STC 449 | STD 450 | STI 451 | STMXCSR 452 | STOS 453 | STR 454 | SUB 455 | SUBPD 456 | SUBPS 457 | SUBSD 458 | SUBSS 459 | SWAPGS 460 | SYSCALL 461 | SYSENTER 462 | SYSEXIT 463 | SYSRET 464 | TEST 465 | TEST 466 | UCOMISS 467 | UD2 468 | UNPCKHPD 469 | UNPCKHPS 470 | UNPCKLPD 471 | UNPCKLPS 472 | VERW 473 | VMCALL 474 | VMCLEAR 475 | VMLAUNCH 476 | VMPTRLD 477 | VMPTRST 478 | VMREAD 479 | VMRESUME 480 | VMWRITE 481 | VMXOFF 482 | VMXON 483 | WRMSR 484 | XADD 485 | XCHG 486 | XGETBV 487 | XLAT 488 | XOR 489 | XORPD 490 | XORPS 491 | XRSTOR 492 | XSAVE 493 | XSETBV -------------------------------------------------------------------------------- /tests/traces-src/fp-test.c: -------------------------------------------------------------------------------- 1 | /* fp-test.c - Check that all floating-point operations are available. 2 | Copyright (C) 1995 Free Software Foundation, Inc. 3 | Contributed by Ronald F. Guilmette . 4 | 5 | This file is part of GNU CC. 6 | 7 | GNU CC is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2, or (at your option) 10 | any later version. 11 | 12 | GNU CC is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with GNU CC; see the file COPYING. If not, write to 19 | the Free Software Foundation, 59 Temple Place - Suite 330, 20 | Boston, MA 02111-1307, USA. */ 21 | 22 | /* This is a trivial test program which may be useful to people who are 23 | porting the GCC or G++ compilers to a new system. The intent here is 24 | merely to check that all floating-point operations have been provided 25 | by the port. (Note that I say ``provided'' rather than ``implemented''.) 26 | 27 | To use this file, simply compile it (with GCC or G++) and then try to 28 | link it in the normal way (also using GCC or G++ respectively). If 29 | all of the floating -point operations (including conversions) have 30 | been provided, then this file will link without incident. If however 31 | one or more of the primitive floating-point operations have not been 32 | properly provided, you will get link-time errors indicating which 33 | floating-point operations are unavailable. 34 | 35 | This file will typically be used when porting the GNU compilers to 36 | some system which lacks floating-point hardware, and for which 37 | software emulation routines (for FP ops) are needed in order to 38 | complete the port. */ 39 | 40 | #if 0 41 | #include 42 | #endif 43 | 44 | extern double acos (double); 45 | extern double asin (double); 46 | extern double atan (double); 47 | extern double atan2 (double, double); 48 | extern double cos (double); 49 | extern double sin (double); 50 | extern double tan (double); 51 | extern double cosh (double); 52 | extern double sinh (double); 53 | extern double tanh (double); 54 | extern double exp (double); 55 | extern double frexp (double, int *); 56 | extern double ldexp (double, int); 57 | extern double log (double); 58 | extern double log10 (double); 59 | extern double modf (double, double *); 60 | extern double pow (double, double); 61 | extern double sqrt (double); 62 | extern double ceil (double); 63 | extern double fabs (double); 64 | extern double floor (double); 65 | extern double fmod (double, double); 66 | 67 | int i1, i2 = 2; 68 | 69 | volatile signed char sc; 70 | volatile unsigned char uc; 71 | 72 | volatile signed short ss; 73 | volatile unsigned short us; 74 | 75 | volatile signed int si; 76 | volatile unsigned int ui; 77 | 78 | volatile signed long sl; 79 | volatile unsigned long ul; 80 | 81 | volatile float f1 = 1.0, f2 = 1.0, f3 = 1.0; 82 | volatile double d1 = 1.0, d2 = 1.0, d3 = 1.0; 83 | volatile long double D1 = 1.0, D2 = 1.0, D3 = 1.0; 84 | 85 | int 86 | main () 87 | { 88 | /* TYPE: float */ 89 | 90 | f1 = -f2; 91 | f1 = f2 + f3; 92 | f1 = f2 - f3; 93 | f1 = f2 * f3; 94 | f1 = f2 / f3; 95 | f1 += f2; 96 | f1 -= f2; 97 | f1 *= f2; 98 | f1 /= f2; 99 | 100 | si = f1 == f2; 101 | si = f1 != f2; 102 | si = f1 > f2; 103 | si = f1 < f2; 104 | si = f1 >= f2; 105 | si = f1 <= f2; 106 | 107 | sc = f1; 108 | uc = f1; 109 | ss = f1; 110 | us = f1; 111 | si = f1; 112 | ui = f1; 113 | sl = f1; 114 | ul = f1; 115 | d1 = f1; 116 | D1 = f1; 117 | 118 | f1 = sc; 119 | f1 = uc; 120 | f1 = ss; 121 | f1 = us; 122 | f1 = si; 123 | f1 = ui; 124 | f1 = sl; 125 | f1 = ul; 126 | f1 = d1; 127 | f1 = D1; 128 | 129 | d1 = -d2; 130 | d1 = d2 + d3; 131 | d1 = d2 - d3; 132 | d1 = d2 * d3; 133 | d1 = d2 / d3; 134 | d1 += d2; 135 | d1 -= d2; 136 | d1 *= d2; 137 | d1 /= d2; 138 | 139 | si = d1 == d2; 140 | si = d1 != d2; 141 | si = d1 > d2; 142 | si = d1 < d2; 143 | si = d1 >= d2; 144 | si = d1 <= d2; 145 | 146 | sc = d1; 147 | uc = d1; 148 | ss = d1; 149 | us = d1; 150 | si = d1; 151 | ui = d1; 152 | sl = d1; 153 | ul = d1; 154 | f1 = d1; 155 | D1 = d1; 156 | 157 | d1 = sc; 158 | d1 = uc; 159 | d1 = ss; 160 | d1 = us; 161 | d1 = si; 162 | d1 = ui; 163 | d1 = sl; 164 | d1 = ul; 165 | d1 = f1; 166 | d1 = D1; 167 | 168 | D1 = -D2; 169 | D1 = D2 + D3; 170 | D1 = D2 - D3; 171 | D1 = D2 * D3; 172 | D1 = D2 / D3; 173 | D1 += D2; 174 | D1 -= D2; 175 | D1 *= D2; 176 | D1 /= D2; 177 | 178 | si = D1 == D2; 179 | si = D1 != D2; 180 | si = D1 > D2; 181 | si = D1 < D2; 182 | si = D1 >= D2; 183 | si = D1 <= D2; 184 | 185 | sc = D1; 186 | uc = D1; 187 | ss = D1; 188 | us = D1; 189 | si = D1; 190 | ui = D1; 191 | sl = D1; 192 | ul = D1; 193 | f1 = D1; 194 | d1 = D1; 195 | 196 | D1 = sc; 197 | D1 = uc; 198 | D1 = ss; 199 | D1 = us; 200 | D1 = si; 201 | D1 = ui; 202 | D1 = sl; 203 | D1 = ul; 204 | D1 = f1; 205 | D1 = d1; 206 | 207 | d1 = acos (d2); 208 | d1 = asin (d2); 209 | d1 = atan (d2); 210 | d1 = atan2 (d2, d3); 211 | d1 = cos (d2); 212 | d1 = sin (d2); 213 | d1 = tan (d2); 214 | d1 = cosh (d2); 215 | d1 = sinh (d2); 216 | d1 = tanh (d2); 217 | d1 = exp (d2); 218 | d1 = frexp (d2, &i1); 219 | d1 = ldexp (d2, i2); 220 | d1 = log (d2); 221 | d1 = log10 (d2); 222 | d1 = modf (d2, &d3); 223 | d1 = pow (d2, d3); 224 | d1 = sqrt (d2); 225 | d1 = ceil (d2); 226 | d1 = fabs (d2); 227 | d1 = floor (d2); 228 | d1 = fmod (d2, d3); 229 | 230 | return 0; 231 | } 232 | -------------------------------------------------------------------------------- /src/cpu/i386cpustate.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Sugar.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "guest.h" 9 | #include "i386cpustate.h" 10 | #include "sc_xlate.h" 11 | extern "C" { 12 | #include 13 | } 14 | 15 | #define state2i386() ((VexGuestX86State*)(state_data)) 16 | 17 | #define reg_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestX86State, guest_##x), true } 18 | #define reg_field_ent(x) reg_field_ent_w_n(x, sizeof(((VexGuestX86State*)0)->guest_##x), 1) 19 | #define raw_field_ent_w_n(x, w, n) { #x, w, n, offsetof(VexGuestX86State, x), true } 20 | #define raw_field_ent(x) raw_field_ent_w_n(x, sizeof((VexGuestX86State*)0)->x, 1) 21 | 22 | 23 | /* ripped from libvex_guest_86 */ 24 | static struct guest_ctx_field x86_fields[] = 25 | { 26 | raw_field_ent(host_EvC_FAILADDR), 27 | raw_field_ent(host_EvC_COUNTER), 28 | 29 | reg_field_ent(EAX), 30 | reg_field_ent(ECX), 31 | reg_field_ent(EDX), 32 | reg_field_ent(EBX), 33 | reg_field_ent(ESP), 34 | reg_field_ent(EBP), 35 | reg_field_ent(ESI), 36 | reg_field_ent(EDI), 37 | 38 | reg_field_ent(CC_OP), 39 | reg_field_ent(CC_DEP1), 40 | reg_field_ent(CC_DEP2), 41 | reg_field_ent(CC_NDEP), 42 | 43 | reg_field_ent(DFLAG), 44 | reg_field_ent(IDFLAG), 45 | reg_field_ent(ACFLAG), 46 | 47 | reg_field_ent(EIP), 48 | 49 | reg_field_ent_w_n(FPREG, 8, 8), 50 | reg_field_ent_w_n(FPTAG, 1, 8), 51 | reg_field_ent(FPROUND), 52 | reg_field_ent(FC3210), 53 | reg_field_ent(FTOP), 54 | 55 | reg_field_ent(SSEROUND), 56 | { "XMM", 16, 8, offsetof(VexGuestX86State, guest_XMM0), true }, 57 | 58 | 59 | reg_field_ent(CS), 60 | reg_field_ent(DS), 61 | reg_field_ent(ES), 62 | reg_field_ent(FS), 63 | reg_field_ent(GS), 64 | reg_field_ent(SS), 65 | 66 | reg_field_ent(LDT), 67 | reg_field_ent(GDT), 68 | 69 | reg_field_ent(EMNOTE), 70 | 71 | reg_field_ent(CMSTART), 72 | reg_field_ent(CMLEN), 73 | 74 | /* unredirected guest addr at start of translation whose 75 | * start has been redirected */ 76 | reg_field_ent(NRADDR), 77 | 78 | /* darwin hax */ 79 | reg_field_ent(SC_CLASS), 80 | reg_field_ent(IP_AT_SYSCALL), 81 | raw_field_ent(padding1), 82 | /* END VEX STRUCTURE */ 83 | 84 | {0} /* time to stop */ 85 | }; 86 | 87 | I386CPUState::I386CPUState() 88 | : VexCPUState(x86_fields) 89 | { 90 | state_byte_c = sizeof(VexGuestX86State); 91 | state_data = new uint8_t[state_byte_c+1]; 92 | memset(state_data, 0, state_byte_c+1); 93 | exit_type = &state_data[state_byte_c]; 94 | state2i386()->guest_DFLAG = 1; 95 | xlate = std::make_unique(); 96 | } 97 | 98 | void I386CPUState::noteRegion(const char* name, guest_ptr g) 99 | { 100 | if (strcmp(name, "regs.ldt") == 0) 101 | state2i386()->guest_LDT = g.o; 102 | else if (strcmp(name, "regs.gdt") == 0) 103 | state2i386()->guest_GDT = g.o; 104 | else 105 | VexCPUState::noteRegion(name, g); 106 | } 107 | 108 | I386CPUState::~I386CPUState() { delete [] state_data; } 109 | 110 | void I386CPUState::setPC(guest_ptr ip) { state2i386()->guest_EIP = ip; } 111 | 112 | guest_ptr I386CPUState::getPC(void) const 113 | { return guest_ptr(state2i386()->guest_EIP); } 114 | 115 | void I386CPUState::setStackPtr(guest_ptr stack_ptr) 116 | { 117 | state2i386()->guest_ESP = (uint64_t)stack_ptr; 118 | } 119 | 120 | guest_ptr I386CPUState::getStackPtr(void) const 121 | { 122 | return guest_ptr(state2i386()->guest_ESP); 123 | } 124 | 125 | // 160 == XMM base 126 | #define XMM_BASE offsetof(VexGuestX86State, guest_XMM0) 127 | #define get_xmm_lo(x,i) ((const uint64_t*)( \ 128 | &(((const uint8_t*)x)[XMM_BASE+16*i])))[0] 129 | #define get_xmm_hi(x,i) ((const uint64_t*)( \ 130 | &(((const uint8_t*)x)[XMM_BASE+16*i])))[1] 131 | 132 | void I386CPUState::print(std::ostream& os, const void* regctx) const 133 | { 134 | const VexGuestX86State *s; 135 | 136 | s = (const VexGuestX86State*)regctx; 137 | #define PRINT_GPR(X) os << #X": " << (void*)(uintptr_t)s->guest_##X << "\n"; 138 | PRINT_GPR(EIP) 139 | PRINT_GPR(EAX) 140 | PRINT_GPR(EBX) 141 | PRINT_GPR(ECX) 142 | PRINT_GPR(EDX) 143 | PRINT_GPR(ESP) 144 | PRINT_GPR(EBP) 145 | PRINT_GPR(EDI) 146 | PRINT_GPR(ESI) 147 | 148 | for (int i = 0; i < 8; i++) { 149 | os 150 | << "XMM" << i << ": " 151 | << (void*) get_xmm_hi(s, i) << "|" 152 | << (void*)get_xmm_lo(s, i) << std::endl; 153 | } 154 | 155 | for (int i = 0; i < 8; i++) { 156 | int r = (s->guest_FTOP + i) & 0x7; 157 | os 158 | << "ST" << i << ": " 159 | << (void*)s->guest_FPREG[r] << std::endl; 160 | } 161 | 162 | const char* seg_tab[] = {"CS", "DS", "ES", "FS", "GS", "SS"}; 163 | for (int i = 0; i < 6; i++) { 164 | os << seg_tab[i] << ": " 165 | << (void*)(uintptr_t)((short*)(&s->guest_CS))[i] << '\n'; 166 | } 167 | } 168 | 169 | #ifdef __i386__ 170 | void I386CPUState::setRegs( 171 | const user_regs_struct& regs, 172 | const user_fpregs_struct& fpregs) 173 | { 174 | state2i386()->guest_EAX = regs.eax; 175 | state2i386()->guest_ECX = regs.ecx; 176 | state2i386()->guest_EDX = regs.edx; 177 | state2i386()->guest_EBX = regs.ebx; 178 | state2i386()->guest_ESP = regs.esp; 179 | state2i386()->guest_EBP = regs.ebp; 180 | state2i386()->guest_ESI = regs.esi; 181 | state2i386()->guest_EDI = regs.edi; 182 | state2i386()->guest_EIP = regs.eip; 183 | 184 | //TODO: some kind of eflags, checking but i don't yet understand this 185 | //mess of broken apart state. 186 | 187 | //TODO: segments? valgrind does something less frakked up here 188 | //(than amd64) ... there are actual segments... and no fs zero 189 | 190 | memcpy( &state2i386()->guest_XMM0, 191 | &fpregs.xmm_space[0], 192 | sizeof(fpregs.xmm_space)); 193 | 194 | //TODO: this is surely wrong, the sizes don't even match... 195 | memcpy( &state2i386()->guest_FPREG[0], 196 | &fpregs.st_space[0], 197 | sizeof(state2i386()->guest_FPREG)); 198 | 199 | //TODO: floating point flags and extra fp state, sse rounding 200 | } 201 | #endif 202 | 203 | unsigned int I386CPUState::getStackRegOff(void) const 204 | { return offsetof(VexGuestX86State, guest_ESP); } -------------------------------------------------------------------------------- /src/cpu/armsyscalls.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Sugar.h" 4 | 5 | #include "cpu/sc_xlate.h" 6 | #include "guest.h" 7 | #include "guestmem.h" 8 | #include "cpu/armcpustate.h" 9 | 10 | /* this header loads all of the system headers outside of the namespace */ 11 | #include "qemu/translatedsyscall.h" 12 | 13 | static GuestMem* g_mem = NULL; 14 | static std::vector g_to_delete; 15 | 16 | namespace ARM { 17 | /* this will hold the last mapping that was changed during the syscall 18 | ... hopefully there is only one... */ 19 | 20 | /* we have to define a few platform specific types, non platform 21 | specific interface code goes in the translatedutil.h */ 22 | #define TARGET_ARM 23 | #define TARGET_ABI_BITS 32 24 | #define TARGET_ABI32 32 25 | #define abi_long int 26 | #define abi_ulong unsigned int 27 | #define target_ulong abi_ulong 28 | #define target_long abi_long 29 | #define PAGE_SIZE 4096 30 | #define HOST_PAGE_ALIGN(x) \ 31 | ((uintptr_t)x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) 32 | #define cpu_to_uname_machine(...) "armv7l" 33 | /* apparently, some syscalls depend on if the thing is EABI or not... 34 | i.e. truncate64, so we'll just say we are */ 35 | #define ARM_EABI 1 36 | 37 | /* memory mapping requires wrappers based on the host address 38 | space limitations */ 39 | #ifdef __amd64__ 40 | /* oh poo, this needs to record mappings... they don't right now */ 41 | #define mmap_find_vma(s, l) mmap_find_vma_flags(s, l, MAP_32BIT) 42 | #else 43 | #define mmap_find_vma(s, l) mmap_find_vma_flags(s, l, 0) 44 | #endif 45 | 46 | /* our implementations of stuff ripped out of the qemu files */ 47 | #include "qemu/translatedutil.h" 48 | /* generic type conversion utility routines */ 49 | #include "qemu/translatedthunk.h" 50 | /* terminal io definitions that are plaform dependent */ 51 | #include "qemu/armtermbits.h" 52 | /* platform dependent signals */ 53 | #include "qemu/armsignal.h" 54 | /* structure and flag definitions that are platform independent */ 55 | #include "qemu/translatedsyscalldefs.h" 56 | /* we need load our platform specific stuff as well */ 57 | #include "qemu/armsyscallnumbers.h" 58 | /* this constructs all of our syscall translation code */ 59 | #include "qemu/translatedsyscall.c" 60 | /* this constructs all of our syscall translation code */ 61 | #include "qemu/translatedsignal.c" 62 | /* this has some tables and such used for type conversion */ 63 | #include "qemu/translatedthunk.c" 64 | 65 | std::vector g_host_to_guest_syscalls(512); 66 | std::vector g_guest_to_host_syscalls(512); 67 | std::vector g_guest_syscall_names(512); 68 | bool syscall_mapping_init() { 69 | foreach(it, g_host_to_guest_syscalls.begin(), 70 | g_host_to_guest_syscalls.end()) *it = -1; 71 | foreach(it, g_guest_to_host_syscalls.begin(), 72 | g_guest_to_host_syscalls.end()) *it = -1; 73 | for(unsigned sys_nr = 0; 74 | sys_nr < g_guest_syscall_names.size(); ++sys_nr) 75 | { 76 | std::ostringstream o; 77 | o << sys_nr; 78 | g_guest_syscall_names[sys_nr] = o.str(); 79 | } 80 | #define SYSCALL_RELATION(name, host, guest) \ 81 | g_host_to_guest_syscalls[host] = guest; \ 82 | g_guest_to_host_syscalls[guest] = host; 83 | #define GUEST_SYSCALL(name, guest) \ 84 | g_guest_syscall_names[guest] = #name; 85 | #include "syscall/syscallsmapping.h" 86 | return true; 87 | } 88 | bool dummy_syscall_mapping = syscall_mapping_init(); 89 | } 90 | 91 | 92 | int ARMSyscallXlate::translateSyscall(int sys_nr) const { 93 | if((unsigned)sys_nr > ARM::g_guest_to_host_syscalls.size()) 94 | return -1; 95 | 96 | int host_sys_nr = ARM::g_guest_to_host_syscalls[sys_nr]; 97 | return host_sys_nr; 98 | } 99 | 100 | std::string ARMSyscallXlate::getSyscallName(int sys_nr) const { 101 | switch(sys_nr) { 102 | case ARM_NR_cacheflush: 103 | return "cacheflush"; 104 | case ARM_NR_set_tls: 105 | return "settls"; 106 | } 107 | if((unsigned)sys_nr > ARM::g_guest_syscall_names.size()) { 108 | std::ostringstream o; 109 | o << sys_nr; 110 | return o.str(); 111 | } 112 | return ARM::g_guest_syscall_names[sys_nr]; 113 | } 114 | 115 | 116 | uintptr_t ARMSyscallXlate::apply(Guest& g, SyscallParams& args) 117 | { 118 | unsigned long sc_ret = ~0UL; 119 | 120 | /* special syscalls that we handle per arch, these 121 | generally supersede any pass through or translated 122 | behaviors, but they can just alter the args and let 123 | the other mechanisms finish the job */ 124 | switch (args.getSyscall()) { 125 | case ARM_NR_set_tls: 126 | if(ARM_set_tls(g, args, sc_ret)) 127 | return sc_ret; 128 | break; 129 | case ARM_NR_cacheflush: 130 | if(ARM_cacheflush(g, args, sc_ret)) 131 | return sc_ret; 132 | break; 133 | case TARGET_NR_mmap2: 134 | if(ARM_mmap2(g, args, sc_ret)) 135 | return sc_ret; 136 | break; 137 | default: 138 | break; 139 | } 140 | 141 | if (tryPassthrough(g, args, (uintptr_t&)sc_ret)) return sc_ret; 142 | 143 | g_mem = g.getMem(); 144 | sc_ret = ARM::do_syscall(NULL, 145 | args.getSyscall(), 146 | args.getArg(0), 147 | args.getArg(1), 148 | args.getArg(2), 149 | args.getArg(3), 150 | args.getArg(4), 151 | args.getArg(5)); 152 | 153 | foreach(it, g_to_delete.begin(), g_to_delete.end()) 154 | delete [] *it; 155 | g_to_delete.clear(); 156 | 157 | return sc_ret; 158 | } 159 | 160 | SYSCALL_BODY(ARM, cacheflush) { return true; } 161 | 162 | SYSCALL_BODY(ARM, set_tls) 163 | { 164 | auto cpu_state = (ARMCPUState*)g.getCPUState(); 165 | cpu_state->setThreadPointer(args.getArg(0)); 166 | //also set the emulation location 167 | GuestMem::Mapping tls_area; 168 | auto mappings = g.getMem(); 169 | mappings->lookupMapping(guest_ptr(0xffff0000), tls_area); 170 | mappings->mprotect(guest_ptr(0xffff0000), PAGE_SIZE, 171 | tls_area.cur_prot | PROT_WRITE); 172 | mappings->write(guest_ptr(0xffff0ff0), (unsigned int)args.getArg(0)); 173 | mappings->mprotect(guest_ptr(0xffff0000), PAGE_SIZE, 174 | tls_area.cur_prot); 175 | sc_ret = 0; 176 | return true; 177 | } 178 | 179 | SYSCALL_BODY(ARM, mmap2) 180 | { 181 | guest_ptr m; 182 | sc_ret = g.getMem()->mmap(m, 183 | guest_ptr(args.getArg(0)), 184 | args.getArg(1), 185 | args.getArg(2), 186 | args.getArg(3), 187 | args.getArg(4), 188 | args.getArg(5) * PAGE_SIZE); 189 | if(sc_ret == 0) 190 | sc_ret = m; 191 | return true; 192 | } 193 | -------------------------------------------------------------------------------- /src/cpu/ptshadowi386.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cpu/i386_macros.h" 8 | #include "cpu/i386cpustate.h" 9 | #include "cpu/ptshadowi386.h" 10 | #include "cpu/pti386cpustate.h" 11 | 12 | #define WARNSTR "[PTimgI386] Warning: " 13 | #define INFOSTR "[PTimgI386] Info: " 14 | 15 | extern "C" { 16 | #include "valgrind/libvex_guest_x86.h" 17 | extern void x86g_dirtyhelper_CPUID_sse2 ( VexGuestX86State* st ); 18 | } 19 | 20 | #define I386CPU ((I386CPUState*)gs->getCPUState()) 21 | #define _pt_cpu ((PTI386CPUState*)pt_cpu.get()) 22 | 23 | /* from linux sources. whatever */ 24 | struct user_desc { 25 | unsigned int entry_number; 26 | unsigned int base_addr; 27 | unsigned int limit; 28 | unsigned int seg_32bit:1; 29 | unsigned int contents:2; 30 | unsigned int read_exec_only:1; 31 | unsigned int limit_in_pages:1; 32 | unsigned int seg_not_present:1; 33 | unsigned int useable:1; 34 | unsigned int lm:1; 35 | }; 36 | 37 | PTShadowI386::PTShadowI386(GuestPTImg* gs, int in_pid) 38 | : PTImgI386(gs, in_pid) 39 | {} 40 | 41 | bool PTShadowI386::isMatch(void) const { assert (0 == 1 && "STUB"); } 42 | 43 | const VexGuestX86State& PTShadowI386::getVexState(void) const 44 | { return *((const VexGuestX86State*)gs->getCPUState()->getStateData()); } 45 | VexGuestX86State& PTShadowI386::getVexState(void) 46 | { return *((VexGuestX86State*)gs->getCPUState()->getStateData()); } 47 | 48 | bool PTShadowI386::isRegMismatch() const { assert (0 == 1 && "STUB"); } 49 | void PTShadowI386::printFPRegs(std::ostream&) const { assert (0 == 1 && "STUB"); } 50 | void PTShadowI386::printUserRegs(std::ostream&) const { assert (0 == 1 && "STUB"); } 51 | 52 | void PTShadowI386::slurpRegisters(void) 53 | { 54 | auto vgs = (VexGuestX86State*)gs->getCPUState()->getStateData(); 55 | auto ®s = _pt_cpu->getRegs(); 56 | 57 | vgs->guest_EAX = regs.orig_eax; 58 | vgs->guest_EBX = regs.ebx; 59 | vgs->guest_ECX = regs.ecx; 60 | vgs->guest_EDX = regs.edx; 61 | vgs->guest_ESI = regs.esi; 62 | vgs->guest_ESP = regs.esp; 63 | vgs->guest_EBP = regs.ebp; 64 | vgs->guest_EDI = regs.edi; 65 | vgs->guest_EIP = regs.eip; 66 | 67 | vgs->guest_CS = regs.xcs; 68 | vgs->guest_DS = regs.xds; 69 | vgs->guest_ES = regs.xes; 70 | vgs->guest_FS = regs.xfs; 71 | vgs->guest_GS = regs.xgs; 72 | vgs->guest_SS = regs.xss; 73 | 74 | /* allocate GDT */ 75 | if (!vgs->guest_GDT && !vgs->guest_LDT) { 76 | fprintf(stderr, INFOSTR "gs=%p. fs=%p\n", 77 | (void*)regs.xgs, (void*)regs.xfs); 78 | setupGDT(); 79 | } 80 | } 81 | 82 | /* I might as well be writing an OS! */ 83 | void PTShadowI386::setupGDT(void) 84 | { 85 | guest_ptr gdt, ldt; 86 | VEXSEG default_ent; 87 | struct user_desc ud; 88 | 89 | fprintf(stderr, WARNSTR "Bogus GDT. Bogus LDT\n"); 90 | 91 | memset(&ud, 0, sizeof(ud)); 92 | ud.limit = ~0; 93 | ud.limit_in_pages = 1; 94 | ud2vexseg(ud, &default_ent.LdtEnt); 95 | 96 | if (gs->getMem()->mmap( 97 | gdt, 98 | guest_ptr(0), 99 | VEX_GUEST_X86_GDT_NENT*sizeof(VEXSEG), 100 | PROT_READ | PROT_WRITE, 101 | MAP_PRIVATE | MAP_ANONYMOUS, 102 | -1, 103 | 0) == 0) 104 | { 105 | VEXSEG *segs; 106 | I386CPU->noteRegion("regs.gdt", gdt); 107 | segs = (VEXSEG*)gs->getMem()->getHostPtr(gdt); 108 | for (unsigned i = 0; i < VEX_GUEST_X86_GDT_NENT; i++) { 109 | if (readThreadEntry(i, &segs[i])) 110 | continue; 111 | segs[i] = default_ent; 112 | } 113 | 114 | gs->getMem()->nameMapping(gdt, "gdt"); 115 | } 116 | 117 | if (gs->getMem()->mmap( 118 | ldt, 119 | guest_ptr(0), 120 | VEX_GUEST_X86_LDT_NENT*sizeof(VEXSEG), 121 | PROT_READ | PROT_WRITE, 122 | MAP_PRIVATE | MAP_ANONYMOUS, 123 | -1, 124 | 0) == 0) 125 | { 126 | VEXSEG *segs; 127 | I386CPU->noteRegion("regs.ldt", ldt); 128 | segs = (VEXSEG*)gs->getMem()->getHostPtr(ldt); 129 | for (unsigned i = 0; i < VEX_GUEST_X86_LDT_NENT; i++) { 130 | if (readThreadEntry(i, &segs[i])) 131 | continue; 132 | segs[i] = default_ent; 133 | } 134 | 135 | gs->getMem()->nameMapping(ldt, "ldt"); 136 | } 137 | } 138 | 139 | bool PTShadowI386::readThreadEntry(unsigned idx, VEXSEG* buf) 140 | { 141 | int err; 142 | struct user_desc ud; 143 | 144 | err = ptrace( 145 | (__ptrace_request)PTRACE_GET_THREAD_AREA, 146 | child_pid, 147 | idx, 148 | &ud); 149 | if (err == -1) 150 | return false; 151 | 152 | fprintf(stderr, 153 | INFOSTR "TLS[%d]: base=%p. limit=%p\n" 154 | INFOSTR "seg32=%d. contents=%d. not_present=%d. useable=%d\n", 155 | idx, (void*)(intptr_t)ud.base_addr, (void*)(intptr_t)ud.limit, 156 | ud.seg_32bit, ud.contents, ud.seg_not_present, ud.useable); 157 | 158 | /* translate linux user desc into vex/hw ldt */ 159 | ud2vexseg(ud, &buf->LdtEnt); 160 | return true; 161 | } 162 | 163 | bool PTShadowI386::patchCPUID(void) 164 | { 165 | struct x86_user_regs regs; 166 | VexGuestX86State fakeState; 167 | int err; 168 | static bool has_patched = false; 169 | struct iovec iov; 170 | 171 | iov.iov_base = ®s; 172 | iov.iov_len = sizeof(regs); 173 | err = ptrace((__ptrace_request)PTRACE_GETREGSET, child_pid, NT_PRSTATUS, &iov); 174 | assert(err != -1); 175 | 176 | /* -1 because the trap opcode is dispatched */ 177 | if (has_patched && cpuid_insts.count(regs.eip-1) == 0) { 178 | fprintf(stderr, INFOSTR "unpatched addr %p\n", (void*)regs.eip); 179 | return false; 180 | } 181 | 182 | fakeState.guest_EAX = regs.eax; 183 | fakeState.guest_EBX = regs.ebx; 184 | fakeState.guest_ECX = regs.ecx; 185 | fakeState.guest_EDX = regs.edx; 186 | x86g_dirtyhelper_CPUID_sse2(&fakeState); 187 | regs.eax = fakeState.guest_EAX; 188 | regs.ebx = fakeState.guest_EBX; 189 | regs.ecx = fakeState.guest_ECX; 190 | regs.edx = fakeState.guest_EDX; 191 | 192 | fprintf(stderr, INFOSTR "patched CPUID @ %p\n", (void*)regs.eip); 193 | 194 | /* skip over the extra byte from the cpuid opcode */ 195 | regs.eip += (has_patched) ? 1 : 2; 196 | 197 | err = ptrace((__ptrace_request)PTRACE_SETREGSET, child_pid, NT_PRSTATUS, &iov); 198 | assert (err != -1); 199 | 200 | has_patched = true; 201 | return true; 202 | } 203 | 204 | void PTShadowI386::trapCPUIDs(uint64_t bias) 205 | { 206 | foreach (it, patch_offsets.begin(), patch_offsets.end()) { 207 | uint64_t addr = *it + bias; 208 | cpuid_insts[addr] = _pt_cpu->setBreakpoint(guest_ptr(addr)); 209 | } 210 | } 211 | 212 | -------------------------------------------------------------------------------- /src/vexstmt.h: -------------------------------------------------------------------------------- 1 | #ifndef VEXSTMT_H 2 | #define VEXSTMT_H 3 | 4 | #include 5 | #include 6 | 7 | #include "Sugar.h" 8 | 9 | extern "C" { 10 | #include 11 | #include 12 | } 13 | #include "guestmem.h" 14 | 15 | namespace llvm 16 | { 17 | class Function; 18 | } 19 | 20 | class VexSB; 21 | class VexExpr; 22 | 23 | class VexStmt 24 | { 25 | public: 26 | virtual ~VexStmt(void) {} 27 | virtual void emit(void) const { assert (0 == 1 && "STUB"); } 28 | virtual void print(std::ostream& os) const = 0; 29 | const VexSB* getParent(void) const { return parent; } 30 | protected: 31 | VexStmt(VexSB* in_parent, const IRStmt* in_stmt) 32 | : parent(in_parent) {} 33 | VexSB* parent; 34 | }; 35 | 36 | class VexStmtNoOp : public VexStmt 37 | { 38 | public: 39 | VexStmtNoOp(VexSB* in_parent, const IRStmt* in_stmt) 40 | : VexStmt(in_parent, in_stmt) {} 41 | virtual ~VexStmtNoOp() {} 42 | virtual void emit(void) const { /* ignore */ } 43 | virtual void print(std::ostream& os) const; 44 | private: 45 | }; 46 | 47 | class VexStmtIMark : public VexStmt 48 | { 49 | public: 50 | VexStmtIMark(VexSB* in_parent, const IRStmt* in_stmt); 51 | VexStmtIMark(VexSB* in_parent, guest_ptr in_ga, unsigned int in_len) 52 | : VexStmt(in_parent, NULL), guest_addr(in_ga), guest_op_len(in_len) {} 53 | virtual ~VexStmtIMark() {} 54 | virtual void emit(void) const { /* ignore */ } 55 | virtual void print(std::ostream& os) const; 56 | guest_ptr getAddr(void) const { return guest_addr; } 57 | unsigned int getLen(void) const { return guest_op_len; } 58 | private: 59 | guest_ptr guest_addr; 60 | unsigned int guest_op_len; 61 | }; 62 | 63 | class VexStmtAbiHint : public VexStmt 64 | { 65 | public: 66 | VexStmtAbiHint(VexSB* in_parent, const IRStmt* in_stmt) 67 | : VexStmt(in_parent, in_stmt) {} 68 | virtual ~VexStmtAbiHint() {} 69 | virtual void emit(void) const { /* ignore */ } 70 | virtual void print(std::ostream& os) const; 71 | private: 72 | }; 73 | 74 | class VexStmtPut : public VexStmt 75 | { 76 | public: 77 | VexStmtPut(VexSB* in_parent, const IRStmt* in_stmt); 78 | VexStmtPut(VexSB* in_parent, int in_offset, VexExpr* in_data_expr) 79 | : VexStmt(in_parent, NULL), offset(in_offset), data_expr(in_data_expr) 80 | {} 81 | virtual ~VexStmtPut(); 82 | virtual void emit(void) const; 83 | virtual void print(std::ostream& os) const; 84 | private: 85 | int offset; /* Offset into the guest state */ 86 | VexExpr *data_expr; /* The value to write */ 87 | }; 88 | 89 | /* Write a guest register, at a non-fixed offset in the guest 90 | state. See the comment for GetI expressions for more 91 | information. */ 92 | class VexStmtPutI : public VexStmt 93 | { 94 | public: 95 | VexStmtPutI(VexSB* in_parent, const IRStmt* in_stmt); 96 | virtual ~VexStmtPutI() {} 97 | virtual void emit(void) const; 98 | virtual void print(std::ostream& os) const; 99 | private: 100 | int base; 101 | int len; 102 | VexExpr* ix_expr; /* Variable part of index into array */ 103 | int bias; /* Constant offset part of index into array */ 104 | VexExpr* data_expr; /* The value to write */ 105 | }; 106 | 107 | class VexStmtWrTmp : public VexStmt 108 | { 109 | public: 110 | VexStmtWrTmp(VexSB* in_parent, const IRStmt* in_stmt); 111 | virtual ~VexStmtWrTmp(); 112 | virtual void emit(void) const; 113 | virtual void print(std::ostream& os) const; 114 | private: 115 | int tmp_reg; 116 | VexExpr *expr; 117 | }; 118 | 119 | class VexStmtStore : public VexStmt 120 | { 121 | public: 122 | VexStmtStore(VexSB* in_parent, const IRStmt* in_stmt); 123 | virtual ~VexStmtStore(); 124 | virtual void emit(void) const; 125 | virtual void print(std::ostream& os) const; 126 | private: 127 | bool isLE; 128 | VexExpr *addr_expr; 129 | VexExpr *data_expr; 130 | }; 131 | 132 | class VexStmtCAS : public VexStmt 133 | { 134 | public: 135 | VexStmtCAS(VexSB* in_parent, const IRStmt* in_stmt); 136 | virtual ~VexStmtCAS(); 137 | virtual void emit(void) const; 138 | virtual void print(std::ostream& os) const; 139 | private: 140 | unsigned int oldVal_tmp, oldVal_tmpHI; 141 | VexExpr *addr; 142 | VexExpr *expected_val, *expected_valHI; 143 | VexExpr *new_val, *new_valHI; 144 | }; 145 | 146 | class VexStmtLLSC : public VexStmt 147 | { 148 | public: 149 | VexStmtLLSC(VexSB* in_parent, const IRStmt* in_stmt); 150 | virtual void emit(void) const; 151 | virtual ~VexStmtLLSC(); 152 | void emitLoad(void) const; 153 | void emitStore(void) const; 154 | virtual void print(std::ostream& os) const; 155 | private: 156 | int result; 157 | VexExpr* addr_expr; 158 | VexExpr* data_expr; /* NULL => LL, non-NULL => SC */ 159 | }; 160 | 161 | class VexStmtDirty : public VexStmt 162 | { 163 | public: 164 | VexStmtDirty(VexSB* in_parent, const IRStmt* in_stmt); 165 | virtual ~VexStmtDirty(); 166 | virtual void emit(void) const; 167 | virtual void print(std::ostream& os) const; 168 | private: 169 | VexExpr *guard; 170 | llvm::Function* func; 171 | ptr_vec_t args; 172 | int tmp_reg; /* where to store */ 173 | }; 174 | 175 | class VexStmtMBE : public VexStmt 176 | { 177 | public: 178 | VexStmtMBE(VexSB* in_parent, const IRStmt* in_stmt) 179 | : VexStmt(in_parent, in_stmt) {} 180 | virtual ~VexStmtMBE() {} 181 | virtual void emit(void) const; 182 | virtual void print(std::ostream& os) const; 183 | private: 184 | }; 185 | 186 | class VexStmtExit : public VexStmt 187 | { 188 | public: 189 | VexStmtExit(VexSB* in_parent, const IRStmt* in_stmt); 190 | virtual ~VexStmtExit(); 191 | virtual void emit(void) const; 192 | virtual void print(std::ostream& os) const; 193 | private: 194 | /* IRStmt.Ist.Exit */ 195 | VexExpr *guard; /* Conditional expression-- always 1-bit */ 196 | uint8_t exit_type; 197 | IRJumpKind jk; /* Jump kind */ 198 | guest_ptr dst; /* target constant */ 199 | }; 200 | 201 | class VexStmtStoreG : public VexStmt 202 | { 203 | public: 204 | VexStmtStoreG(VexSB* in_parent, const IRStmt* in_stmt); 205 | virtual ~VexStmtStoreG(void); 206 | virtual void emit(void) const; 207 | virtual void print(std::ostream& os) const; 208 | private: 209 | VexExpr *addr; 210 | VexExpr *data; 211 | VexExpr *guard; 212 | }; 213 | 214 | class VexStmtLoadG : public VexStmt 215 | { 216 | public: 217 | VexStmtLoadG(VexSB* in_parent, const IRStmt* in_stmt); 218 | virtual ~VexStmtLoadG(void); 219 | virtual void emit(void) const; 220 | virtual void print(std::ostream& os) const; 221 | private: 222 | IRLoadGOp loadg_op; /* conversions */ 223 | int dst_tmp; 224 | VexExpr *addr; 225 | VexExpr *alt; 226 | VexExpr *guard; 227 | }; 228 | 229 | #endif 230 | -------------------------------------------------------------------------------- /scripts/guest_cov.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This creates visualization of the hits in the memory map 4 | # In the future, it would be nice to get source-level info from this 5 | 6 | import sys 7 | import os 8 | import Image 9 | import ImageColor 10 | import colorsys 11 | 12 | class MemEnt: 13 | def __init__(self, l): 14 | l = l.replace('-',' ') 15 | l = l.split(' ') 16 | self.begin = int(l[0],0) 17 | self.end = int(l[1],0) 18 | self.prot = int(l[2]) 19 | def write(self): 20 | print "%x-%x %d" % (self.begin, self.end, self.prot) 21 | 22 | def is_exec(self): 23 | return (self.prot & 0x4) != 0 24 | 25 | @staticmethod 26 | def loadFromFile(fname): 27 | maptab = dict() 28 | mapf=open(fname,'r') 29 | for l in mapf: 30 | m = MemEnt(l) 31 | maptab[m.begin] = m 32 | mapf.close() 33 | return maptab 34 | 35 | def loadBBlockList(fname): 36 | bblist=[] 37 | funcf=open(fname, 'r') 38 | for l in funcf: 39 | if not l.startswith("fn=sb_0x"): 40 | continue 41 | addr=l.replace('fn=sb_','')[:-1] 42 | bblist.append(int(addr, 0)) 43 | funcf.close() 44 | return bblist 45 | 46 | 47 | def loadVisitedByInsAddrFile(insAddrFile): 48 | visited_tab = dict() 49 | f = open(insAddrFile, 'r') 50 | last_ins_addr=0 51 | for l in f: 52 | cur_ins_addr=int(l,0) 53 | dist=last_ins_addr-cur_ins_addr 54 | if dist < 0 or dist > 16: 55 | visited_tab[last_ins_addr] = 16 56 | else: 57 | visited_tab[last_ins_addr] = cur_ins_addr - last_ins_addr 58 | last_ins_addr = cur_ins_addr 59 | visited_tab.pop(0) 60 | print "Loaded ins addr file" 61 | return visited_tab 62 | 63 | def loadVisitedByFile(fname): 64 | visited_tab = dict() 65 | f = open(fname, 'r') 66 | for l in f: 67 | # 0xaddress numbytes 68 | v = l.split(' ') 69 | visited_tab[int(v[0],0)] = int(v[1]) 70 | f.close() 71 | return visited_tab 72 | 73 | def loadVisitedByRun(guestpath, bblist): 74 | visited_tab = dict() 75 | for a in bblist: 76 | s = os.popen('frag_run '+ ('0x%x' % a) +' '+guestpath).read() 77 | w = filter(lambda x : x.count('VSB') == 1, s.split('\n')) 78 | if len(w) == 0: 79 | vsb_sz = '0' 80 | else: 81 | fields= w[0].split(' ') 82 | vsb_sz = (fields[2].split('='))[1] 83 | print ('0x%x' % a) + " " + vsb_sz 84 | visited_tab[a] = int(vsb_sz) 85 | return visited_tab 86 | 87 | # symtab is a list sorted by address of (address, func_name, length) tuples 88 | def loadSyms(guestpath): 89 | symtab = [] 90 | f = open(guestpath + "/syms", 'r') 91 | # example: xdr_netobj 7f17cac14b70-7f17cac14b81 92 | for l in f: 93 | (func_name, addr_range) = l.split(' ') 94 | (addr_begin, addr_end) = addr_range.split('-') 95 | addr_begin = int('0x'+addr_begin,0) 96 | addr_end = int('0x'+addr_end,0) 97 | symtab.append((addr_begin, func_name, addr_end-addr_begin)) 98 | f.close() 99 | symtab.sort() 100 | return symtab 101 | 102 | # TODO: Binary search 103 | addr2sym_memo = (0, 'DERP DERP BAD FUNC', 1) 104 | def addr2sym(symtab, addr): 105 | global addr2sym_memo 106 | 107 | if addr < addr2sym_memo[0]+addr2sym_memo[2] and \ 108 | addr > addr2sym_memo[0]: 109 | return addr2sym_memo 110 | 111 | 112 | last_s = symtab[0] 113 | for s in symtab: 114 | if s[0] > addr: 115 | if addr < (last_s[0]+last_s[2]): 116 | addr2sym_memo = last_s 117 | return last_s 118 | return None 119 | last_s = s 120 | 121 | if last_s[0] > addr or addr > (last_s[0]+last_s[2]): 122 | return None 123 | 124 | addr2sym_memo = last_s 125 | return last_s 126 | 127 | # Format 128 | # function 129 | # ex: malloc 200 100 130 | def saveFuncCov(symtab, visited_tab, outdir): 131 | funcs_map = dict() 132 | print "Assigning coverages (get some coffee)" 133 | 134 | visited_list = list(set(visited_tab.items())) 135 | visited_list.sort() 136 | for (v_addr, v_bytes) in visited_list: 137 | sym = addr2sym(symtab, v_addr) 138 | if sym is None: 139 | print 'NOTFOUND '+ str(v_addr) 140 | continue 141 | 142 | if sym[1] not in funcs_map: 143 | funcs_map[sym[1]] = (sym[2], 0) 144 | (tot,cov) = funcs_map[sym[1]] 145 | funcs_map[sym[1]] = (tot, cov + v_bytes) 146 | 147 | print "Coverages assigned. Back to work." 148 | outfname = outdir + '/funcov.txt' 149 | f = open(outfname, 'w') 150 | for (func_name, (tot, cov)) in funcs_map.items(): 151 | f.write("%s %d %d\n" % (func_name, tot, cov)) 152 | f.close() 153 | 154 | def ent2img(visited_tab, m): 155 | global red 156 | 157 | target_px_w=640 158 | target_px_h=480 159 | target_px=target_px_w*target_px_h 160 | target_dim = (target_px_w, target_px_h) 161 | m.write() 162 | 163 | # only care about coverage for regions that are exec 164 | if not m.is_exec(): 165 | return None 166 | 167 | # ignore empty regions, if any 168 | if m.end - m.begin == 0: 169 | return None 170 | 171 | pixels_per_byte = float(target_px)/float(m.end - m.begin) 172 | if pixels_per_byte == 0: 173 | print "0 pixels per byte. Whoops" 174 | return None 175 | 176 | im = Image.new("RGB", target_dim, ImageColor.getrgb("black")) 177 | for (k, num_bytes) in visited_tab.items(): 178 | if k < m.begin or k+num_bytes > m.end: 179 | continue 180 | offset=int(pixels_per_byte*(k-m.begin)) 181 | for i in range(0, int(num_bytes*pixels_per_byte)): 182 | x = (offset+i) % target_px_w 183 | y = (offset+i) / target_px_w 184 | im.putpixel((x,y), red) 185 | return im 186 | 187 | 188 | from optparse import OptionParser 189 | op = OptionParser("usage: %prog guestpath [istats-file]") 190 | op.add_option( 191 | '-v', 192 | '--visited-file', 193 | dest='visitedFile', 194 | action="store", 195 | type="string") 196 | op.add_option( 197 | '-i', 198 | '--insaddr-file', 199 | dest='insAddrFile', 200 | action="store", 201 | type='string') 202 | op.add_option( 203 | '-o', 204 | '--output-dir', 205 | dest='outputDir', 206 | action='store', 207 | default='.', 208 | type='string') 209 | opts,args = op.parse_args() 210 | 211 | if len(args) == 0: 212 | op.error("invalid arguments") 213 | 214 | guestpath=args[0] 215 | 216 | maptab = MemEnt.loadFromFile(guestpath+"/mapinfo") 217 | symtab = loadSyms(guestpath) 218 | 219 | if opts.visitedFile: 220 | print "Visit file: " + opts.visitedFile 221 | visited_tab = loadVisitedByFile(opts.visitedFile) 222 | elif opts.insAddrFile: 223 | visited_tab = loadVisitedByInsAddrFile(opts.insAddrFile) 224 | else: 225 | istatspath=args[1] 226 | bblist = loadBBlockList(istatspath) 227 | visited_tab = loadVisitedByRun(guestpath, bblist) 228 | 229 | 230 | red = ImageColor.getrgb("red") 231 | 232 | print "SaveFuncCov" 233 | saveFuncCov(symtab, visited_tab, opts.outputDir) 234 | for m in maptab.values(): 235 | im = ent2img(visited_tab, m) 236 | if im is None: 237 | continue 238 | outfname = ('cov-0x%x' % m.begin) + '.png' 239 | if opts.outputDir: 240 | outfname = "%s/%s" % (opts.outputDir,outfname) 241 | im.save(outfname) 242 | 243 | --------------------------------------------------------------------------------