mirror of
https://github.com/geohot/qira
synced 2025-03-13 02:23:07 +03:00
1153 lines
38 KiB
Diff
1153 lines
38 KiB
Diff
diff -ruN qemu-2.5.1/disas.c qemu-2.5.1-patched/disas.c
|
|
--- qemu-2.5.1/disas.c 2016-03-29 22:01:14.000000000 +0100
|
|
+++ qemu-2.5.1-patched/disas.c 2016-03-30 16:48:08.429754903 +0100
|
|
@@ -172,6 +172,7 @@
|
|
return print_insn_objdump(pc, info, "OBJD-T");
|
|
}
|
|
|
|
+
|
|
/* Disassemble this for me please... (debugging). 'flags' has the following
|
|
values:
|
|
i386 - 1 means 16 bit code, 2 means 64 bit code
|
|
@@ -179,7 +180,7 @@
|
|
bit 16 indicates little endian.
|
|
other targets - unused
|
|
*/
|
|
-void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|
+void real_target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
|
target_ulong size, int flags)
|
|
{
|
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
@@ -228,7 +229,7 @@
|
|
s.info.mach = bfd_mach_ppc;
|
|
#endif
|
|
}
|
|
- s.info.disassembler_options = (char *)"any";
|
|
+ s.info.disassembler_options = (char *)"intel";
|
|
s.info.print_insn = print_insn_ppc;
|
|
#endif
|
|
if (s.info.print_insn == NULL) {
|
|
@@ -236,6 +237,10 @@
|
|
}
|
|
|
|
for (pc = code; size > 0; pc += count, size -= count) {
|
|
+ #ifdef TARGET_ARM
|
|
+ if (flags & 1) fprintf(out, "t");
|
|
+ else fprintf(out, "n");
|
|
+ #endif
|
|
fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
|
|
count = s.info.print_insn(pc, &s.info);
|
|
#if 0
|
|
diff -ruN qemu-2.5.1/include/librarymap.h qemu-2.5.1-patched/include/librarymap.h
|
|
--- qemu-2.5.1/include/librarymap.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ qemu-2.5.1-patched/include/librarymap.h 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -0,0 +1,38 @@
|
|
+struct librarymap {
|
|
+ struct librarymap *next;
|
|
+ abi_ulong begin;
|
|
+ abi_ulong end;
|
|
+ const char *name;
|
|
+};
|
|
+
|
|
+struct librarymap *GLOBAL_librarymap;
|
|
+
|
|
+void init_librarymap(void);
|
|
+void add_to_librarymap(const char *name, abi_ulong begin, abi_ulong end);
|
|
+bool is_library_addr(abi_ulong addr);
|
|
+
|
|
+void init_librarymap(void){
|
|
+ GLOBAL_librarymap = malloc(sizeof(struct librarymap));
|
|
+ memset(GLOBAL_librarymap, 0, sizeof(struct librarymap));
|
|
+ GLOBAL_librarymap->name = "dummy";
|
|
+}
|
|
+
|
|
+void add_to_librarymap(const char *name, abi_ulong begin, abi_ulong end){
|
|
+ struct librarymap *cur, *newmap;
|
|
+ for(cur = GLOBAL_librarymap; cur->next != NULL; cur = cur->next);
|
|
+ newmap = malloc(sizeof(struct librarymap));
|
|
+ newmap->next = NULL;
|
|
+ newmap->begin = begin;
|
|
+ newmap->end = end;
|
|
+ newmap->name = strdup(name);
|
|
+ cur->next = newmap;
|
|
+}
|
|
+
|
|
+bool is_library_addr(abi_ulong addr){
|
|
+ struct librarymap *cur = GLOBAL_librarymap;
|
|
+ while(cur != NULL){
|
|
+ if (addr >= cur->begin && addr <= cur->end) return true;
|
|
+ cur = cur->next;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
diff -ruN qemu-2.5.1/linux-user/elfload.c qemu-2.5.1-patched/linux-user/elfload.c
|
|
--- qemu-2.5.1/linux-user/elfload.c 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/elfload.c 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -1808,6 +1808,9 @@
|
|
|
|
On return: INFO values will be filled in, as necessary or available. */
|
|
|
|
+extern struct library *GLOBAL_librarymap;
|
|
+extern const char *filename;
|
|
+
|
|
static void load_elf_image(const char *image_name, int image_fd,
|
|
struct image_info *info, char **pinterp_name,
|
|
char bprm_buf[BPRM_BUF_SIZE])
|
|
@@ -1874,6 +1877,12 @@
|
|
load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
|
|
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
|
-1, 0);
|
|
+
|
|
+ if (strcmp(filename, image_name)){
|
|
+ if (GLOBAL_librarymap == NULL) init_librarymap();
|
|
+ add_to_librarymap(image_name, load_addr, load_addr+(hiaddr-loaddr));
|
|
+ }
|
|
+
|
|
if (load_addr == -1) {
|
|
goto exit_perror;
|
|
}
|
|
diff -ruN qemu-2.5.1/linux-user/main.c qemu-2.5.1-patched/linux-user/main.c
|
|
--- qemu-2.5.1/linux-user/main.c 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/main.c 2016-03-30 17:39:36.487105911 +0100
|
|
@@ -37,7 +37,7 @@
|
|
char *exec_path;
|
|
|
|
int singlestep;
|
|
-static const char *filename;
|
|
+const char *filename;
|
|
static const char *argv0;
|
|
static int gdbstub_port;
|
|
static envlist_t *envlist;
|
|
@@ -275,6 +275,7 @@
|
|
int trapnr;
|
|
abi_ulong pc;
|
|
target_siginfo_t info;
|
|
+ void *a;
|
|
|
|
for(;;) {
|
|
cpu_exec_start(cs);
|
|
@@ -3899,6 +3900,28 @@
|
|
const char *help;
|
|
};
|
|
|
|
+extern int GLOBAL_parent_id, GLOBAL_start_clnum, GLOBAL_id;
|
|
+
|
|
+static void handle_arg_qirachild(const char *arg) {
|
|
+ singlestep = 1; // always
|
|
+
|
|
+ int ret = sscanf(arg, "%d %d %d", &GLOBAL_parent_id, &GLOBAL_start_clnum, &GLOBAL_id);
|
|
+ if (ret != 3) {
|
|
+ printf("CORRUPT qirachild\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+extern int GLOBAL_tracelibraries;
|
|
+
|
|
+static void handle_arg_tracelibraries(const char *arg) {
|
|
+ GLOBAL_tracelibraries = 1;
|
|
+}
|
|
+
|
|
+extern uint64_t GLOBAL_gatetrace;
|
|
+static void handle_arg_gatetrace(const char *arg) {
|
|
+ GLOBAL_gatetrace = strtoull(arg, NULL, 0);
|
|
+}
|
|
+
|
|
static const struct qemu_argument arg_table[] = {
|
|
{"h", "", false, handle_arg_help,
|
|
"", "print this help"},
|
|
@@ -3933,6 +3956,12 @@
|
|
"pagesize", "set the host page size to 'pagesize'"},
|
|
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
|
|
"", "run in singlestep mode"},
|
|
+ {"qirachild", "QIRA_CHILD", true, handle_arg_qirachild,
|
|
+ "", "parent_id, start_clnum, id"},
|
|
+ {"tracelibraries", "QIRA_TRACELIBRARIES", false, handle_arg_tracelibraries,
|
|
+ "", ""},
|
|
+ {"gatetrace", "QIRA_GATETRACE", true, handle_arg_gatetrace,
|
|
+ "", "address to gate starting trace on"},
|
|
{"strace", "QEMU_STRACE", false, handle_arg_strace,
|
|
"", "log system calls"},
|
|
{"seed", "QEMU_RAND_SEED", true, handle_arg_randseed,
|
|
diff -ruN qemu-2.5.1/linux-user/qemu.h qemu-2.5.1-patched/linux-user/qemu.h
|
|
--- qemu-2.5.1/linux-user/qemu.h 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/qemu.h 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -22,6 +22,8 @@
|
|
|
|
#define THREAD __thread
|
|
|
|
+#define QIRA_TRACKING
|
|
+
|
|
/* This struct is used to hold certain information about the image.
|
|
* Basically, it replicates in user space what would be certain
|
|
* task_struct fields in the kernel
|
|
@@ -362,6 +364,7 @@
|
|
#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t)
|
|
#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t)
|
|
|
|
+
|
|
/* copy_from_user() and copy_to_user() are usually used to copy data
|
|
* buffers between the target and host. These internally perform
|
|
* locking/unlocking of the memory.
|
|
@@ -375,10 +378,17 @@
|
|
any byteswapping. lock_user may return either a pointer to the guest
|
|
memory, or a temporary buffer. */
|
|
|
|
+
|
|
+#ifdef QIRA_TRACKING
|
|
+void track_kernel_read(void *host_addr, target_ulong guest_addr, long len);
|
|
+void track_kernel_write(void *host_addr, target_ulong guest_addr, long len);
|
|
+#endif
|
|
+
|
|
/* Lock an area of guest memory into the host. If copy is true then the
|
|
host area will have the same contents as the guest. */
|
|
static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
|
|
{
|
|
+ void *ret;
|
|
if (!access_ok(type, guest_addr, len))
|
|
return NULL;
|
|
#ifdef DEBUG_REMAP
|
|
@@ -389,11 +399,18 @@
|
|
memcpy(addr, g2h(guest_addr), len);
|
|
else
|
|
memset(addr, 0, len);
|
|
- return addr;
|
|
+ ret = addr;
|
|
}
|
|
#else
|
|
- return g2h(guest_addr);
|
|
+ ret = g2h(guest_addr);
|
|
#endif
|
|
+
|
|
+#ifdef QIRA_TRACKING
|
|
+ if (type == VERIFY_READ) {
|
|
+ track_kernel_read(ret, guest_addr, len);
|
|
+ }
|
|
+#endif
|
|
+ return ret;
|
|
}
|
|
|
|
/* Unlock an area of guest memory. The first LEN bytes must be
|
|
@@ -402,6 +419,11 @@
|
|
static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
|
|
long len)
|
|
{
|
|
+#ifdef QIRA_TRACKING
|
|
+ if (len > 0) {
|
|
+ track_kernel_write(host_ptr, guest_addr, len);
|
|
+ }
|
|
+#endif
|
|
|
|
#ifdef DEBUG_REMAP
|
|
if (!host_ptr)
|
|
diff -ruN qemu-2.5.1/linux-user/strace.c qemu-2.5.1-patched/linux-user/strace.c
|
|
--- qemu-2.5.1/linux-user/strace.c 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/strace.c 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -11,6 +11,16 @@
|
|
#include <sched.h>
|
|
#include "qemu.h"
|
|
|
|
+#undef TARGET_ABI_FMT_lx
|
|
+#ifdef TARGET_ABI32
|
|
+#define TARGET_ABI_FMT_lx "%x"
|
|
+#else
|
|
+#define TARGET_ABI_FMT_lx "%llx"
|
|
+#endif
|
|
+
|
|
+extern FILE *GLOBAL_strace_file;
|
|
+#define gemu_log(x...) { fprintf(GLOBAL_strace_file, x); fflush(GLOBAL_strace_file); }
|
|
+
|
|
int do_strace=0;
|
|
|
|
struct syscallname {
|
|
@@ -637,10 +647,11 @@
|
|
static void
|
|
print_pointer(abi_long p, int last)
|
|
{
|
|
- if (p == 0)
|
|
+ if (p == 0) {
|
|
gemu_log("NULL%s", get_comma(last));
|
|
- else
|
|
+ } else {
|
|
gemu_log("0x" TARGET_ABI_FMT_lx "%s", p, get_comma(last));
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -1562,6 +1573,8 @@
|
|
|
|
static int nsyscalls = ARRAY_SIZE(scnames);
|
|
|
|
+uint32_t get_current_clnum(void);
|
|
+
|
|
/*
|
|
* The public interface to this module.
|
|
*/
|
|
@@ -1573,6 +1586,7 @@
|
|
int i;
|
|
const char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")";
|
|
|
|
+ gemu_log("%d ", get_current_clnum() );
|
|
gemu_log("%d ", getpid() );
|
|
|
|
for(i=0;i<nsyscalls;i++)
|
|
diff -ruN qemu-2.5.1/linux-user/strace.list qemu-2.5.1-patched/linux-user/strace.list
|
|
--- qemu-2.5.1/linux-user/strace.list 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/strace.list 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -1000,7 +1000,7 @@
|
|
{ TARGET_NR_quotactl, "quotactl" , NULL, NULL, NULL },
|
|
#endif
|
|
#ifdef TARGET_NR_read
|
|
-{ TARGET_NR_read, "read" , "%s(%d,%#x,%d)", NULL, NULL },
|
|
+{ TARGET_NR_read, "read" , "%s(%d,0x"TARGET_ABI_FMT_lx",%d)", NULL, NULL },
|
|
#endif
|
|
#ifdef TARGET_NR_readahead
|
|
{ TARGET_NR_readahead, "readahead" , NULL, NULL, NULL },
|
|
@@ -1519,7 +1519,7 @@
|
|
{ TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
|
|
#endif
|
|
#ifdef TARGET_NR_write
|
|
-{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL },
|
|
+{ TARGET_NR_write, "write" , "%s(%d,0x"TARGET_ABI_FMT_lx",%d)", NULL, NULL },
|
|
#endif
|
|
#ifdef TARGET_NR_writev
|
|
{ TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
|
|
diff -ruN qemu-2.5.1/linux-user/syscall.c qemu-2.5.1-patched/linux-user/syscall.c
|
|
--- qemu-2.5.1/linux-user/syscall.c 2016-03-29 22:01:17.000000000 +0100
|
|
+++ qemu-2.5.1-patched/linux-user/syscall.c 2016-03-30 16:45:38.821919080 +0100
|
|
@@ -5663,6 +5663,8 @@
|
|
return timerid;
|
|
}
|
|
|
|
+extern void add_to_librarymap(const char *name, abi_ulong begin, abi_ulong end);
|
|
+
|
|
/* do_syscall() should always have a single exit point at the end so
|
|
that actions, such as logging of syscall results, can be performed.
|
|
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
|
|
@@ -10029,6 +10031,24 @@
|
|
#endif
|
|
if(do_strace)
|
|
print_syscall_ret(num, ret);
|
|
+
|
|
+#ifdef TARGET_NR_mmap2
|
|
+ if (num == TARGET_NR_mmap || num == TARGET_NR_mmap2){
|
|
+#else
|
|
+ if (num == TARGET_NR_mmap){
|
|
+#endif
|
|
+ int fd = arg5;
|
|
+ target_ulong mapaddr = ret;
|
|
+ target_ulong size = arg2;
|
|
+ if (fd >= 30){
|
|
+ add_to_librarymap("unknown", mapaddr, mapaddr+size);
|
|
+ }
|
|
+ }else if (num == TARGET_NR_open){
|
|
+ /* here we could store the fd->libname mapping */
|
|
+ }else if (num == TARGET_NR_close){
|
|
+ /* here we could clear the fd->libname mapping */
|
|
+ }
|
|
+
|
|
return ret;
|
|
efault:
|
|
ret = -TARGET_EFAULT;
|
|
diff -ruN qemu-2.5.1/tci.c qemu-2.5.1-patched/tci.c
|
|
--- qemu-2.5.1/tci.c 2016-03-29 22:01:20.000000000 +0100
|
|
+++ qemu-2.5.1-patched/tci.c 2016-03-30 17:39:24.918794988 +0100
|
|
@@ -28,6 +28,7 @@
|
|
#include "exec/exec-all.h" /* MAX_OPC_PARAM_IARGS */
|
|
#include "exec/cpu_ldst.h"
|
|
#include "tcg-op.h"
|
|
+#include "librarymap.h"
|
|
|
|
/* Marker for missing code. */
|
|
#define TODO() \
|
|
@@ -413,6 +414,269 @@
|
|
return result;
|
|
}
|
|
|
|
+// if it's not softmmu, assume it's user
|
|
+#ifndef CONFIG_SOFTMMU
|
|
+#define QEMU_USER
|
|
+#endif
|
|
+
|
|
+#define QIRA_TRACKING
|
|
+
|
|
+#ifdef QIRA_TRACKING
|
|
+
|
|
+#include <fcntl.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/file.h>
|
|
+
|
|
+#ifdef QEMU_USER
|
|
+#include "qemu.h"
|
|
+#endif
|
|
+
|
|
+#define QIRA_DEBUG(...) {}
|
|
+//#define QIRA_DEBUG qemu_debug
|
|
+//#define QIRA_DEBUG printf
|
|
+
|
|
+// struct storing change data
|
|
+struct change {
|
|
+ uint64_t address;
|
|
+ uint64_t data;
|
|
+ uint32_t changelist_number;
|
|
+ uint32_t flags;
|
|
+};
|
|
+
|
|
+// prototypes
|
|
+void init_QIRA(CPUArchState *env, int id);
|
|
+struct change *add_change(target_ulong addr, uint64_t data, uint32_t flags);
|
|
+void track_load(target_ulong a, uint64_t data, int size);
|
|
+void track_store(target_ulong a, uint64_t data, int size);
|
|
+void track_read(target_ulong base, target_ulong offset, target_ulong data, int size);
|
|
+void track_write(target_ulong base, target_ulong offset, target_ulong data, int size);
|
|
+void add_pending_change(target_ulong addr, uint64_t data, uint32_t flags);
|
|
+void commit_pending_changes(void);
|
|
+void resize_change_buffer(size_t size);
|
|
+
|
|
+// defined in qemu.h
|
|
+//void track_kernel_read(void *host_addr, target_ulong guest_addr, long len);
|
|
+//void track_kernel_write(void *host_addr, target_ulong guest_addr, long len);
|
|
+
|
|
+#define IS_VALID 0x80000000
|
|
+#define IS_WRITE 0x40000000
|
|
+#define IS_MEM 0x20000000
|
|
+#define IS_START 0x10000000
|
|
+#define IS_SYSCALL 0x08000000
|
|
+#define SIZE_MASK 0xFF
|
|
+
|
|
+#define FAKE_SYSCALL_LOADSEG 0x10001
|
|
+
|
|
+int GLOBAL_QIRA_did_init = 0;
|
|
+CPUArchState *GLOBAL_CPUArchState;
|
|
+struct change *GLOBAL_change_buffer;
|
|
+
|
|
+uint32_t GLOBAL_qira_log_fd;
|
|
+size_t GLOBAL_change_size;
|
|
+
|
|
+// current state that must survive forks
|
|
+struct logstate {
|
|
+ uint32_t change_count;
|
|
+ uint32_t changelist_number;
|
|
+ uint32_t is_filtered;
|
|
+ uint32_t first_changelist_number;
|
|
+ int parent_id;
|
|
+ int this_pid;
|
|
+};
|
|
+struct logstate *GLOBAL_logstate;
|
|
+
|
|
+// input args
|
|
+uint32_t GLOBAL_start_clnum = 1;
|
|
+int GLOBAL_parent_id = -1, GLOBAL_id = -1;
|
|
+
|
|
+int GLOBAL_tracelibraries = 0;
|
|
+uint64_t GLOBAL_gatetrace = 0;
|
|
+
|
|
+#define OPEN_GLOBAL_ASM_FILE { if (unlikely(GLOBAL_asm_file == NULL)) { GLOBAL_asm_file = fopen("/tmp/qira_asm", "a"); } }
|
|
+FILE *GLOBAL_asm_file = NULL;
|
|
+FILE *GLOBAL_strace_file = NULL;
|
|
+
|
|
+// should be 0ed on startup
|
|
+#define PENDING_CHANGES_MAX_ADDR 0x100
|
|
+struct change GLOBAL_pending_changes[PENDING_CHANGES_MAX_ADDR/4];
|
|
+
|
|
+uint32_t get_current_clnum(void);
|
|
+uint32_t get_current_clnum(void) {
|
|
+ return GLOBAL_logstate->changelist_number;
|
|
+}
|
|
+
|
|
+void resize_change_buffer(size_t size) {
|
|
+ if(ftruncate(GLOBAL_qira_log_fd, size)) {
|
|
+ perror("ftruncate");
|
|
+ }
|
|
+ GLOBAL_change_buffer = mmap(NULL, size,
|
|
+ PROT_READ | PROT_WRITE, MAP_SHARED, GLOBAL_qira_log_fd, 0);
|
|
+ GLOBAL_logstate = (struct logstate *)GLOBAL_change_buffer;
|
|
+ if (GLOBAL_change_buffer == NULL) QIRA_DEBUG("MMAP FAILED!\n");
|
|
+}
|
|
+
|
|
+void init_QIRA(CPUArchState *env, int id) {
|
|
+ QIRA_DEBUG("init QIRA called\n");
|
|
+ GLOBAL_QIRA_did_init = 1;
|
|
+ GLOBAL_CPUArchState = env; // unused
|
|
+
|
|
+ OPEN_GLOBAL_ASM_FILE
|
|
+
|
|
+ char fn[PATH_MAX];
|
|
+ sprintf(fn, "/tmp/qira_logs/%d_strace", id);
|
|
+ GLOBAL_strace_file = fopen(fn, "w");
|
|
+
|
|
+ sprintf(fn, "/tmp/qira_logs/%d", id);
|
|
+
|
|
+ // unlink it first
|
|
+ unlink(fn);
|
|
+ GLOBAL_qira_log_fd = open(fn, O_RDWR | O_CREAT, 0644);
|
|
+ GLOBAL_change_size = 1;
|
|
+ memset(GLOBAL_pending_changes, 0, (PENDING_CHANGES_MAX_ADDR/4) * sizeof(struct change));
|
|
+
|
|
+ resize_change_buffer(GLOBAL_change_size * sizeof(struct change));
|
|
+ memset(GLOBAL_change_buffer, 0, sizeof(struct change));
|
|
+
|
|
+ // skip the first change
|
|
+ GLOBAL_logstate->change_count = 1;
|
|
+ GLOBAL_logstate->is_filtered = 0;
|
|
+ GLOBAL_logstate->this_pid = getpid();
|
|
+
|
|
+ // do this after init_QIRA
|
|
+ GLOBAL_logstate->changelist_number = GLOBAL_start_clnum-1;
|
|
+ GLOBAL_logstate->first_changelist_number = GLOBAL_start_clnum;
|
|
+ GLOBAL_logstate->parent_id = GLOBAL_parent_id;
|
|
+
|
|
+ // use all fds up to 30
|
|
+ int i;
|
|
+ int dupme = open("/dev/null", O_RDONLY);
|
|
+ struct stat useless;
|
|
+ for (i = 0; i < 30; i++) {
|
|
+ sprintf(fn, "/proc/self/fd/%d", i);
|
|
+ if (stat(fn, &useless) == -1) {
|
|
+ //printf("dup2 %d %d\n", dupme, i);
|
|
+ dup2(dupme, i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (GLOBAL_librarymap == NULL){
|
|
+ init_librarymap();
|
|
+ }
|
|
+
|
|
+ // no more opens can happen here in QEMU, only the target process
|
|
+}
|
|
+
|
|
+struct change *add_change(target_ulong addr, uint64_t data, uint32_t flags) {
|
|
+ size_t cc = __sync_fetch_and_add(&GLOBAL_logstate->change_count, 1);
|
|
+
|
|
+ if (cc == GLOBAL_change_size) {
|
|
+ // double the buffer size
|
|
+ QIRA_DEBUG("doubling buffer with size %d\n", GLOBAL_change_size);
|
|
+ resize_change_buffer(GLOBAL_change_size * sizeof(struct change) * 2);
|
|
+ GLOBAL_change_size *= 2;
|
|
+ }
|
|
+ struct change *this_change = GLOBAL_change_buffer + cc;
|
|
+ this_change->address = (uint64_t)addr;
|
|
+ this_change->data = data;
|
|
+ this_change->changelist_number = GLOBAL_logstate->changelist_number;
|
|
+ this_change->flags = IS_VALID | flags;
|
|
+ return this_change;
|
|
+}
|
|
+
|
|
+void add_pending_change(target_ulong addr, uint64_t data, uint32_t flags) {
|
|
+ if (addr < PENDING_CHANGES_MAX_ADDR) {
|
|
+ GLOBAL_pending_changes[addr/4].address = (uint64_t)addr;
|
|
+ GLOBAL_pending_changes[addr/4].data = data;
|
|
+ GLOBAL_pending_changes[addr/4].flags = IS_VALID | flags;
|
|
+ }
|
|
+}
|
|
+
|
|
+void commit_pending_changes(void) {
|
|
+ int i;
|
|
+ for (i = 0; i < PENDING_CHANGES_MAX_ADDR/4; i++) {
|
|
+ struct change *c = &GLOBAL_pending_changes[i];
|
|
+ if (c->flags & IS_VALID) add_change(c->address, c->data, c->flags);
|
|
+ }
|
|
+ memset(GLOBAL_pending_changes, 0, (PENDING_CHANGES_MAX_ADDR/4) * sizeof(struct change));
|
|
+}
|
|
+
|
|
+struct change *track_syscall_begin(void *env, target_ulong sysnr);
|
|
+struct change *track_syscall_begin(void *env, target_ulong sysnr) {
|
|
+ int i;
|
|
+ QIRA_DEBUG("syscall: %d\n", sysnr);
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ for (i = 0; i < 0x20; i+=4) {
|
|
+ add_change(i, *(target_ulong*)(env+i), IS_WRITE | (sizeof(target_ulong)*8));
|
|
+ }
|
|
+ }
|
|
+ return add_change(sysnr, 0, IS_SYSCALL);
|
|
+}
|
|
+
|
|
+
|
|
+// all loads and store happen in libraries...
|
|
+void track_load(target_ulong addr, uint64_t data, int size) {
|
|
+ QIRA_DEBUG("load: 0x%x:%d\n", addr, size);
|
|
+ add_change(addr, data, IS_MEM | size);
|
|
+}
|
|
+
|
|
+void track_store(target_ulong addr, uint64_t data, int size) {
|
|
+ QIRA_DEBUG("store: 0x%x:%d = 0x%lX\n", addr, size, data);
|
|
+ add_change(addr, data, IS_MEM | IS_WRITE | size);
|
|
+}
|
|
+
|
|
+void track_read(target_ulong base, target_ulong offset, target_ulong data, int size) {
|
|
+ QIRA_DEBUG("read: %x+%x:%d = %x\n", base, offset, size, data);
|
|
+ if ((int)offset < 0) return;
|
|
+ if (GLOBAL_logstate->is_filtered == 0) add_change(offset, data, size);
|
|
+}
|
|
+
|
|
+void track_write(target_ulong base, target_ulong offset, target_ulong data, int size) {
|
|
+ QIRA_DEBUG("write: %x+%x:%d = %x\n", base, offset, size, data);
|
|
+ if ((int)offset < 0) return;
|
|
+ if (GLOBAL_logstate->is_filtered == 0) add_change(offset, data, IS_WRITE | size);
|
|
+ else add_pending_change(offset, data, IS_WRITE | size);
|
|
+ //else add_change(offset, data, IS_WRITE | size);
|
|
+}
|
|
+
|
|
+#ifdef QEMU_USER
|
|
+
|
|
+void track_kernel_read(void *host_addr, target_ulong guest_addr, long len) {
|
|
+ if (unlikely(GLOBAL_QIRA_did_init == 0)) return;
|
|
+
|
|
+ // this is generating tons of changes, and maybe not too useful
|
|
+ /*QIRA_DEBUG("kernel_read: %p %X %ld\n", host_addr, guest_addr, len);
|
|
+ long i = 0;
|
|
+ //for (; i < len; i+=4) add_change(guest_addr+i, ((unsigned int*)host_addr)[i], IS_MEM | 32);
|
|
+ for (; i < len; i+=1) add_change(guest_addr+i, ((unsigned char*)host_addr)[i], IS_MEM | 8);*/
|
|
+}
|
|
+
|
|
+void track_kernel_write(void *host_addr, target_ulong guest_addr, long len) {
|
|
+ if (unlikely(GLOBAL_QIRA_did_init == 0)) return;
|
|
+ // clamp at 0x40, badness
|
|
+ //if (len > 0x40) len = 0x40;
|
|
+
|
|
+ QIRA_DEBUG("kernel_write: %p %X %ld\n", host_addr, guest_addr, len);
|
|
+ long i = 0;
|
|
+ //for (; i < len; i+=4) add_change(guest_addr+i, ((unsigned int*)host_addr)[i], IS_MEM | IS_WRITE | 32);
|
|
+ for (; i < len; i+=1) add_change(guest_addr+i, ((unsigned char*)host_addr)[i], IS_MEM | IS_WRITE | 8);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+// careful, this does it twice, MMIO?
|
|
+#define R(x,y,z) (track_load(x,(uint64_t)y,z),y)
|
|
+#define W(x,y,z) (track_store(x,(uint64_t)y,z),x)
|
|
+
|
|
+#else
|
|
+
|
|
+#define R(x,y,z) y
|
|
+#define W(x,y,z) x
|
|
+#define track_read(x,y,z) ;
|
|
+#define track_write(w,x,y,z) ;
|
|
+
|
|
+#endif
|
|
+
|
|
+
|
|
#ifdef CONFIG_SOFTMMU
|
|
# define qemu_ld_ub \
|
|
helper_ret_ldub_mmu(env, taddr, oi, (uintptr_t)tb_ptr)
|
|
@@ -443,25 +707,297 @@
|
|
# define qemu_st_beq(X) \
|
|
helper_be_stq_mmu(env, taddr, X, oi, (uintptr_t)tb_ptr)
|
|
#else
|
|
-# define qemu_ld_ub ldub_p(g2h(taddr))
|
|
-# define qemu_ld_leuw lduw_le_p(g2h(taddr))
|
|
-# define qemu_ld_leul (uint32_t)ldl_le_p(g2h(taddr))
|
|
-# define qemu_ld_leq ldq_le_p(g2h(taddr))
|
|
-# define qemu_ld_beuw lduw_be_p(g2h(taddr))
|
|
-# define qemu_ld_beul (uint32_t)ldl_be_p(g2h(taddr))
|
|
-# define qemu_ld_beq ldq_be_p(g2h(taddr))
|
|
-# define qemu_st_b(X) stb_p(g2h(taddr), X)
|
|
-# define qemu_st_lew(X) stw_le_p(g2h(taddr), X)
|
|
-# define qemu_st_lel(X) stl_le_p(g2h(taddr), X)
|
|
-# define qemu_st_leq(X) stq_le_p(g2h(taddr), X)
|
|
-# define qemu_st_bew(X) stw_be_p(g2h(taddr), X)
|
|
-# define qemu_st_bel(X) stl_be_p(g2h(taddr), X)
|
|
-# define qemu_st_beq(X) stq_be_p(g2h(taddr), X)
|
|
+# define qemu_ld_ub R(taddr, ldub_p(g2h(taddr)), 8)
|
|
+# define qemu_ld_leuw R(taddr, lduw_le_p(g2h(taddr)), 16)
|
|
+# define qemu_ld_leul R(taddr, (uint32_t)ldl_le_p(g2h(taddr)), 32)
|
|
+# define qemu_ld_leq R(taddr, ldq_le_p(g2h(taddr)), 64)
|
|
+# define qemu_ld_beuw R(taddr, lduw_be_p(g2h(taddr)), 16)
|
|
+# define qemu_ld_beul R(taddr, (uint32_t)ldl_be_p(g2h(taddr)), 32)
|
|
+# define qemu_ld_beq R(taddr, ldq_be_p(g2h(taddr)), 64)
|
|
+# define qemu_st_b(X) stb_p(g2h(W(taddr,X,8)), X)
|
|
+# define qemu_st_lew(X) stw_le_p(g2h(W(taddr,X,16)), X)
|
|
+# define qemu_st_lel(X) stl_le_p(g2h(W(taddr,X,32)), X)
|
|
+# define qemu_st_leq(X) stq_le_p(g2h(W(taddr,X,64)), X)
|
|
+# define qemu_st_bew(X) stw_be_p(g2h(W(taddr,X,16)), X)
|
|
+# define qemu_st_bel(X) stl_be_p(g2h(W(taddr,X,32)), X)
|
|
+# define qemu_st_beq(X) stq_be_p(g2h(W(taddr,X,64)), X)
|
|
+#endif
|
|
+
|
|
+// poorly written, and it fills in holes
|
|
+int get_next_id(void);
|
|
+int get_next_id(void) {
|
|
+ char fn[PATH_MAX];
|
|
+ int this_id = 0;
|
|
+ struct stat junk;
|
|
+ while (1) {
|
|
+ sprintf(fn, "/tmp/qira_logs/%d", this_id);
|
|
+ if (stat(fn, &junk) == -1) break;
|
|
+ this_id++;
|
|
+ }
|
|
+ return this_id;
|
|
+}
|
|
+
|
|
+int run_QIRA_log_from_fd(CPUArchState *env, int qira_log_fd, uint32_t to_change);
|
|
+int run_QIRA_log_from_fd(CPUArchState *env, int qira_log_fd, uint32_t to_change) {
|
|
+ struct change pchange;
|
|
+ // skip the first change
|
|
+ lseek(qira_log_fd, sizeof(pchange), SEEK_SET);
|
|
+ int ret = 0;
|
|
+ while(1) {
|
|
+ if (read(qira_log_fd, &pchange, sizeof(pchange)) != sizeof(pchange)) { break; }
|
|
+ uint32_t flags = pchange.flags;
|
|
+ if (!(flags & IS_VALID)) break;
|
|
+ if (pchange.changelist_number >= to_change) break;
|
|
+ QIRA_DEBUG("running old change %lX %d\n", pchange.address, pchange.changelist_number);
|
|
+
|
|
+#ifdef QEMU_USER
|
|
+#ifdef R_EAX
|
|
+ if (flags & IS_SYSCALL) {
|
|
+ // replay all the syscalls?
|
|
+ // skip reads
|
|
+ if (pchange.address == FAKE_SYSCALL_LOADSEG) {
|
|
+ //printf("LOAD_SEG!\n");
|
|
+ helper_load_seg(env, pchange.data >> 32, pchange.data & 0xFFFFFFFF);
|
|
+ } else if (pchange.address != 3) {
|
|
+ env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], 0, 0);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ // wrong for system, we need this
|
|
+ if (flags & IS_WRITE) {
|
|
+ void *base;
|
|
+ if (flags & IS_MEM) { base = g2h(pchange.address); }
|
|
+ else { base = ((void *)env) + pchange.address; }
|
|
+ memcpy(base, &pchange.data, (flags&SIZE_MASK) >> 3);
|
|
+ }
|
|
#endif
|
|
+ ret++;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void run_QIRA_mods(CPUArchState *env, int this_id);
|
|
+void run_QIRA_mods(CPUArchState *env, int this_id) {
|
|
+ char fn[PATH_MAX];
|
|
+ sprintf(fn, "/tmp/qira_logs/%d_mods", this_id);
|
|
+ int qira_log_fd = open(fn, O_RDONLY);
|
|
+ if (qira_log_fd == -1) return;
|
|
+
|
|
+ // seek past the header
|
|
+ lseek(qira_log_fd, sizeof(struct logstate), SEEK_SET);
|
|
+
|
|
+ // run all the changes in this file
|
|
+ int count = run_QIRA_log_from_fd(env, qira_log_fd, 0xFFFFFFFF);
|
|
+
|
|
+ close(qira_log_fd);
|
|
+
|
|
+ printf("+++ REPLAY %d MODS DONE with entry count %d\n", this_id, count);
|
|
+}
|
|
+
|
|
+void run_QIRA_log(CPUArchState *env, int this_id, int to_change);
|
|
+void run_QIRA_log(CPUArchState *env, int this_id, int to_change) {
|
|
+ char fn[PATH_MAX];
|
|
+ sprintf(fn, "/tmp/qira_logs/%d", this_id);
|
|
+
|
|
+ int qira_log_fd, qira_log_fd_ = open(fn, O_RDONLY);
|
|
+ // qira_log_fd_ must be 30, if it isn't, i'm not sure what happened
|
|
+ dup2(qira_log_fd_, 100+this_id);
|
|
+ close(qira_log_fd_);
|
|
+ qira_log_fd = 100+this_id;
|
|
+
|
|
+ struct logstate plogstate;
|
|
+ if (read(qira_log_fd, &plogstate, sizeof(plogstate)) != sizeof(plogstate)) {
|
|
+ printf("HEADER READ ISSUE!\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ printf("+++ REPLAY %d START on fd %d(%d)\n", this_id, qira_log_fd, qira_log_fd_);
|
|
+
|
|
+ // check if this one has a parent and recurse here
|
|
+ // BUG: FD ISSUE!
|
|
+ QIRA_DEBUG("parent is %d with first_change %d\n", plogstate.parent_id, plogstate.first_changelist_number);
|
|
+ if (plogstate.parent_id != -1) {
|
|
+ run_QIRA_log(env, plogstate.parent_id, plogstate.first_changelist_number);
|
|
+ }
|
|
+
|
|
+ int count = run_QIRA_log_from_fd(env, qira_log_fd, to_change);
|
|
+
|
|
+ close(qira_log_fd);
|
|
+
|
|
+ printf("+++ REPLAY %d DONE to %d with entry count %d\n", this_id, to_change, count);
|
|
+}
|
|
+
|
|
+bool is_filtered_address(target_ulong pc, bool ignore_gatetrace);
|
|
+bool is_filtered_address(target_ulong pc, bool ignore_gatetrace) {
|
|
+ // to remove the warning
|
|
+ uint64_t bpc = (uint64_t)pc;
|
|
+
|
|
+ // do this check before the tracelibraries one
|
|
+ if (unlikely(GLOBAL_gatetrace) && !ignore_gatetrace) {
|
|
+ if (GLOBAL_gatetrace == bpc) GLOBAL_gatetrace = 0;
|
|
+ else return true;
|
|
+ }
|
|
+
|
|
+ // TODO(geohot): FIX THIS!, filter anything that isn't the user binary and not dynamic
|
|
+ if (unlikely(GLOBAL_tracelibraries)) {
|
|
+ return false;
|
|
+ } else {
|
|
+ return is_library_addr(pc);
|
|
+ // return ((bpc > 0x80000000 && bpc < 0xf6800000) || bpc >= 0x100000000);
|
|
+ }
|
|
+}
|
|
+
|
|
+void real_target_disas(FILE *out, CPUState *env, target_ulong code, target_ulong size, int flags);
|
|
+void target_disas(FILE *out, CPUState *env, target_ulong code, target_ulong size, int flags) {
|
|
+ OPEN_GLOBAL_ASM_FILE
|
|
+
|
|
+ if (is_filtered_address(code, true)) return;
|
|
+
|
|
+ flock(fileno(GLOBAL_asm_file), LOCK_EX);
|
|
+ real_target_disas(GLOBAL_asm_file, env, code, size, flags);
|
|
+ flock(fileno(GLOBAL_asm_file), LOCK_UN);
|
|
+
|
|
+ fflush(GLOBAL_asm_file);
|
|
+}
|
|
+
|
|
+
|
|
+int GLOBAL_last_was_syscall = 0;
|
|
+uint32_t GLOBAL_last_fork_change = -1;
|
|
+target_long last_pc = 0;
|
|
+
|
|
+void write_out_base(CPUArchState *env, int id);
|
|
+
|
|
+void write_out_base(CPUArchState *env, int id) {
|
|
+#ifdef QEMU_USER
|
|
+ CPUState *cpu = ENV_GET_CPU(env);
|
|
+ TaskState *ts = (TaskState *)cpu->opaque;
|
|
+
|
|
+ char fn[PATH_MAX];
|
|
+ char envfn[PATH_MAX];
|
|
+
|
|
+ sprintf(envfn, "/tmp/qira_logs/%d_env", id);
|
|
+ FILE *envf = fopen(envfn, "wb");
|
|
+
|
|
+ // could still be wrong, clipping on env vars
|
|
+ target_ulong ss = ts->info->start_stack;
|
|
+ target_ulong se = (ts->info->arg_end + (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK;
|
|
+
|
|
+ /*while (h2g_valid(g2h(se))) {
|
|
+ printf("%x\n", g2h(se));
|
|
+ fflush(stdout);
|
|
+ se += TARGET_PAGE_SIZE;
|
|
+ }*/
|
|
+
|
|
+ //target_ulong ss = ts->info->arg_start;
|
|
+ //target_ulong se = ts->info->arg_end;
|
|
+
|
|
+ fwrite(g2h(ss), 1, se-ss, envf);
|
|
+ fclose(envf);
|
|
+
|
|
+ sprintf(fn, "/tmp/qira_logs/%d_base", id);
|
|
+ FILE *f = fopen(fn, "w");
|
|
+
|
|
+
|
|
+ // code copied from linux-user/syscall.c
|
|
+ FILE *maps = fopen("/proc/self/maps", "r");
|
|
+ char *line = NULL;
|
|
+ size_t len = 0;
|
|
+ while (getline(&line, &len, maps) != -1) {
|
|
+ int fields, dev_maj, dev_min, inode;
|
|
+ uint64_t min, max, offset;
|
|
+ char flag_r, flag_w, flag_x, flag_p;
|
|
+ char path[512] = "";
|
|
+ fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d"
|
|
+ " %512s", &min, &max, &flag_r, &flag_w, &flag_x,
|
|
+ &flag_p, &offset, &dev_maj, &dev_min, &inode, path);
|
|
+ if ((fields < 10) || (fields > 11)) { continue; }
|
|
+
|
|
+ if (h2g_valid(min) && h2g_valid(max) && strlen(path) && flag_w == '-') {
|
|
+ fprintf(f, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx " %"PRIx64" %s\n", h2g(min), h2g(max), offset, path);
|
|
+ //printf("%p - %p -- %s", h2g(min), h2g(max), line);
|
|
+ //fflush(stdout);
|
|
+ }
|
|
+
|
|
+ /*printf("%s", line);
|
|
+ fflush(stdout);*/
|
|
+ }
|
|
+ fclose(maps);
|
|
+
|
|
+ // env
|
|
+ fprintf(f, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx " %"PRIx64" %s\n", ss, se, (uint64_t)0, envfn);
|
|
+
|
|
+ fclose(f);
|
|
+#endif
|
|
+}
|
|
|
|
/* Interpret pseudo code in tb. */
|
|
uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
|
|
{
|
|
+#ifdef QIRA_TRACKING
|
|
+ CPUState *cpu = ENV_GET_CPU(env);
|
|
+ TranslationBlock *tb = cpu->current_tb;
|
|
+ //TaskState *ts = (TaskState *)cpu->opaque;
|
|
+
|
|
+ if (unlikely(GLOBAL_QIRA_did_init == 0)) {
|
|
+ // get next id
|
|
+ if (GLOBAL_id == -1) { GLOBAL_id = get_next_id(); }
|
|
+
|
|
+ // these are the base libraries we load
|
|
+ write_out_base(env, GLOBAL_id);
|
|
+
|
|
+ init_QIRA(env, GLOBAL_id);
|
|
+
|
|
+ // these three arguments (parent_id, start_clnum, id) must be passed into QIRA
|
|
+ // this now runs after init_QIRA
|
|
+ if (GLOBAL_parent_id != -1) {
|
|
+ run_QIRA_log(env, GLOBAL_parent_id, GLOBAL_start_clnum);
|
|
+ run_QIRA_mods(env, GLOBAL_id);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (unlikely(GLOBAL_logstate->this_pid != getpid())) {
|
|
+ GLOBAL_start_clnum = GLOBAL_last_fork_change + 1;
|
|
+ GLOBAL_parent_id = GLOBAL_id;
|
|
+
|
|
+ // BUG: race condition
|
|
+ GLOBAL_id = get_next_id();
|
|
+
|
|
+ // this fixes the PID
|
|
+ init_QIRA(env, GLOBAL_id);
|
|
+ }
|
|
+
|
|
+ // set this every time, it's not in shmem
|
|
+ GLOBAL_last_fork_change = GLOBAL_logstate->changelist_number;
|
|
+
|
|
+ if (GLOBAL_last_was_syscall) {
|
|
+ #ifdef R_EAX
|
|
+ add_change((void *)&env->regs[R_EAX] - (void *)env, env->regs[R_EAX], IS_WRITE | (sizeof(target_ulong)<<3));
|
|
+ #endif
|
|
+ #ifdef TARGET_ARM
|
|
+ //first register is 0 from enum
|
|
+ add_change((void *)&env->regs[0] - (void *)env, env->regs[0], IS_WRITE | (sizeof(target_ulong)<<3));
|
|
+ #endif
|
|
+ GLOBAL_last_was_syscall = 0;
|
|
+ }
|
|
+
|
|
+ if (is_filtered_address(tb->pc, false)) {
|
|
+ GLOBAL_logstate->is_filtered = 1;
|
|
+ } else {
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ commit_pending_changes();
|
|
+ GLOBAL_logstate->is_filtered = 0;
|
|
+ }
|
|
+ GLOBAL_logstate->changelist_number++;
|
|
+ add_change(tb->pc, tb->size, IS_START);
|
|
+ }
|
|
+
|
|
+
|
|
+ QIRA_DEBUG("set changelist %d at %x(%d)\n", GLOBAL_logstate->changelist_number, tb->pc, tb->size);
|
|
+#endif
|
|
+
|
|
long tcg_temps[CPU_TEMP_BUF_NLONGS];
|
|
uintptr_t sp_value = (uintptr_t)(tcg_temps + CPU_TEMP_BUF_NLONGS);
|
|
uintptr_t next_tb = 0;
|
|
@@ -472,6 +1008,7 @@
|
|
|
|
for (;;) {
|
|
TCGOpcode opc = tb_ptr[0];
|
|
+ //printf("exec : %d\n", opc);
|
|
#if !defined(NDEBUG)
|
|
uint8_t op_size = tb_ptr[1];
|
|
uint8_t *old_code_ptr = tb_ptr;
|
|
@@ -479,6 +1016,7 @@
|
|
tcg_target_ulong t0;
|
|
tcg_target_ulong t1;
|
|
tcg_target_ulong t2;
|
|
+ tcg_target_ulong a0,a1,a2,a3;
|
|
tcg_target_ulong label;
|
|
TCGCond condition;
|
|
target_ulong taddr;
|
|
@@ -501,11 +1039,56 @@
|
|
switch (opc) {
|
|
case INDEX_op_call:
|
|
t0 = tci_read_ri(&tb_ptr);
|
|
+ a0 = tci_read_reg(TCG_REG_R0);
|
|
+ a1 = tci_read_reg(TCG_REG_R1);
|
|
+ a2 = tci_read_reg(TCG_REG_R2);
|
|
+ a3 = tci_read_reg(TCG_REG_R3);
|
|
+ //printf("op_call: %X\n", t0);
|
|
+ // helper_function raise_interrupt, load_seg
|
|
+#ifdef R_EAX
|
|
+ struct change *a = NULL;
|
|
+
|
|
+ if ((void*)t0 == helper_load_seg) {
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ commit_pending_changes();
|
|
+ }
|
|
+ a = track_syscall_begin(env, FAKE_SYSCALL_LOADSEG);
|
|
+ a->data = a1<<32 | a2;
|
|
+ //printf("LOAD SEG %x %x %x %x\n", a0, a1, a2, a3);
|
|
+ } else if ((void*)t0 == helper_raise_interrupt) {
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ commit_pending_changes();
|
|
+ // syscalls always get a change?
|
|
+ /*GLOBAL_logstate->changelist_number++;
|
|
+ add_change(tb->pc, tb->size, IS_START);*/
|
|
+ }
|
|
+ a = track_syscall_begin(env, env->regs[R_EAX]);
|
|
+ GLOBAL_last_was_syscall = 1;
|
|
+ }
|
|
+#endif
|
|
+#ifdef TARGET_ARM
|
|
+ struct change *a = NULL;
|
|
+ if ((void*)t0 == helper_exception_with_syndrome) {
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ commit_pending_changes();
|
|
+ }
|
|
+ a = track_syscall_begin(env, env->regs[0]);
|
|
+ GLOBAL_last_was_syscall = 1;
|
|
+ }
|
|
+#endif
|
|
+#ifdef TARGET_MIPS
|
|
+ struct change *a = NULL;
|
|
+ if ((void*)t0 == helper_raise_exception && a1 == EXCP_SYSCALL) {
|
|
+ if (GLOBAL_logstate->is_filtered == 1) {
|
|
+ commit_pending_changes();
|
|
+ }
|
|
+ a = track_syscall_begin(env, env->active_tc.gpr[2]);
|
|
+ GLOBAL_last_was_syscall = 1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
#if TCG_TARGET_REG_BITS == 32
|
|
- tmp64 = ((helper_function)t0)(tci_read_reg(TCG_REG_R0),
|
|
- tci_read_reg(TCG_REG_R1),
|
|
- tci_read_reg(TCG_REG_R2),
|
|
- tci_read_reg(TCG_REG_R3),
|
|
+ tmp64 = ((helper_function)t0)(a0,a1,a2,a3,
|
|
tci_read_reg(TCG_REG_R5),
|
|
tci_read_reg(TCG_REG_R6),
|
|
tci_read_reg(TCG_REG_R7),
|
|
@@ -515,10 +1098,7 @@
|
|
tci_write_reg(TCG_REG_R0, tmp64);
|
|
tci_write_reg(TCG_REG_R1, tmp64 >> 32);
|
|
#else
|
|
- tmp64 = ((helper_function)t0)(tci_read_reg(TCG_REG_R0),
|
|
- tci_read_reg(TCG_REG_R1),
|
|
- tci_read_reg(TCG_REG_R2),
|
|
- tci_read_reg(TCG_REG_R3),
|
|
+ tmp64 = ((helper_function)t0)(a0,a1,a2,a3,
|
|
tci_read_reg(TCG_REG_R5));
|
|
tci_write_reg(TCG_REG_R0, tmp64);
|
|
#endif
|
|
@@ -569,6 +1149,7 @@
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(uint8_t *)(t1 + t2), 32);
|
|
tci_write_reg8(t0, *(uint8_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_ld8s_i32:
|
|
@@ -582,18 +1163,21 @@
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(uint32_t *)(t1 + t2), 32);
|
|
tci_write_reg32(t0, *(uint32_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_st8_i32:
|
|
t0 = tci_read_r8(&tb_ptr);
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_write(t1, t2, t0, 32);
|
|
*(uint8_t *)(t1 + t2) = t0;
|
|
break;
|
|
case INDEX_op_st16_i32:
|
|
t0 = tci_read_r16(&tb_ptr);
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_write(t1, t2, t0, 32);
|
|
*(uint16_t *)(t1 + t2) = t0;
|
|
break;
|
|
case INDEX_op_st_i32:
|
|
@@ -601,6 +1185,7 @@
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
assert(t1 != sp_value || (int32_t)t2 < 0);
|
|
+ track_write(t1, t2, t0, 32);
|
|
*(uint32_t *)(t1 + t2) = t0;
|
|
break;
|
|
|
|
@@ -838,6 +1423,7 @@
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(uint8_t *)(t1 + t2), 8);
|
|
tci_write_reg8(t0, *(uint8_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_ld8s_i64:
|
|
@@ -849,36 +1435,42 @@
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(uint32_t *)(t1 + t2), 32);
|
|
tci_write_reg32(t0, *(uint32_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_ld32s_i64:
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(int32_t *)(t1 + t2), 32);
|
|
tci_write_reg32s(t0, *(int32_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_ld_i64:
|
|
t0 = *tb_ptr++;
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_read(t1, t2, *(uint64_t *)(t1 + t2), 64);
|
|
tci_write_reg64(t0, *(uint64_t *)(t1 + t2));
|
|
break;
|
|
case INDEX_op_st8_i64:
|
|
t0 = tci_read_r8(&tb_ptr);
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_write(t1, t2, t0, 64);
|
|
*(uint8_t *)(t1 + t2) = t0;
|
|
break;
|
|
case INDEX_op_st16_i64:
|
|
t0 = tci_read_r16(&tb_ptr);
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_write(t1, t2, t0, 64);
|
|
*(uint16_t *)(t1 + t2) = t0;
|
|
break;
|
|
case INDEX_op_st32_i64:
|
|
t0 = tci_read_r32(&tb_ptr);
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
+ track_write(t1, t2, t0, 64);
|
|
*(uint32_t *)(t1 + t2) = t0;
|
|
break;
|
|
case INDEX_op_st_i64:
|
|
@@ -886,6 +1478,7 @@
|
|
t1 = tci_read_r(&tb_ptr);
|
|
t2 = tci_read_s32(&tb_ptr);
|
|
assert(t1 != sp_value || (int32_t)t2 < 0);
|
|
+ track_write(t1, t2, t0, 64);
|
|
*(uint64_t *)(t1 + t2) = t0;
|
|
break;
|
|
|
|
@@ -1088,6 +1681,7 @@
|
|
case INDEX_op_goto_tb:
|
|
t0 = tci_read_i32(&tb_ptr);
|
|
assert(tb_ptr == old_code_ptr + op_size);
|
|
+ //printf("goto_tb: %lx\n", t0);
|
|
tb_ptr += (int32_t)t0;
|
|
continue;
|
|
case INDEX_op_qemu_ld_i32:
|
|
@@ -1237,5 +1831,14 @@
|
|
assert(tb_ptr == old_code_ptr + op_size);
|
|
}
|
|
exit:
|
|
+#ifdef QIRA_TRACKING
|
|
+ // this fixes the jump instruction merging bug
|
|
+ // with the last_pc hack for ARM, might break some x86 reps
|
|
+ if (next_tb != 0 && last_pc != tb->pc) {
|
|
+ next_tb = 0;
|
|
+ }
|
|
+#endif
|
|
+ last_pc = tb->pc;
|
|
return next_tb;
|
|
}
|
|
+
|