From 8b23a6c7e1aee255004dd19098d4c2462b61b849 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:30:32 -0800 Subject: auto import from //depot/cupcake/@135843 --- hw/goldfish_trace.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 hw/goldfish_trace.c (limited to 'hw/goldfish_trace.c') 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'; +} -- cgit v1.1