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