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 "qemu_file.h" 17 #include "goldfish_trace.h" 18 #include "sysemu.h" 19 #include "android-trace.h" 20 #ifdef CONFIG_MEMCHECK 21 #include "memcheck/memcheck.h" 22 #include "memcheck/memcheck_util.h" 23 #endif // CONFIG_MEMCHECK 24 25 /* Set to 1 to debug tracing */ 26 #define DEBUG 0 27 28 #if DEBUG 29 # define D(...) printf(__VA_ARGS__), fflush(stdout) 30 #else 31 # define D(...) ((void)0) 32 #endif 33 34 /* Set to 1 to debug PID tracking */ 35 #define DEBUG_PID 0 36 37 #if DEBUG_PID 38 # define DPID(...) printf(__VA_ARGS__), fflush(stdout) 39 #else 40 # define DPID(...) ((void)0) 41 #endif 42 43 extern void cpu_loop_exit(void); 44 45 extern int tracing; 46 extern const char *trace_filename; 47 48 /* for execve */ 49 static char exec_path[CLIENT_PAGE_SIZE]; 50 static char exec_arg[CLIENT_PAGE_SIZE]; 51 static unsigned long vstart; // VM start 52 static unsigned long vend; // VM end 53 static unsigned long eoff; // offset in EXE file 54 static unsigned cmdlen; // cmdline length 55 static unsigned pid; // PID (really thread id) 56 static unsigned tgid; // thread group id (really process id) 57 static unsigned tid; // current thread id (same as pid, most of the time) 58 static unsigned long dsaddr; // dynamic symbol address 59 static unsigned long unmap_start; // start address to unmap 60 61 /* for context switch */ 62 //static unsigned long cs_pid; // context switch PID 63 64 /* I/O write */ 65 static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value) 66 { 67 trace_dev_state *s = (trace_dev_state *)opaque; 68 69 (void)s; 70 71 switch (offset >> 2) { 72 case TRACE_DEV_REG_SWITCH: // context switch, switch to pid 73 DPID("QEMU.trace: context switch tid=%u\n", value); 74 if (trace_filename != NULL) { 75 trace_switch(value); 76 D("QEMU.trace: kernel, context switch %u\n", value); 77 } 78 #ifdef CONFIG_MEMCHECK 79 if (memcheck_enabled) { 80 memcheck_switch(value); 81 } 82 #endif // CONFIG_MEMCHECK 83 tid = (unsigned) value; 84 break; 85 case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone 86 DPID("QEMU.trace: tgid=%u\n", value); 87 tgid = value; 88 if (trace_filename != NULL) { 89 D("QEMU.trace: kernel, tgid %u\n", value); 90 } 91 break; 92 case TRACE_DEV_REG_FORK: // fork, fork new pid 93 DPID("QEMU.trace: fork (pid=%d tgid=%d value=%d)\n", pid, tgid, value); 94 if (trace_filename != NULL) { 95 trace_fork(tgid, value); 96 D("QEMU.trace: kernel, fork %u\n", value); 97 } 98 #ifdef CONFIG_MEMCHECK 99 if (memcheck_enabled) { 100 memcheck_fork(tgid, value); 101 } 102 #endif // CONFIG_MEMCHECK 103 break; 104 case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread) 105 DPID("QEMU.trace: clone (pid=%d tgid=%d value=%d)\n", pid, tgid, value); 106 if (trace_filename != NULL) { 107 trace_clone(tgid, value); 108 D("QEMU.trace: kernel, clone %u\n", value); 109 } 110 #ifdef CONFIG_MEMCHECK 111 if (memcheck_enabled) { 112 memcheck_clone(tgid, value); 113 } 114 #endif // CONFIG_MEMCHECK 115 break; 116 case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart 117 vstart = value; 118 break; 119 case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend 120 vend = value; 121 break; 122 case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE 123 eoff = value; 124 break; 125 case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE 126 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 127 if (trace_filename != NULL) { 128 trace_init_exec(vstart, vend, eoff, exec_path); 129 D("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", 130 vstart, vend, eoff, exec_path); 131 } 132 #ifdef CONFIG_MEMCHECK 133 if (memcheck_enabled) { 134 if (exec_path[0] == '\0') { 135 // vstrcpy may fail to copy path. In this case lets do it 136 // differently. 137 memcheck_get_guest_kernel_string(exec_path, value, CLIENT_PAGE_SIZE); 138 } 139 memcheck_mmap_exepath(vstart, vend, eoff, exec_path); 140 } 141 #endif // CONFIG_MEMCHECK 142 exec_path[0] = 0; 143 break; 144 case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length 145 cmdlen = value; 146 break; 147 case TRACE_DEV_REG_CMDLINE: // execve, process cmdline 148 cpu_memory_rw_debug(cpu_single_env, value, (uint8_t*)exec_arg, cmdlen, 0); 149 if (trace_filename != NULL) { 150 trace_execve(exec_arg, cmdlen); 151 } 152 #ifdef CONFIG_MEMCHECK 153 if (memcheck_enabled) { 154 memcheck_set_cmd_line(exec_arg, cmdlen); 155 } 156 #endif // CONFIG_MEMCHECK 157 #if DEBUG || DEBUG_PID 158 if (trace_filename != NULL) { 159 int i; 160 for (i = 0; i < cmdlen; i ++) 161 if (i != cmdlen - 1 && exec_arg[i] == 0) 162 exec_arg[i] = ' '; 163 printf("QEMU.trace: kernel, execve %s[%d]\n", exec_arg, cmdlen); 164 exec_arg[0] = 0; 165 } 166 #endif 167 break; 168 case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code 169 DPID("QEMU.trace: exit tid=%u\n", value); 170 if (trace_filename != NULL) { 171 trace_exit(value); 172 D("QEMU.trace: kernel, exit %x\n", value); 173 } 174 #ifdef CONFIG_MEMCHECK 175 if (memcheck_enabled) { 176 memcheck_exit(value); 177 } 178 #endif // CONFIG_MEMCHECK 179 break; 180 case TRACE_DEV_REG_NAME: // record thread name 181 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 182 DPID("QEMU.trace: thread name=%s\n", exec_path); 183 184 // Remove the trailing newline if it exists 185 int len = strlen(exec_path); 186 if (exec_path[len - 1] == '\n') { 187 exec_path[len - 1] = 0; 188 } 189 if (trace_filename != NULL) { 190 trace_name(exec_path); 191 D("QEMU.trace: kernel, name %s\n", exec_path); 192 } 193 break; 194 case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve 195 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 196 DPID("QEMU.trace: mmap exe=%s\n", exec_path); 197 if (trace_filename != NULL) { 198 trace_mmap(vstart, vend, eoff, exec_path); 199 D("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path); 200 } 201 #ifdef CONFIG_MEMCHECK 202 if (memcheck_enabled) { 203 if (exec_path[0] == '\0') { 204 // vstrcpy may fail to copy path. In this case lets do it 205 // differently. 206 memcheck_get_guest_kernel_string(exec_path, value, CLIENT_PAGE_SIZE); 207 } 208 memcheck_mmap_exepath(vstart, vend, eoff, exec_path); 209 } 210 #endif // CONFIG_MEMCHECK 211 exec_path[0] = 0; 212 break; 213 case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered 214 pid = value; 215 DPID("QEMU.trace: pid=%d\n", value); 216 #ifdef CONFIG_MEMCHECK 217 if (memcheck_enabled) { 218 memcheck_init_pid(value); 219 } 220 #endif // CONFIG_MEMCHECK 221 break; 222 case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid 223 vstrcpy(value, exec_path, CLIENT_PAGE_SIZE); 224 DPID("QEMU.trace: tgid=%d pid=%d name=%s\n", tgid, pid, exec_path); 225 if (trace_filename != NULL) { 226 trace_init_name(tgid, pid, exec_path); 227 D("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path); 228 } 229 exec_path[0] = 0; 230 break; 231 232 case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address 233 dsaddr = value; 234 break; 235 case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol 236 vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE); 237 if (trace_filename != NULL) { 238 trace_dynamic_symbol_add(dsaddr, exec_arg); 239 D("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg); 240 } 241 exec_arg[0] = 0; 242 break; 243 case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr 244 if (trace_filename != NULL) { 245 trace_dynamic_symbol_remove(value); 246 D("QEMU.trace: dynamic symbol remove %lx\n", dsaddr); 247 } 248 break; 249 250 case TRACE_DEV_REG_PRINT_STR: // print string 251 vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE); 252 printf("%s", exec_arg); 253 exec_arg[0] = 0; 254 break; 255 case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal 256 printf("%d", value); 257 break; 258 case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical 259 printf("%x", value); 260 break; 261 262 case TRACE_DEV_REG_STOP_EMU: // stop the VM execution 263 if (trace_filename != NULL) { 264 // To ensure that the number of instructions executed in this 265 // block is correct, we pretend that there was an exception. 266 trace_exception(0); 267 } 268 cpu_single_env->exception_index = EXCP_HLT; 269 cpu_single_env->halted = 1; 270 qemu_system_shutdown_request(); 271 cpu_loop_exit(); 272 break; 273 274 case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start 275 if (value == 1) { 276 if (trace_filename != NULL) { 277 start_tracing(); 278 } 279 } 280 else if (value == 0) { 281 if (trace_filename != NULL) { 282 stop_tracing(); 283 284 // To ensure that the number of instructions executed in this 285 // block is correct, we pretend that there was an exception. 286 trace_exception(0); 287 } 288 } 289 break; 290 291 case TRACE_DEV_REG_UNMAP_START: 292 unmap_start = value; 293 break; 294 case TRACE_DEV_REG_UNMAP_END: 295 if (trace_filename != NULL) { 296 trace_munmap(unmap_start, value); 297 } 298 #ifdef CONFIG_MEMCHECK 299 if (memcheck_enabled) { 300 memcheck_unmap(unmap_start, value); 301 } 302 #endif // CONFIG_MEMCHECK 303 break; 304 305 case TRACE_DEV_REG_METHOD_ENTRY: 306 case TRACE_DEV_REG_METHOD_EXIT: 307 case TRACE_DEV_REG_METHOD_EXCEPTION: 308 case TRACE_DEV_REG_NATIVE_ENTRY: 309 case TRACE_DEV_REG_NATIVE_EXIT: 310 case TRACE_DEV_REG_NATIVE_EXCEPTION: 311 if (trace_filename != NULL) { 312 if (tracing) { 313 int call_type = (offset - 4096) >> 2; 314 trace_interpreted_method(value, call_type); 315 } 316 } 317 break; 318 319 #ifdef CONFIG_MEMCHECK 320 case TRACE_DEV_REG_MALLOC: 321 if (memcheck_enabled) { 322 memcheck_guest_alloc(value); 323 } 324 break; 325 326 case TRACE_DEV_REG_FREE_PTR: 327 if (memcheck_enabled) { 328 memcheck_guest_free(value); 329 } 330 break; 331 332 case TRACE_DEV_REG_QUERY_MALLOC: 333 if (memcheck_enabled) { 334 memcheck_guest_query_malloc(value); 335 } 336 break; 337 338 case TRACE_DEV_REG_LIBC_INIT: 339 if (memcheck_enabled) { 340 memcheck_guest_libc_initialized(value); 341 } 342 break; 343 344 case TRACE_DEV_REG_PRINT_USER_STR: 345 if (memcheck_enabled) { 346 memcheck_guest_print_str(value); 347 } 348 break; 349 #endif // CONFIG_MEMCHECK 350 351 default: 352 if (offset < 4096) { 353 cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset); 354 } else { 355 D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset, 356 offset, value, value); 357 } 358 break; 359 } 360 } 361 362 /* I/O read */ 363 static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset) 364 { 365 trace_dev_state *s = (trace_dev_state *)opaque; 366 367 (void)s; 368 369 switch (offset >> 2) { 370 case TRACE_DEV_REG_ENABLE: // tracing enable 371 return tracing; 372 373 default: 374 if (offset < 4096) { 375 cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); 376 } else { 377 D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset); 378 } 379 return 0; 380 } 381 return 0; 382 } 383 384 static CPUReadMemoryFunc *trace_dev_readfn[] = { 385 trace_dev_read, 386 trace_dev_read, 387 trace_dev_read 388 }; 389 390 static CPUWriteMemoryFunc *trace_dev_writefn[] = { 391 trace_dev_write, 392 trace_dev_write, 393 trace_dev_write 394 }; 395 396 /* initialize the trace device */ 397 void trace_dev_init() 398 { 399 trace_dev_state *s; 400 401 s = (trace_dev_state *)qemu_mallocz(sizeof(trace_dev_state)); 402 s->dev.name = "qemu_trace"; 403 s->dev.id = -1; 404 s->dev.base = 0; // will be allocated dynamically 405 s->dev.size = 0x2000; 406 s->dev.irq = 0; 407 s->dev.irq_count = 0; 408 409 goldfish_device_add(&s->dev, trace_dev_readfn, trace_dev_writefn, s); 410 411 exec_path[0] = exec_arg[0] = '\0'; 412 } 413