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