From 335d2c1342bb887ac67f1f60cff795f0c06beaca Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Mon, 21 Mar 2011 22:24:45 +0100 Subject: goldfish_trace: Hook with goldfish_pipe.h functions. Note that this is also forces tracing support during machine initialization. Measurements show that this doesn't have any significant impact on emulation performance. Change-Id: Ie32352659611531ce65ba2c95c5896e2421f509d --- hw/android_arm.c | 1 + hw/goldfish_trace.c | 98 +++++++++++++++++++++++++++++++++-------------------- hw/goldfish_trace.h | 39 +++++++++++++++++++++ 3 files changed, 102 insertions(+), 36 deletions(-) (limited to 'hw') diff --git a/hw/android_arm.c b/hw/android_arm.c index 6062981..664ae36 100644 --- a/hw/android_arm.c +++ b/hw/android_arm.c @@ -146,6 +146,7 @@ static void android_arm_init_(ram_addr_t ram_size, #ifdef CONFIG_MEMCHECK || memcheck_enabled #endif // CONFIG_MEMCHECK + || 1 /* XXX: ALWAYS AVAILABLE FOR QEMUD PIPES */ ) { trace_dev_init(); } diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c index fc338c8..ee51a8b 100644 --- a/hw/goldfish_trace.c +++ b/hw/goldfish_trace.c @@ -15,6 +15,7 @@ */ #include "qemu_file.h" #include "goldfish_trace.h" +#include "goldfish_pipe.h" #include "sysemu.h" #include "trace.h" #ifdef CONFIG_MEMCHECK @@ -22,7 +23,23 @@ #include "memcheck/memcheck_util.h" #endif // CONFIG_MEMCHECK -//#define DEBUG 1 +/* Set to 1 to debug tracing */ +#define DEBUG 0 + +#if DEBUG +# define D(...) printf(__VA_ARGS__), fflush(stdout) +#else +# define D(...) ((void)0) +#endif + +/* Set to 1 to debug PID tracking */ +#define DEBUG_PID 0 + +#if DEBUG_PID +# define DPID(...) printf(__VA_ARGS__), fflush(stdout) +#else +# define DPID(...) ((void)0) +#endif extern void cpu_loop_exit(void); @@ -38,6 +55,7 @@ static unsigned long eoff; // offset in EXE file static unsigned cmdlen; // cmdline length static unsigned pid; // PID (really thread id) static unsigned tgid; // thread group id (really process id) +static unsigned tid; // current thread id (same as pid, most of the time) static unsigned long dsaddr; // dynamic symbol address static unsigned long unmap_start; // start address to unmap @@ -53,32 +71,30 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va switch (offset >> 2) { case TRACE_DEV_REG_SWITCH: // context switch, switch to pid + DPID("QEMU.trace: context switch tid=%u\n", value); if (trace_filename != NULL) { trace_switch(value); -#ifdef DEBUG - printf("QEMU.trace: kernel, context switch %u\n", value); -#endif + D("QEMU.trace: kernel, context switch %u\n", value); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { memcheck_switch(value); } #endif // CONFIG_MEMCHECK + tid = (unsigned) value; break; case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone + DPID("QEMU.trace: tgid=%u\n", value); tgid = value; -#ifdef DEBUG if (trace_filename != NULL) { - printf("QEMU.trace: kernel, tgid %u\n", value); + D("QEMU.trace: kernel, tgid %u\n", value); } -#endif break; case TRACE_DEV_REG_FORK: // fork, fork new pid + DPID("QEMU.trace: fork (pid=%d tgid=%d value=%d)\n", pid, tgid, value); if (trace_filename != NULL) { trace_fork(tgid, value); -#ifdef DEBUG - printf("QEMU.trace: kernel, fork %u\n", value); -#endif + D("QEMU.trace: kernel, fork %u\n", value); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { @@ -87,11 +103,10 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va #endif // CONFIG_MEMCHECK break; case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread) + DPID("QEMU.trace: clone (pid=%d tgid=%d value=%d)\n", pid, tgid, value); if (trace_filename != NULL) { trace_clone(tgid, value); -#ifdef DEBUG - printf("QEMU.trace: kernel, clone %u\n", value); -#endif + D("QEMU.trace: kernel, clone %u\n", value); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { @@ -112,10 +127,8 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); if (trace_filename != NULL) { trace_init_exec(vstart, vend, eoff, exec_path); -#ifdef DEBUG - printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", - vstart, vend, eoff, exec_path); -#endif + D("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", + vstart, vend, eoff, exec_path); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { @@ -142,7 +155,7 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va memcheck_set_cmd_line(exec_arg, cmdlen); } #endif // CONFIG_MEMCHECK -#ifdef DEBUG +#if DEBUG || DEBUG_PID if (trace_filename != NULL) { int i; for (i = 0; i < cmdlen; i ++) @@ -154,20 +167,21 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va #endif break; case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code + DPID("QEMU.trace: exit tid=%u\n", value); if (trace_filename != NULL) { trace_exit(value); -#ifdef DEBUG - printf("QEMU.trace: kernel, exit %x\n", value); -#endif + D("QEMU.trace: kernel, exit %x\n", value); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { memcheck_exit(value); } #endif // CONFIG_MEMCHECK + goldfish_pipe_thread_death((int)tid); break; case TRACE_DEV_REG_NAME: // record thread name vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); + DPID("QEMU.trace: thread name=%s\n", exec_path); // Remove the trailing newline if it exists int len = strlen(exec_path); @@ -176,18 +190,15 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va } if (trace_filename != NULL) { trace_name(exec_path); -#ifdef DEBUG - printf("QEMU.trace: kernel, name %s\n", exec_path); -#endif + D("QEMU.trace: kernel, name %s\n", exec_path); } break; case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); + DPID("QEMU.trace: mmap exe=%s\n", exec_path); if (trace_filename != NULL) { trace_mmap(vstart, vend, eoff, exec_path); -#ifdef DEBUG - printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path); -#endif + D("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path); } #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { @@ -203,6 +214,7 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va break; case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered pid = value; + DPID("QEMU.trace: pid=%d\n", value); #ifdef CONFIG_MEMCHECK if (memcheck_enabled) { memcheck_init_pid(value); @@ -211,11 +223,10 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va break; case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); + DPID("QEMU.trace: tgid=%d pid=%d name=%s\n", tgid, pid, exec_path); if (trace_filename != NULL) { trace_init_name(tgid, pid, exec_path); -#ifdef DEBUG - printf("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path); -#endif + D("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path); } exec_path[0] = 0; break; @@ -227,18 +238,14 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE); if (trace_filename != NULL) { trace_dynamic_symbol_add(dsaddr, exec_arg); -#ifdef DEBUG - printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg); -#endif + D("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg); } exec_arg[0] = 0; break; case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr if (trace_filename != NULL) { trace_dynamic_symbol_remove(value); -#ifdef DEBUG - printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr); -#endif + D("QEMU.trace: dynamic symbol remove %lx\n", dsaddr); } break; @@ -343,9 +350,19 @@ static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t va break; #endif // CONFIG_MEMCHECK + case TRACE_DEV_PIPE_COMMAND: + case TRACE_DEV_PIPE_ADDRESS: + case TRACE_DEV_PIPE_SIZE: + case TRACE_DEV_PIPE_CHANNEL: + goldfish_pipe_write(tid, ((offset >> 2) - TRACE_DEV_PIPE_BASE), value); + break; + default: if (offset < 4096) { cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset); + } else { + D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset, + offset, value, value); } break; } @@ -361,9 +378,18 @@ static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset) switch (offset >> 2) { case TRACE_DEV_REG_ENABLE: // tracing enable return tracing; + + case TRACE_DEV_PIPE_COMMAND: + case TRACE_DEV_PIPE_ADDRESS: + case TRACE_DEV_PIPE_SIZE: + case TRACE_DEV_PIPE_CHANNEL: + return goldfish_pipe_read(tid, (offset >> 2) - TRACE_DEV_PIPE_BASE); + default: if (offset < 4096) { cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); + } else { + D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset); } return 0; } diff --git a/hw/goldfish_trace.h b/hw/goldfish_trace.h index 76b61a8..61d3f4f 100644 --- a/hw/goldfish_trace.h +++ b/hw/goldfish_trace.h @@ -17,6 +17,11 @@ #define CLIENT_PAGE_SIZE 4096 /* trace device registers */ + +/* The indices below all corresponds to slots that can only be accessed + * by the guest kernel. See below for indices reachable from the guest + * user-land. + */ #define TRACE_DEV_REG_SWITCH 0 #define TRACE_DEV_REG_FORK 1 #define TRACE_DEV_REG_EXECVE_PID 2 @@ -43,6 +48,22 @@ #define TRACE_DEV_REG_PRINT_NUM_HEX 62 #define TRACE_DEV_REG_STOP_EMU 90 #define TRACE_DEV_REG_ENABLE 100 + +/* NOTE: The device's second physical page is mapped to /dev/qemu_trace + * This means that if you do the following: + * + * magicPage = my_mmap("/dev/qemu_trace", ...); + * *(uint32_t*)magicPage[index] = value; + * + * The write at address magicPage+index*4 here will be seen + * by the device as a write to the i/o offset 4096 + index*4, + * i.e. (1024 + index)*4. + * + * As a consequence, any index defined below corresponds to + * location (index-1024)*4 in the mmapped page in the guest. + */ + +/* The first 64 entries are reserved for VM instrumentation */ #define TRACE_DEV_REG_METHOD_ENTRY 1024 #define TRACE_DEV_REG_METHOD_EXIT 1025 #define TRACE_DEV_REG_METHOD_EXCEPTION 1026 @@ -50,6 +71,24 @@ #define TRACE_DEV_REG_NATIVE_EXIT 1029 #define TRACE_DEV_REG_NATIVE_EXCEPTION 1030 +/* Next, QEMUD fast pipes */ +#define TRACE_DEV_PIPE_BASE 1280 /* 1024 + (64*4) */ +#define TRACE_DEV_PIPE_COMMAND (TRACE_DEV_PIPE_BASE + 0) +#define TRACE_DEV_PIPE_STATUS (TRACE_DEV_PIPE_BASE + 0) +#define TRACE_DEV_PIPE_ADDRESS (TRACE_DEV_PIPE_BASE + 1) +#define TRACE_DEV_PIPE_SIZE (TRACE_DEV_PIPE_BASE + 2) +#define TRACE_DEV_PIPE_CHANNEL (TRACE_DEV_PIPE_BASE + 3) + +/* These entries are reserved for libc instrumentation, i.e. memcheck */ +#if 0 /* see memcheck_common.h */ +#define TRACE_DEV_REG_MEMCHECK 1536 /* 1024 + (128*4) */ +#define TRACE_DEV_REG_LIBC_INIT (TRACE_DEV_REG_MEMCHECK + MEMCHECK_EVENT_LIBC_INIT) +#define TRACE_DEV_REG_MALLOC (TRACE_DEV_REG_MEMCHECK + MEMCHECK_EVENT_MALLOC) +#define TRACE_DEV_REG_FREE_PTR (TRACE_DEV_REG_MEMCHECK + MEMCHECK_EVENT_FREE_PTR) +#define TRACE_DEV_REG_QUERY_MALLOC (TRACE_DEV_REG_MEMCHECK + MEMCHECK_EVENT_QUERY_MALLOC) +#define TRACE_DEV_REG_PRINT_USER_STR (TRACE_DEV_REG_MEMCHECK + MEMCHECK_EVENT_PRINT_USER_STR) +#endif + /* the virtual trace device state */ typedef struct { struct goldfish_device dev; -- cgit v1.1