aboutsummaryrefslogtreecommitdiffstats
path: root/hw/goldfish_trace.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
commit8b23a6c7e1aee255004dd19098d4c2462b61b849 (patch)
tree7a4d682ba51f0ff0364c5ca2509f515bdaf96de9 /hw/goldfish_trace.c
parentf721e3ac031f892af46f255a47d7f54a91317b30 (diff)
downloadexternal_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.zip
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.gz
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'hw/goldfish_trace.c')
-rw-r--r--hw/goldfish_trace.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c
new file mode 100644
index 0000000..ad0eba5
--- /dev/null
+++ b/hw/goldfish_trace.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+/*
+ * Virtual hardware for bridging the FUSE kernel module
+ * in the emulated OS and outside file system
+ */
+#include "qemu_file.h"
+#include "goldfish_trace.h"
+
+//#define DEBUG 1
+
+extern void cpu_loop_exit(void);
+
+extern int tracing;
+
+/* for execve */
+static char path[CLIENT_PAGE_SIZE];
+static char arg[CLIENT_PAGE_SIZE];
+static unsigned long vstart; // VM start
+static unsigned long vend; // VM end
+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 long dsaddr; // dynamic symbol address
+static unsigned long unmap_start; // start address to unmap
+
+/* for context switch */
+//static unsigned long cs_pid; // context switch PID
+
+/* I/O write */
+static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ trace_dev_state *s = (trace_dev_state *)opaque;
+
+ offset -= s->base;
+ switch (offset >> 2) {
+ case TRACE_DEV_REG_SWITCH: // context switch, switch to pid
+ trace_switch(value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, context switch %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone
+ tgid = value;
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, tgid %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_FORK: // fork, fork new pid
+ trace_fork(tgid, value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, fork %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread)
+ trace_clone(tgid, value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, clone %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart
+ vstart = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend
+ vend = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE
+ eoff = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_init_exec(vstart, vend, eoff, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+#endif
+ path[0] = 0;
+ break;
+ case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length
+ cmdlen = value;
+ break;
+ case TRACE_DEV_REG_CMDLINE: // execve, process cmdline
+ vmemcpy(value, arg, cmdlen);
+ trace_execve(arg, cmdlen);
+#ifdef DEBUG
+ {
+ int i;
+ for (i = 0; i < cmdlen; i ++)
+ if (i != cmdlen - 1 && arg[i] == 0)
+ arg[i] = ' ';
+ printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
+ }
+#endif
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code
+ trace_exit(value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, exit %x\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_NAME: // record thread name
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+
+ // Remove the trailing newline if it exists
+ int len = strlen(path);
+ if (path[len - 1] == '\n') {
+ path[len - 1] = 0;
+ }
+ trace_name(path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, name %s\n", path);
+#endif
+ break;
+ case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_mmap(vstart, vend, eoff, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+#endif
+ path[0] = 0;
+ break;
+ case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered
+ pid = value;
+ break;
+ case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_init_name(tgid, pid, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
+#endif
+ path[0] = 0;
+ break;
+
+ case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address
+ dsaddr = value;
+ break;
+ case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol
+ vstrcpy(value, arg, CLIENT_PAGE_SIZE);
+ trace_dynamic_symbol_add(dsaddr, arg);
+#ifdef DEBUG
+ printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
+#endif
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr
+ trace_dynamic_symbol_remove(value);
+#ifdef DEBUG
+ printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
+#endif
+ arg[0] = 0;
+ break;
+
+ case TRACE_DEV_REG_PRINT_STR: // print string
+ vstrcpy(value, arg, CLIENT_PAGE_SIZE);
+ printf("%s", arg);
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal
+ printf("%d", value);
+ break;
+ case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical
+ printf("%x", value);
+ break;
+
+ case TRACE_DEV_REG_STOP_EMU: // stop the VM execution
+ // To ensure that the number of instructions executed in this
+ // block is correct, we pretend that there was an exception.
+ trace_exception(0);
+
+ cpu_single_env->exception_index = EXCP_HLT;
+ cpu_single_env->halted = 1;
+ qemu_system_shutdown_request();
+ cpu_loop_exit();
+ break;
+
+ case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start
+ if (value == 1)
+ start_tracing();
+ else if (value == 0) {
+ stop_tracing();
+
+ // To ensure that the number of instructions executed in this
+ // block is correct, we pretend that there was an exception.
+ trace_exception(0);
+ }
+ break;
+
+ case TRACE_DEV_REG_UNMAP_START:
+ unmap_start = value;
+ break;
+ case TRACE_DEV_REG_UNMAP_END:
+ trace_munmap(unmap_start, value);
+ break;
+
+ default:
+ cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
+ break;
+ }
+}
+
+/* I/O read */
+static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset)
+{
+ trace_dev_state *s = (trace_dev_state *)opaque;
+
+ offset -= s->base;
+ switch (offset >> 2) {
+ case TRACE_DEV_REG_ENABLE: // tracing enable
+ return tracing;
+ default:
+ cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset);
+ return 0;
+ }
+ return 0;
+}
+
+static CPUReadMemoryFunc *trace_dev_readfn[] = {
+ trace_dev_read,
+ trace_dev_read,
+ trace_dev_read
+};
+
+static CPUWriteMemoryFunc *trace_dev_writefn[] = {
+ trace_dev_write,
+ trace_dev_write,
+ trace_dev_write
+};
+
+/* initialize the trace device */
+void trace_dev_init(uint32_t base)
+{
+ int iomemtype;
+ trace_dev_state *s;
+
+ s = (trace_dev_state *)qemu_mallocz(sizeof(trace_dev_state));
+ iomemtype = cpu_register_io_memory(0, trace_dev_readfn, trace_dev_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ s->base = base;
+
+ path[0] = arg[0] = '\0';
+}