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