aboutsummaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-03-21 22:24:45 +0100
committerDavid 'Digit' Turner <digit@android.com>2011-04-11 18:19:07 +0200
commit335d2c1342bb887ac67f1f60cff795f0c06beaca (patch)
treef4d66f3f3e6e284b6748fa251caa55694eb76fb4 /hw
parent89217f57a256796b67b4d3f319e0f18f6225666a (diff)
downloadexternal_qemu-335d2c1342bb887ac67f1f60cff795f0c06beaca.zip
external_qemu-335d2c1342bb887ac67f1f60cff795f0c06beaca.tar.gz
external_qemu-335d2c1342bb887ac67f1f60cff795f0c06beaca.tar.bz2
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
Diffstat (limited to 'hw')
-rw-r--r--hw/android_arm.c1
-rw-r--r--hw/goldfish_trace.c98
-rw-r--r--hw/goldfish_trace.h39
3 files changed, 102 insertions, 36 deletions
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;