• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
trace_dev_write(void * opaque,target_phys_addr_t offset,uint32_t value)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 */
trace_dev_read(void * opaque,target_phys_addr_t offset)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 */
trace_dev_init()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