• 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 "migration/qemu-file.h"
17 #include "hw/android/goldfish/trace.h"
18 #include "hw/android/goldfish/vmem.h"
19 #include "sysemu/sysemu.h"
20 
21 /* Set to 1 to debug tracing */
22 #define DEBUG   0
23 
24 #if DEBUG
25 #  define D(...)  printf(__VA_ARGS__), fflush(stdout)
26 #else
27 #  define D(...)  ((void)0)
28 #endif
29 
30 /* Set to 1 to debug PID tracking */
31 #define  DEBUG_PID  0
32 
33 #if DEBUG_PID
34 #  define  DPID(...)  printf(__VA_ARGS__), fflush(stdout)
35 #else
36 #  define  DPID(...)  ((void)0)
37 #endif
38 
39 // TODO(digit): Re-enable tracing some day?
40 #define tracing 0
41 
42 extern void cpu_loop_exit(CPUArchState* env);
43 
44 extern const char *trace_filename;
45 
46 /* for execve */
47 static char exec_path[CLIENT_PAGE_SIZE];
48 static char exec_arg[CLIENT_PAGE_SIZE];
49 static unsigned long vstart;    // VM start
50 static unsigned long vend;      // VM end
51 static unsigned long eoff;      // offset in EXE file
52 static unsigned cmdlen;         // cmdline length
53 static unsigned pid;            // PID (really thread id)
54 static unsigned tgid;           // thread group id (really process id)
55 static unsigned tid;            // current thread id (same as pid, most of the time)
56 static unsigned long dsaddr;    // dynamic symbol address
57 static unsigned long unmap_start; // start address to unmap
58 
59 /* for context switch */
60 //static unsigned long cs_pid;    // context switch PID
61 
62 /* I/O write */
trace_dev_write(void * opaque,hwaddr offset,uint32_t value)63 static void trace_dev_write(void *opaque, hwaddr offset, uint32_t value)
64 {
65     trace_dev_state *s = (trace_dev_state *)opaque;
66 
67     (void)s;
68 
69     switch (offset >> 2) {
70     case TRACE_DEV_REG_SWITCH:  // context switch, switch to pid
71         DPID("QEMU.trace: context switch tid=%u\n", value);
72         if (trace_filename != NULL) {
73             D("QEMU.trace: kernel, context switch %u\n", value);
74         }
75         tid = (unsigned) value;
76         break;
77     case TRACE_DEV_REG_TGID:    // save the tgid for the following fork/clone
78         DPID("QEMU.trace: tgid=%u\n", value);
79         tgid = value;
80         if (trace_filename != NULL) {
81             D("QEMU.trace: kernel, tgid %u\n", value);
82         }
83         break;
84     case TRACE_DEV_REG_FORK:    // fork, fork new pid
85         DPID("QEMU.trace: fork (pid=%d tgid=%d value=%d)\n", pid, tgid, value);
86         if (trace_filename != NULL) {
87             D("QEMU.trace: kernel, fork %u\n", value);
88         }
89         break;
90     case TRACE_DEV_REG_CLONE:    // fork, clone new pid (i.e. thread)
91         DPID("QEMU.trace: clone (pid=%d tgid=%d value=%d)\n", pid, tgid, value);
92         if (trace_filename != NULL) {
93             D("QEMU.trace: kernel, clone %u\n", value);
94         }
95         break;
96     case TRACE_DEV_REG_EXECVE_VMSTART:  // execve, vstart
97         vstart = value;
98         break;
99     case TRACE_DEV_REG_EXECVE_VMEND:    // execve, vend
100         vend = value;
101         break;
102     case TRACE_DEV_REG_EXECVE_OFFSET:   // execve, offset in EXE
103         eoff = value;
104         break;
105     case TRACE_DEV_REG_EXECVE_EXEPATH:  // init exec, path of EXE
106         vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
107         if (trace_filename != NULL) {
108             D("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n",
109               vstart, vend, eoff, exec_path);
110         }
111         exec_path[0] = 0;
112         break;
113     case TRACE_DEV_REG_CMDLINE_LEN:     // execve, process cmdline length
114         cmdlen = value;
115         break;
116     case TRACE_DEV_REG_CMDLINE:         // execve, process cmdline
117         safe_memory_rw_debug(current_cpu, value, (uint8_t*)exec_arg, cmdlen, 0);
118         if (trace_filename != NULL) {
119             D("QEMU.trace: kernel, execve [%.*s]\n", cmdlen, exec_arg);
120         }
121 #if DEBUG || DEBUG_PID
122         if (trace_filename != NULL) {
123             int i;
124             for (i = 0; i < cmdlen; i ++)
125                 if (i != cmdlen - 1 && exec_arg[i] == 0)
126                     exec_arg[i] = ' ';
127             printf("QEMU.trace: kernel, execve %s[%d]\n", exec_arg, cmdlen);
128             exec_arg[0] = 0;
129         }
130 #endif
131         break;
132     case TRACE_DEV_REG_EXIT:            // exit, exit current process with exit code
133         DPID("QEMU.trace: exit tid=%u\n", value);
134         if (trace_filename != NULL) {
135             D("QEMU.trace: kernel, exit %x\n", value);
136         }
137         break;
138     case TRACE_DEV_REG_NAME:            // record thread name
139         vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
140         DPID("QEMU.trace: thread name=%s\n", exec_path);
141 
142         // Remove the trailing newline if it exists
143         int len = strlen(exec_path);
144         if (exec_path[len - 1] == '\n') {
145             exec_path[len - 1] = 0;
146         }
147         if (trace_filename != NULL) {
148             D("QEMU.trace: kernel, name %s\n", exec_path);
149         }
150         break;
151     case TRACE_DEV_REG_MMAP_EXEPATH:    // mmap, path of EXE, the others are same as execve
152         vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
153         DPID("QEMU.trace: mmap exe=%s\n", exec_path);
154         if (trace_filename != NULL) {
155             D("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, exec_path);
156         }
157         exec_path[0] = 0;
158         break;
159     case TRACE_DEV_REG_INIT_PID:        // init, name the pid that starts before device registered
160         pid = value;
161         DPID("QEMU.trace: pid=%d\n", value);
162         break;
163     case TRACE_DEV_REG_INIT_NAME:       // init, the comm of the init pid
164         vstrcpy(value, exec_path, CLIENT_PAGE_SIZE);
165         DPID("QEMU.trace: tgid=%d pid=%d name=%s\n", tgid, pid, exec_path);
166         if (trace_filename != NULL) {
167             D("QEMU.trace: kernel, init name %u [%s]\n", pid, exec_path);
168         }
169         exec_path[0] = 0;
170         break;
171 
172     case TRACE_DEV_REG_DYN_SYM_ADDR:    // dynamic symbol address
173         dsaddr = value;
174         break;
175     case TRACE_DEV_REG_DYN_SYM:         // add dynamic symbol
176         vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE);
177         if (trace_filename != NULL) {
178             D("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, exec_arg);
179         }
180         exec_arg[0] = 0;
181         break;
182     case TRACE_DEV_REG_REMOVE_ADDR:         // remove dynamic symbol addr
183         if (trace_filename != NULL) {
184             D("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
185         }
186         break;
187 
188     case TRACE_DEV_REG_PRINT_STR:       // print string
189         vstrcpy(value, exec_arg, CLIENT_PAGE_SIZE);
190         printf("%s", exec_arg);
191         exec_arg[0] = 0;
192         break;
193     case TRACE_DEV_REG_PRINT_NUM_DEC:   // print number in decimal
194         printf("%d", value);
195         break;
196     case TRACE_DEV_REG_PRINT_NUM_HEX:   // print number in hexical
197         printf("%x", value);
198         break;
199 
200     case TRACE_DEV_REG_STOP_EMU:        // stop the VM execution
201         cpu_single_env->exception_index = EXCP_HLT;
202         current_cpu->halted = 1;
203         qemu_system_shutdown_request();
204         cpu_loop_exit(cpu_single_env);
205         break;
206 
207     case TRACE_DEV_REG_ENABLE:          // tracing enable: 0 = stop, 1 = start
208         break;
209 
210     case TRACE_DEV_REG_UNMAP_START:
211         unmap_start = value;
212         break;
213     case TRACE_DEV_REG_UNMAP_END:
214         break;
215 
216     case TRACE_DEV_REG_METHOD_ENTRY:
217     case TRACE_DEV_REG_METHOD_EXIT:
218     case TRACE_DEV_REG_METHOD_EXCEPTION:
219     case TRACE_DEV_REG_NATIVE_ENTRY:
220     case TRACE_DEV_REG_NATIVE_EXIT:
221     case TRACE_DEV_REG_NATIVE_EXCEPTION:
222         if (trace_filename != NULL) {
223             if (tracing) {
224                 int __attribute__((unused)) call_type = (offset - 4096) >> 2;
225                 //trace_interpreted_method(value, call_type);
226             }
227         }
228         break;
229 
230     default:
231         if (offset < 4096) {
232             cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
233         } else {
234             D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset,
235               offset, value, value);
236         }
237         break;
238     }
239 }
240 
241 /* I/O read */
trace_dev_read(void * opaque,hwaddr offset)242 static uint32_t trace_dev_read(void *opaque, hwaddr offset)
243 {
244     trace_dev_state *s = (trace_dev_state *)opaque;
245 
246     (void)s;
247 
248     switch (offset >> 2) {
249     case TRACE_DEV_REG_ENABLE:          // tracing enable
250         return tracing;
251 
252     default:
253         if (offset < 4096) {
254             cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset);
255         } else {
256             D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset);
257         }
258         return 0;
259     }
260     return 0;
261 }
262 
263 static CPUReadMemoryFunc *trace_dev_readfn[] = {
264    trace_dev_read,
265    trace_dev_read,
266    trace_dev_read
267 };
268 
269 static CPUWriteMemoryFunc *trace_dev_writefn[] = {
270    trace_dev_write,
271    trace_dev_write,
272    trace_dev_write
273 };
274 
275 /* initialize the trace device */
trace_dev_init()276 void trace_dev_init()
277 {
278     trace_dev_state *s;
279 
280     s = (trace_dev_state *)g_malloc0(sizeof(trace_dev_state));
281     s->dev.name = "qemu_trace";
282     s->dev.id = -1;
283     s->dev.base = 0;       // will be allocated dynamically
284     s->dev.size = 0x2000;
285     s->dev.irq = 0;
286     s->dev.irq_count = 0;
287 
288     goldfish_device_add(&s->dev, trace_dev_readfn, trace_dev_writefn, s);
289 
290     exec_path[0] = exec_arg[0] = '\0';
291 }
292