blob: c4f2f92c3611ef184ed5f1ac11594f5def0f040f [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* 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
19//#define DEBUG 1
20
21extern void cpu_loop_exit(void);
22
23extern int tracing;
24
25/* for execve */
26static char path[CLIENT_PAGE_SIZE];
27static char arg[CLIENT_PAGE_SIZE];
28static unsigned long vstart; // VM start
29static unsigned long vend; // VM end
30static unsigned long eoff; // offset in EXE file
31static unsigned cmdlen; // cmdline length
32static unsigned pid; // PID (really thread id)
33static unsigned tgid; // thread group id (really process id)
34static unsigned long dsaddr; // dynamic symbol address
35static unsigned long unmap_start; // start address to unmap
36
37/* for context switch */
38//static unsigned long cs_pid; // context switch PID
39
40/* I/O write */
41static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
42{
43 trace_dev_state *s = (trace_dev_state *)opaque;
44
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080045 switch (offset >> 2) {
46 case TRACE_DEV_REG_SWITCH: // context switch, switch to pid
47 trace_switch(value);
48#ifdef DEBUG
49 printf("QEMU.trace: kernel, context switch %u\n", value);
50#endif
51 break;
52 case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone
53 tgid = value;
54#ifdef DEBUG
55 printf("QEMU.trace: kernel, tgid %u\n", value);
56#endif
57 break;
58 case TRACE_DEV_REG_FORK: // fork, fork new pid
59 trace_fork(tgid, value);
60#ifdef DEBUG
61 printf("QEMU.trace: kernel, fork %u\n", value);
62#endif
63 break;
64 case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread)
65 trace_clone(tgid, value);
66#ifdef DEBUG
67 printf("QEMU.trace: kernel, clone %u\n", value);
68#endif
69 break;
70 case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart
71 vstart = value;
72 break;
73 case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend
74 vend = value;
75 break;
76 case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE
77 eoff = value;
78 break;
79 case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE
80 vstrcpy(value, path, CLIENT_PAGE_SIZE);
81 trace_init_exec(vstart, vend, eoff, path);
82#ifdef DEBUG
83 printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
84#endif
85 path[0] = 0;
86 break;
87 case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length
88 cmdlen = value;
89 break;
90 case TRACE_DEV_REG_CMDLINE: // execve, process cmdline
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070091 cpu_memory_rw_debug(cpu_single_env, value, arg, cmdlen, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080092 trace_execve(arg, cmdlen);
93#ifdef DEBUG
94 {
95 int i;
96 for (i = 0; i < cmdlen; i ++)
97 if (i != cmdlen - 1 && arg[i] == 0)
98 arg[i] = ' ';
99 printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
100 }
101#endif
102 arg[0] = 0;
103 break;
104 case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code
105 trace_exit(value);
106#ifdef DEBUG
107 printf("QEMU.trace: kernel, exit %x\n", value);
108#endif
109 break;
110 case TRACE_DEV_REG_NAME: // record thread name
111 vstrcpy(value, path, CLIENT_PAGE_SIZE);
112
113 // Remove the trailing newline if it exists
114 int len = strlen(path);
115 if (path[len - 1] == '\n') {
116 path[len - 1] = 0;
117 }
118 trace_name(path);
119#ifdef DEBUG
120 printf("QEMU.trace: kernel, name %s\n", path);
121#endif
122 break;
123 case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve
124 vstrcpy(value, path, CLIENT_PAGE_SIZE);
125 trace_mmap(vstart, vend, eoff, path);
126#ifdef DEBUG
127 printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
128#endif
129 path[0] = 0;
130 break;
131 case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered
132 pid = value;
133 break;
134 case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid
135 vstrcpy(value, path, CLIENT_PAGE_SIZE);
136 trace_init_name(tgid, pid, path);
137#ifdef DEBUG
138 printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
139#endif
140 path[0] = 0;
141 break;
142
143 case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address
144 dsaddr = value;
145 break;
146 case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol
147 vstrcpy(value, arg, CLIENT_PAGE_SIZE);
148 trace_dynamic_symbol_add(dsaddr, arg);
149#ifdef DEBUG
150 printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
151#endif
152 arg[0] = 0;
153 break;
154 case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr
155 trace_dynamic_symbol_remove(value);
156#ifdef DEBUG
157 printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
158#endif
159 arg[0] = 0;
160 break;
161
162 case TRACE_DEV_REG_PRINT_STR: // print string
163 vstrcpy(value, arg, CLIENT_PAGE_SIZE);
164 printf("%s", arg);
165 arg[0] = 0;
166 break;
167 case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal
168 printf("%d", value);
169 break;
170 case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical
171 printf("%x", value);
172 break;
173
174 case TRACE_DEV_REG_STOP_EMU: // stop the VM execution
175 // To ensure that the number of instructions executed in this
176 // block is correct, we pretend that there was an exception.
177 trace_exception(0);
178
179 cpu_single_env->exception_index = EXCP_HLT;
180 cpu_single_env->halted = 1;
181 qemu_system_shutdown_request();
182 cpu_loop_exit();
183 break;
184
185 case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start
186 if (value == 1)
187 start_tracing();
188 else if (value == 0) {
189 stop_tracing();
190
191 // To ensure that the number of instructions executed in this
192 // block is correct, we pretend that there was an exception.
193 trace_exception(0);
194 }
195 break;
196
197 case TRACE_DEV_REG_UNMAP_START:
198 unmap_start = value;
199 break;
200 case TRACE_DEV_REG_UNMAP_END:
201 trace_munmap(unmap_start, value);
202 break;
203
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700204 case TRACE_DEV_REG_METHOD_ENTRY:
205 case TRACE_DEV_REG_METHOD_EXIT:
206 case TRACE_DEV_REG_METHOD_EXCEPTION:
Jack Veenstrae3ea32f2009-05-19 14:41:14 -0700207 case TRACE_DEV_REG_NATIVE_ENTRY:
208 case TRACE_DEV_REG_NATIVE_EXIT:
209 case TRACE_DEV_REG_NATIVE_EXCEPTION:
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700210 if (tracing) {
211 int call_type = (offset - 4096) >> 2;
212 trace_interpreted_method(value, call_type);
213 }
214 break;
215
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800216 default:
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700217 if (offset < 4096) {
218 cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
219 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800220 break;
221 }
222}
223
224/* I/O read */
225static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset)
226{
227 trace_dev_state *s = (trace_dev_state *)opaque;
228
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800229 switch (offset >> 2) {
230 case TRACE_DEV_REG_ENABLE: // tracing enable
231 return tracing;
232 default:
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700233 if (offset < 4096) {
234 cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset);
235 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800236 return 0;
237 }
238 return 0;
239}
240
241static CPUReadMemoryFunc *trace_dev_readfn[] = {
242 trace_dev_read,
243 trace_dev_read,
244 trace_dev_read
245};
246
247static CPUWriteMemoryFunc *trace_dev_writefn[] = {
248 trace_dev_write,
249 trace_dev_write,
250 trace_dev_write
251};
252
253/* initialize the trace device */
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700254void trace_dev_init()
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800255{
256 int iomemtype;
257 trace_dev_state *s;
258
259 s = (trace_dev_state *)qemu_mallocz(sizeof(trace_dev_state));
Jack Veenstra9980bbb2009-05-05 10:35:03 -0700260 s->dev.name = "qemu_trace";
261 s->dev.id = -1;
262 s->dev.base = 0; // will be allocated dynamically
263 s->dev.size = 0x2000;
264 s->dev.irq = 0;
265 s->dev.irq_count = 0;
266
267 goldfish_device_add(&s->dev, trace_dev_readfn, trace_dev_writefn, s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800268
269 path[0] = arg[0] = '\0';
270}