1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 /* 13 * Virtual hardware for bridging the FUSE kernel module 14 * in the emulated OS and outside file system 15 */ 16 #include "migration/qemu-file.h" 17 #include "hw/android/goldfish/trace.h" 18 #include "hw/android/goldfish/vmem.h" 19 #include "sysemu/sysemu.h" 20 21 /* Set to 1 to debug tracing */ 22 #define DEBUG 0 23 24 #if DEBUG 25 # define D(...) printf(__VA_ARGS__), fflush(stdout) 26 #else 27 # define D(...) ((void)0) 28 #endif 29 30 /* Set to 1 to debug PID tracking */ 31 #define DEBUG_PID 0 32 33 #if DEBUG_PID 34 # define DPID(...) printf(__VA_ARGS__), fflush(stdout) 35 #else 36 # define DPID(...) ((void)0) 37 #endif 38 39 // TODO(digit): Re-enable tracing some day? 40 #define tracing 0 41 42 extern void cpu_loop_exit(CPUArchState* env); 43 44 extern const char *trace_filename; 45 46 /* for execve */ 47 static char exec_path[CLIENT_PAGE_SIZE]; 48 static char exec_arg[CLIENT_PAGE_SIZE]; 49 static unsigned long vstart; // VM start 50 static unsigned long vend; // VM end 51 static unsigned long eoff; // offset in EXE file 52 static unsigned cmdlen; // cmdline length 53 static unsigned pid; // PID (really thread id) 54 static unsigned tgid; // thread group id (really process id) 55 static unsigned tid; // current thread id (same as pid, most of the time) 56 static unsigned long dsaddr; // dynamic symbol address 57 static unsigned long unmap_start; // start address to unmap 58 59 /* for context switch */ 60 //static unsigned long cs_pid; // context switch PID 61 62 /* I/O write */ 63 static void trace_dev_write(void *opaque, hwaddr offset, uint32_t value) 64 { 65 trace_dev_state *s = (trace_dev_state *)opaque; 66 67 (void)s; 68 69 switch (offset >> 2) { 70 case TRACE_DEV_REG_SWITCH: // context switch, switch to pid 71 DPID("QEMU.trace: context switch tid=%u\n", value); 72 if (trace_filename != NULL) { 73 D("QEMU.trace: kernel, context switch %u\n", value); 74 } 75 tid = (unsigned) value; 76 break; 77 case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone 78 DPID("QEMU.trace: tgid=%u\n", value); 79 tgid = value; 80 if (trace_filename != NULL) { 81 D("QEMU.trace: kernel, tgid %u\n", value); 82 } 83 break; 84 case TRACE_DEV_REG_FORK: // fork, fork new pid 85 DPID("QEMU.trace: fork (pid=%d tgid=%d value=%d)\n", pid, tgid, value); 86 if (trace_filename != NULL) { 87 D("QEMU.trace: kernel, fork %u\n", value); 88 } 89 break; 90 case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread) 91 DPID("QEMU.trace: clone (pid=%d tgid=%d value=%d)\n", pid, tgid, value); 92 if (trace_filename != NULL) { 93 D("QEMU.trace: kernel, clone %u\n", value); 94 } 95 break; 96 case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart 97 vstart = value; 98 break; 99 case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend 100 vend = value; 101 break; 102 case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE 103 eoff = value; 104 break; 105 case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE 106 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 107 if (trace_filename != NULL) { 108 D("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", 109 vstart, vend, eoff, exec_path); 110 } 111 exec_path[0] = 0; 112 break; 113 case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length 114 cmdlen = value; 115 break; 116 case TRACE_DEV_REG_CMDLINE: // execve, process cmdline 117 safe_memory_rw_debug(current_cpu, value, (uint8_t*)exec_arg, cmdlen, 0); 118 if (trace_filename != NULL) { 119 D("QEMU.trace: kernel, execve [%.*s]\n", cmdlen, exec_arg); 120 } 121 #if DEBUG || DEBUG_PID 122 if (trace_filename != NULL) { 123 int i; 124 for (i = 0; i < cmdlen; i ++) 125 if (i != cmdlen - 1 && exec_arg[i] == 0) 126 exec_arg[i] = ' '; 127 printf("QEMU.trace: kernel, execve %s[%d]\n", exec_arg, cmdlen); 128 exec_arg[0] = 0; 129 } 130 #endif 131 break; 132 case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code 133 DPID("QEMU.trace: exit tid=%u\n", value); 134 if (trace_filename != NULL) { 135 D("QEMU.trace: kernel, exit %x\n", value); 136 } 137 break; 138 case TRACE_DEV_REG_NAME: // record thread name 139 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 140 DPID("QEMU.trace: thread name=%s\n", exec_path); 141 142 // Remove the trailing newline if it exists 143 int len = strlen(exec_path); 144 if (exec_path[len - 1] == '\n') { 145 exec_path[len - 1] = 0; 146 } 147 if (trace_filename != NULL) { 148 D("QEMU.trace: kernel, name %s\n", exec_path); 149 } 150 break; 151 case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve 152 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 153 DPID("QEMU.trace: mmap exe=%s\n", exec_path); 154 if (trace_filename != NULL) { 155 D("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path); 156 } 157 exec_path[0] = 0; 158 break; 159 case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered 160 pid = value; 161 DPID("QEMU.trace: pid=%d\n", value); 162 break; 163 case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid 164 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 165 DPID("QEMU.trace: tgid=%d pid=%d name=%s\n", tgid, pid, exec_path); 166 if (trace_filename != NULL) { 167 D("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path); 168 } 169 exec_path[0] = 0; 170 break; 171 172 case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address 173 dsaddr = value; 174 break; 175 case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol 176 vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE); 177 if (trace_filename != NULL) { 178 D("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg); 179 } 180 exec_arg[0] = 0; 181 break; 182 case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr 183 if (trace_filename != NULL) { 184 D("QEMU.trace: dynamic symbol remove %lx\n", dsaddr); 185 } 186 break; 187 188 case TRACE_DEV_REG_PRINT_STR: // print string 189 vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE); 190 printf("%s", exec_arg); 191 exec_arg[0] = 0; 192 break; 193 case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal 194 printf("%d", value); 195 break; 196 case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical 197 printf("%x", value); 198 break; 199 200 case TRACE_DEV_REG_STOP_EMU: // stop the VM execution 201 cpu_single_env->exception_index = EXCP_HLT; 202 current_cpu->halted = 1; 203 qemu_system_shutdown_request(); 204 cpu_loop_exit(cpu_single_env); 205 break; 206 207 case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start 208 break; 209 210 case TRACE_DEV_REG_UNMAP_START: 211 unmap_start = value; 212 break; 213 case TRACE_DEV_REG_UNMAP_END: 214 break; 215 216 case TRACE_DEV_REG_METHOD_ENTRY: 217 case TRACE_DEV_REG_METHOD_EXIT: 218 case TRACE_DEV_REG_METHOD_EXCEPTION: 219 case TRACE_DEV_REG_NATIVE_ENTRY: 220 case TRACE_DEV_REG_NATIVE_EXIT: 221 case TRACE_DEV_REG_NATIVE_EXCEPTION: 222 if (trace_filename != NULL) { 223 if (tracing) { 224 int __attribute__((unused)) call_type = (offset - 4096) >> 2; 225 //trace_interpreted_method(value, call_type); 226 } 227 } 228 break; 229 230 default: 231 if (offset < 4096) { 232 cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset); 233 } else { 234 D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset, 235 offset, value, value); 236 } 237 break; 238 } 239 } 240 241 /* I/O read */ 242 static uint32_t trace_dev_read(void *opaque, hwaddr offset) 243 { 244 trace_dev_state *s = (trace_dev_state *)opaque; 245 246 (void)s; 247 248 switch (offset >> 2) { 249 case TRACE_DEV_REG_ENABLE: // tracing enable 250 return tracing; 251 252 default: 253 if (offset < 4096) { 254 cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); 255 } else { 256 D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset); 257 } 258 return 0; 259 } 260 return 0; 261 } 262 263 static CPUReadMemoryFunc *trace_dev_readfn[] = { 264 trace_dev_read, 265 trace_dev_read, 266 trace_dev_read 267 }; 268 269 static CPUWriteMemoryFunc *trace_dev_writefn[] = { 270 trace_dev_write, 271 trace_dev_write, 272 trace_dev_write 273 }; 274 275 /* initialize the trace device */ 276 void trace_dev_init() 277 { 278 trace_dev_state *s; 279 280 s = (trace_dev_state *)g_malloc0(sizeof(trace_dev_state)); 281 s->dev.name = "qemu_trace"; 282 s->dev.id = -1; 283 s->dev.base = 0; // will be allocated dynamically 284 s->dev.size = 0x2000; 285 s->dev.irq = 0; 286 s->dev.irq_count = 0; 287 288 goldfish_device_add(&s->dev, trace_dev_readfn, trace_dev_writefn, s); 289 290 exec_path[0] = exec_arg[0] = '\0'; 291 } 292