From cc726ee1c62da18fc2bb96a393115b5512d4786a Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 00:47:43 -0700 Subject: [PATCH 1/7] Original Qira QEMU patch ontop of v3.1.0 I attempted to be as literal as possible, but this was not actually a cherry-pick. There were so many re-arranged files from v2.5.1 where the patch was last applied, that the merge conflicts were just nonsense. Additional fixes to get QEMU to build are in follow commits. --- disas.c | 9 +- include/disas/disas.h | 8 +- include/librarymap.h | 10 + linux-user/elfload.c | 10 + linux-user/main.c | 30 +- linux-user/qemu.h | 25 +- linux-user/strace.c | 26 +- linux-user/strace.list | 4 +- linux-user/syscall.c | 19 ++ tcg/tci.c | 674 +++++++++++++++++++++++++++++++++++++++-- 10 files changed, 780 insertions(+), 35 deletions(-) create mode 100644 include/librarymap.h diff --git a/disas.c b/disas.c index 5325b7e6be67..6f283fe2bb8d 100644 --- a/disas.c +++ b/disas.c @@ -421,8 +421,8 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) #endif /* CONFIG_CAPSTONE */ /* Disassemble this for me please... (debugging). */ -void target_disas(FILE *out, CPUState *cpu, target_ulong code, - target_ulong size) +void real_target_disas(FILE *out, CPUState *cpu, target_ulong code, + target_ulong size, int flags) { CPUClass *cc = CPU_GET_CLASS(cpu); target_ulong pc; @@ -440,6 +440,7 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code, s.info.cap_mode = 0; s.info.cap_insn_unit = 4; s.info.cap_insn_split = 4; + s.info.disassembler_options = (char *)"intel"; #ifdef TARGET_WORDS_BIGENDIAN s.info.endian = BFD_ENDIAN_BIG; @@ -460,6 +461,10 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code, } 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); fprintf(out, "\n"); diff --git a/include/disas/disas.h b/include/disas/disas.h index 4d48c13c65fa..74d2f38267d9 100644 --- a/include/disas/disas.h +++ b/include/disas/disas.h @@ -8,8 +8,14 @@ /* Disassemble this for me please... (debugging). */ void disas(FILE *out, void *code, unsigned long size); + +// this is hooked in tci.c for qira void target_disas(FILE *out, CPUState *cpu, target_ulong code, - target_ulong size); + target_ulong size, int flags); + +// this is the old function in disas.c +void real_target_disas(FILE *out, CPUState *cpu, target_ulong code, + target_ulong size, int flags); void monitor_disas(Monitor *mon, CPUState *cpu, target_ulong pc, int nb_insn, int is_physical); diff --git a/include/librarymap.h b/include/librarymap.h new file mode 100644 index 000000000000..9ca8ae522fad --- /dev/null +++ b/include/librarymap.h @@ -0,0 +1,10 @@ +struct librarymap { + struct librarymap *next; + abi_ulong begin; + abi_ulong end; + const char *name; +}; + +void init_librarymap(void); +void add_to_librarymap(const char *name, abi_ulong begin, abi_ulong end); +bool is_library_addr(abi_ulong addr); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5bccd2e24318..8cb69e4f8d20 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -7,6 +7,7 @@ #include "qemu.h" #include "disas/disas.h" #include "qemu/path.h" +#include "librarymap.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -2183,6 +2184,9 @@ static void probe_guest_base(const char *image_name, } +extern struct library *GLOBAL_librarymap; +extern const char *filename; + /* Load an ELF image into the address space. IMAGE_NAME is the filename of the image, to use in error messages. @@ -2261,6 +2265,12 @@ static void load_elf_image(const char *image_name, int image_fd, 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 --git a/linux-user/main.c b/linux-user/main.c index 923cbb753acc..0d030dfca7df 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -41,7 +41,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; @@ -385,6 +385,28 @@ static void handle_arg_trace(const char *arg) trace_file = trace_opt_parse(arg); } +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); +} + struct qemu_argument { const char *argv; const char *env; @@ -430,6 +452,12 @@ static const struct qemu_argument arg_table[] = { "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 --git a/linux-user/qemu.h b/linux-user/qemu.h index dd5771ce0cbc..44d92464531a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -18,6 +18,9 @@ #include "exec/gdbstub.h" #include "qemu/queue.h" +#define QIRA_TRACKING + + /* This is the size of the host kernel's sigset_t, needed where we make * direct system calls that take a sigset_t pointer and a size. */ @@ -596,10 +599,16 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); 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 @@ -610,11 +619,18 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy 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 @@ -623,6 +639,11 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy 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 --git a/linux-user/strace.c b/linux-user/strace.c index d1d14945f9dc..2318420d3106 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -11,6 +11,18 @@ #include #include "qemu.h" +#undef TARGET_ABI_FMT_lx +#ifdef TARGET_ABI32 +typedef unsigned int abi_ulonglong; +#define TARGET_ABI_FMT_lx "%x" +#else +typedef unsigned long long abi_ulonglong; +#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 { @@ -627,7 +639,7 @@ print_semctl(const struct syscallname *name, { gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2); print_ipc_cmd(arg3); - gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); + gemu_log(",0x" TARGET_ABI_FMT_lx ")", (abi_ulonglong)arg4); } #endif @@ -697,7 +709,7 @@ print_syscall_ret_addr(const struct syscallname *name, abi_long ret) if (errstr) { gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr); } else { - gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); + gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", (abi_ulonglong)ret); } } @@ -1143,10 +1155,11 @@ print_raw_param(const char *fmt, abi_long param, int last) static void print_pointer(abi_long p, int last) { - if (p == 0) + if (p == 0) { gemu_log("NULL%s", get_comma(last)); - else - gemu_log("0x" TARGET_ABI_FMT_lx "%s", p, get_comma(last)); + } else { + gemu_log("0x" TARGET_ABI_FMT_lx "%s", (abi_ulonglong)p, get_comma(last)); + } } /* @@ -2609,6 +2622,8 @@ static const struct syscallname scnames[] = { static int nsyscalls = ARRAY_SIZE(scnames); +uint32_t get_current_clnum(void); + /* * The public interface to this module. */ @@ -2620,6 +2635,7 @@ print_syscall(int num, 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= 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 */ + } + trace_guest_user_syscall_ret(cpu, num, ret); return ret; } diff --git a/tcg/tci.c b/tcg/tci.c index 33edca190386..9d944114c308 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -31,6 +31,36 @@ #include "tcg/tcg.h" /* MAX_OPC_PARAM_IARGS */ #include "exec/cpu_ldst.h" #include "tcg-op.h" +#include "disas/disas.h" +#include "librarymap.h" + +struct librarymap *GLOBAL_librarymap; + +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; +} /* Marker for missing code. */ #define TODO() \ @@ -422,6 +452,269 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition) 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 +#include +#include + +#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) @@ -452,25 +745,297 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition) # 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 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 + tcg_target_ulong regs[TCG_TARGET_NB_REGS]; long tcg_temps[CPU_TEMP_BUF_NLONGS]; uintptr_t sp_value = (uintptr_t)(tcg_temps + CPU_TEMP_BUF_NLONGS); @@ -482,6 +1047,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) for (;;) { TCGOpcode opc = tb_ptr[0]; + //printf("exec : %d\n", opc); #if defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG) uint8_t op_size = tb_ptr[1]; uint8_t *old_code_ptr = tb_ptr; @@ -489,6 +1055,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) 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; @@ -511,11 +1078,54 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) switch (opc) { case INDEX_op_call: t0 = tci_read_ri(regs, &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 + if ((void*)t0 == helper_exception_with_syndrome) { + if (GLOBAL_logstate->is_filtered == 1) { + commit_pending_changes(); + } + track_syscall_begin(env, env->regs[0]); + GLOBAL_last_was_syscall = 1; + } +#endif +#ifdef TARGET_MIPS + if ((void*)t0 == helper_raise_exception && a1 == EXCP_SYSCALL) { + if (GLOBAL_logstate->is_filtered == 1) { + commit_pending_changes(); + } + 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(regs, TCG_REG_R0), - tci_read_reg(regs, TCG_REG_R1), - tci_read_reg(regs, TCG_REG_R2), - tci_read_reg(regs, TCG_REG_R3), + tmp64 = ((helper_function)t0)(a0,a1,a2,a3, tci_read_reg(regs, TCG_REG_R5), tci_read_reg(regs, TCG_REG_R6), tci_read_reg(regs, TCG_REG_R7), @@ -527,10 +1137,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) tci_write_reg(regs, TCG_REG_R0, tmp64); tci_write_reg(regs, TCG_REG_R1, tmp64 >> 32); #else - tmp64 = ((helper_function)t0)(tci_read_reg(regs, TCG_REG_R0), - tci_read_reg(regs, TCG_REG_R1), - tci_read_reg(regs, TCG_REG_R2), - tci_read_reg(regs, TCG_REG_R3), + tmp64 = ((helper_function)t0)(a0,a1,a2,a3, tci_read_reg(regs, TCG_REG_R5), tci_read_reg(regs, TCG_REG_R6)); tci_write_reg(regs, TCG_REG_R0, tmp64); @@ -582,6 +1189,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(uint8_t *)(t1 + t2), 32); tci_write_reg8(regs, t0, *(uint8_t *)(t1 + t2)); break; case INDEX_op_ld8s_i32: @@ -595,18 +1203,21 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(uint32_t *)(t1 + t2), 32); tci_write_reg32(regs, t0, *(uint32_t *)(t1 + t2)); break; case INDEX_op_st8_i32: t0 = tci_read_r8(regs, &tb_ptr); t1 = tci_read_r(regs, &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(regs, &tb_ptr); t1 = tci_read_r(regs, &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: @@ -614,6 +1225,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); tci_assert(t1 != sp_value || (int32_t)t2 < 0); + track_write(t1, t2, t0, 32); *(uint32_t *)(t1 + t2) = t0; break; @@ -851,6 +1463,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(uint8_t *)(t1 + t2), 8); tci_write_reg8(regs, t0, *(uint8_t *)(t1 + t2)); break; case INDEX_op_ld8s_i64: @@ -862,36 +1475,42 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(uint32_t *)(t1 + t2), 32); tci_write_reg32(regs, t0, *(uint32_t *)(t1 + t2)); break; case INDEX_op_ld32s_i64: t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(int32_t *)(t1 + t2), 32); tci_write_reg32s(regs, t0, *(int32_t *)(t1 + t2)); break; case INDEX_op_ld_i64: t0 = *tb_ptr++; t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); + track_read(t1, t2, *(uint64_t *)(t1 + t2), 64); tci_write_reg64(regs, t0, *(uint64_t *)(t1 + t2)); break; case INDEX_op_st8_i64: t0 = tci_read_r8(regs, &tb_ptr); t1 = tci_read_r(regs, &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(regs, &tb_ptr); t1 = tci_read_r(regs, &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(regs, &tb_ptr); t1 = tci_read_r(regs, &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: @@ -899,6 +1518,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t1 = tci_read_r(regs, &tb_ptr); t2 = tci_read_s32(&tb_ptr); tci_assert(t1 != sp_value || (int32_t)t2 < 0); + track_write(t1, t2, t0, 64); *(uint64_t *)(t1 + t2) = t0; break; @@ -1103,6 +1723,7 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) t0 = atomic_read((int32_t *)tb_ptr); tb_ptr += sizeof(int32_t); tci_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: @@ -1256,5 +1877,14 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) tci_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 ret; } + From 524e2dbe23d3927c2f8cbe2362a223d2b29cde58 Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:32:23 -0700 Subject: [PATCH 2/7] Fix Capstone header include I'm really not sure about this one. I can't see how QEMU would build for anyone without --disable-capstone, without this change. Surely this must be a misconfiguration of my own system? However, the Capstone documentation for their C API clearly shows to use \#include here: http://www.capstone-engine.org/lang_c.html --- include/disas/capstone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index 84e214956d00..2eb6be222bee 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -3,7 +3,7 @@ #ifdef CONFIG_CAPSTONE -#include +#include #else From 4962042a6e841003278ddc76b41e88629ba2137b Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:35:20 -0700 Subject: [PATCH 3/7] Skip check for open syscall on systems without it --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 65269cf57ed7..8187409bd73b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11528,8 +11528,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (fd >= 30){ add_to_librarymap("unknown", mapaddr, mapaddr+size); } +#ifdef TARGET_NR_open }else if (num == TARGET_NR_open){ /* here we could store the fd->libname mapping */ +#endif }else if (num == TARGET_NR_close){ /* here we could clear the fd->libname mapping */ } From 41f7ac3c0fe8c742594f6caada7a016f2a5bfd23 Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:37:42 -0700 Subject: [PATCH 4/7] target_disas no longer takes flags argument --- disas.c | 6 +----- include/disas/disas.h | 4 ++-- tcg/tci.c | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/disas.c b/disas.c index 6f283fe2bb8d..740519425ea2 100644 --- a/disas.c +++ b/disas.c @@ -422,7 +422,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count) /* Disassemble this for me please... (debugging). */ void real_target_disas(FILE *out, CPUState *cpu, target_ulong code, - target_ulong size, int flags) + target_ulong size) { CPUClass *cc = CPU_GET_CLASS(cpu); target_ulong pc; @@ -461,10 +461,6 @@ void real_target_disas(FILE *out, CPUState *cpu, target_ulong code, } 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); fprintf(out, "\n"); diff --git a/include/disas/disas.h b/include/disas/disas.h index 74d2f38267d9..80bc637fc0a5 100644 --- a/include/disas/disas.h +++ b/include/disas/disas.h @@ -11,11 +11,11 @@ void disas(FILE *out, void *code, unsigned long size); // this is hooked in tci.c for qira void target_disas(FILE *out, CPUState *cpu, target_ulong code, - target_ulong size, int flags); + target_ulong size); // this is the old function in disas.c void real_target_disas(FILE *out, CPUState *cpu, target_ulong code, - target_ulong size, int flags); + target_ulong size); void monitor_disas(Monitor *mon, CPUState *cpu, target_ulong pc, int nb_insn, int is_physical); diff --git a/tcg/tci.c b/tcg/tci.c index 9d944114c308..73ae335059f9 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -886,13 +886,13 @@ bool is_filtered_address(target_ulong pc, bool ignore_gatetrace) { } } -void 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) { 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); + real_target_disas(GLOBAL_asm_file, env, code, size); flock(fileno(GLOBAL_asm_file), LOCK_UN); fflush(GLOBAL_asm_file); From 5383c18805cc853d2bdeb917be1020ff308ce52f Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:38:51 -0700 Subject: [PATCH 5/7] Pass TranslationBlock to tb_exec for TCG Standard QEMU passes only the pointer to the start of the translation block's instructions, however for Qira tracking we need more details from the `TranslationBlock` structure. This updates the `tcg_qemu_tb_exec` function to take a pointer to the `TranslationBlock` to execute, to minimize the changes needed to build with the Qira patch. We should probably determine if it would be possible to move the Qira tracking code into `cpu_tb_exec` instead, which would not require modifying the signature of `tcg_qemu_tb_exec` (although it is only called from that one location). --- accel/tcg/cpu-exec.c | 3 +-- tcg/tcg.h | 6 +++--- tcg/tci.c | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 870027d43596..5527e2be2a59 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -142,7 +142,6 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) uintptr_t ret; TranslationBlock *last_tb; int tb_exit; - uint8_t *tb_ptr = itb->tc.ptr; qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc, "Trace %d: %p [" @@ -168,7 +167,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) #endif /* DEBUG_DISAS */ cpu->can_do_io = !use_icount; - ret = tcg_qemu_tb_exec(env, tb_ptr); + ret = tcg_qemu_tb_exec(env, itb); cpu->can_do_io = 1; last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK); tb_exit = ret & TB_EXIT_MASK; diff --git a/tcg/tcg.h b/tcg/tcg.h index f4efbaa6804c..929bee571909 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -1260,10 +1260,10 @@ static inline unsigned get_mmuidx(TCGMemOpIdx oi) #define TB_EXIT_REQUESTED 3 #ifdef HAVE_TCG_QEMU_TB_EXEC -uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr); +uintptr_t tcg_qemu_tb_exec(CPUArchState *env, TranslationBlock *tb); #else -# define tcg_qemu_tb_exec(env, tb_ptr) \ - ((uintptr_t (*)(void *, void *))tcg_ctx->code_gen_prologue)(env, tb_ptr) +# define tcg_qemu_tb_exec(env, tb) \ + ((uintptr_t (*)(void *, void *))tcg_ctx->code_gen_prologue)(env, tb) #endif void tcg_register_jit(void *buf, size_t buf_size); diff --git a/tcg/tci.c b/tcg/tci.c index 73ae335059f9..e602a234a17d 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -970,11 +970,11 @@ void write_out_base(CPUArchState *env, int id) { /* Interpret pseudo code in tb. */ -uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) +uintptr_t tcg_qemu_tb_exec(CPUArchState *env, TranslationBlock *tb) { + uint8_t *tb_ptr = tb->tc.ptr; #ifdef QIRA_TRACKING - CPUState *cpu = ENV_GET_CPU(env); - TranslationBlock *tb = cpu->current_tb; + //CPUState *cpu = ENV_GET_CPU(env); //TaskState *ts = (TaskState *)cpu->opaque; if (unlikely(GLOBAL_QIRA_did_init == 0)) { From 8c3de149f12e6feb980a5f9f87126897667ce3ce Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:45:21 -0700 Subject: [PATCH 6/7] tci_read_reg requires regs argument --- tcg/tci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tcg/tci.c b/tcg/tci.c index e602a234a17d..006dcd8ffb75 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -1078,10 +1078,10 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, TranslationBlock *tb) switch (opc) { case INDEX_op_call: t0 = tci_read_ri(regs, &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); + a0 = tci_read_reg(regs, TCG_REG_R0); + a1 = tci_read_reg(regs, TCG_REG_R1); + a2 = tci_read_reg(regs, TCG_REG_R2); + a3 = tci_read_reg(regs, TCG_REG_R3); //printf("op_call: %X\n", t0); // helper_function raise_interrupt, load_seg #ifdef R_EAX From 20039e24bb4f4c9129f6c752ec76a0432d8e223c Mon Sep 17 00:00:00 2001 From: Charles Ellis Date: Mon, 25 Mar 2019 02:46:15 -0700 Subject: [PATCH 7/7] Fix Qira tracking in TCG's tb_exec The `next_tb` variable was renamed to `ret` at some point. --- tcg/tci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcg/tci.c b/tcg/tci.c index 006dcd8ffb75..bc55ae70c6e3 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -1880,8 +1880,8 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, TranslationBlock *tb) #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; + if (ret != 0 && last_pc != tb->pc) { + ret = 0; } #endif last_pc = tb->pc;