add the 'goldfish' target, useful for experimenting with virtual phone hardware ...
[openwrt/svn-archive/archive.git] / target / linux / goldfish / patches-2.6.30 / 0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch
1 From fcd69dd4537320a25a294c82362cc7abe4fe773c Mon Sep 17 00:00:00 2001
2 From: Ye Wen <ywen@google.com>
3 Date: Fri, 14 Jul 2006 14:51:45 +0700
4 Subject: [PATCH 129/134] [ARM] goldfish: qemutrace: Kernel instrumentation for tracing the events.
5
6 Like fork, context switch, execve and exit.
7 This code is to complement Jack's tracing facility.
8
9 To turn tracing on:
10 echo 1 > /sysfs/qemu_trace/state
11 To turn tracing off: echo 0 > /sysfs/qemu_trace/state
12 I also added java methods to Debug.java to turn tracing on and off.
13 The kernel driver also supports adding dynamic symbols to the trace.
14 To add a symbol 'foo' with hex address 'abcd1234' to the trace:
15 echo 'abcd1234 foo' > /sysfs/qemu_trace/symbol
16
17 Signed-off-by: Mike Chan <mike@android.com>
18
19 [ARM] goldfish: qemutrace: Improved support for tracing thread and process names.
20
21 Added a new pseudo file /sys/qemu_trace/process_name to allow user
22 programs to add a trace record for a process name change. Removed
23 the tracing of thread and process names from the exit() system call
24 because that was not sufficiently general. Added tracing of thread
25 names in set_task_comm() and daemonize(). Added tracing of the
26 thread group id to fork() and clone().
27
28 Signed-off-by: Jack Veenstra <veenstra@google.com>
29 Signed-off-by: Mike Chan <mike@android.com>
30 ---
31 arch/arm/kernel/entry-armv.S | 5 +
32 drivers/misc/Kconfig | 5 +
33 drivers/misc/Makefile | 1 +
34 drivers/misc/qemutrace/Makefile | 2 +
35 drivers/misc/qemutrace/qemu_trace.c | 386 +++++++++++++++++++++++++++++
36 drivers/misc/qemutrace/qemu_trace.h | 22 ++
37 drivers/misc/qemutrace/qemu_trace_sysfs.c | 182 ++++++++++++++
38 fs/exec.c | 14 +
39 kernel/exit.c | 14 +
40 kernel/fork.c | 8 +
41 kernel/sched.c | 9 +
42 mm/mmap.c | 13 +
43 12 files changed, 661 insertions(+), 0 deletions(-)
44 create mode 100644 drivers/misc/qemutrace/Makefile
45 create mode 100644 drivers/misc/qemutrace/qemu_trace.c
46 create mode 100644 drivers/misc/qemutrace/qemu_trace.h
47 create mode 100644 drivers/misc/qemutrace/qemu_trace_sysfs.c
48
49 --- a/arch/arm/kernel/entry-armv.S
50 +++ b/arch/arm/kernel/entry-armv.S
51 @@ -733,6 +733,11 @@ ENTRY(__switch_to)
52 ldr r0, =thread_notify_head
53 mov r1, #THREAD_NOTIFY_SWITCH
54 bl atomic_notifier_call_chain
55 +#ifdef CONFIG_QEMU_TRACE
56 +/*
57 + mcr p15, 0, r0, c15, c0, 0 @ signal context switch
58 +*/
59 +#endif
60 mov r0, r5
61 ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
62 UNWIND(.fnend )
63 --- a/drivers/misc/Kconfig
64 +++ b/drivers/misc/Kconfig
65 @@ -233,6 +233,11 @@ config ISL29003
66 This driver can also be built as a module. If so, the module
67 will be called isl29003.
68
69 +config QEMU_TRACE
70 + tristate "Virtual Device for QEMU tracing"
71 + ---help---
72 + This is a virtual device for QEMU tracing.
73 +
74 source "drivers/misc/c2port/Kconfig"
75 source "drivers/misc/eeprom/Kconfig"
76
77 --- a/drivers/misc/Makefile
78 +++ b/drivers/misc/Makefile
79 @@ -20,4 +20,5 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
80 obj-$(CONFIG_HP_ILO) += hpilo.o
81 obj-$(CONFIG_ISL29003) += isl29003.o
82 obj-$(CONFIG_C2PORT) += c2port/
83 +obj-$(CONFIG_QEMU_TRACE) += qemutrace/
84 obj-y += eeprom/
85 --- /dev/null
86 +++ b/drivers/misc/qemutrace/Makefile
87 @@ -0,0 +1,2 @@
88 +obj-$(CONFIG_QEMU_TRACE) := qemu_trace.o
89 +obj-$(CONFIG_QEMU_TRACE) += qemu_trace_sysfs.o
90 --- /dev/null
91 +++ b/drivers/misc/qemutrace/qemu_trace.c
92 @@ -0,0 +1,386 @@
93 +/* drivers/misc/qemutrace/qemu_trace.c
94 + *
95 + * Copyright (C) 2007-2008 Google, Inc.
96 + *
97 + * This software is licensed under the terms of the GNU General Public
98 + * License version 2, as published by the Free Software Foundation, and
99 + * may be copied, distributed, and modified under those terms.
100 + *
101 + * This program is distributed in the hope that it will be useful,
102 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
103 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
104 + * GNU General Public License for more details.
105 + *
106 + */
107 +
108 +#include <linux/module.h>
109 +#include <linux/kernel.h>
110 +#include <linux/spinlock.h>
111 +#include <linux/miscdevice.h>
112 +#include <linux/pci.h>
113 +#include <linux/proc_fs.h>
114 +#include <linux/platform_device.h>
115 +#include <linux/mm.h>
116 +#include <linux/sched.h>
117 +#include <asm/uaccess.h>
118 +#include <asm/io.h>
119 +#include <asm/sizes.h>
120 +#include "qemu_trace.h"
121 +
122 +/* trace device registers */
123 +#define TRACE_DEV_REG_SWITCH 0
124 +#define TRACE_DEV_REG_FORK 1
125 +#define TRACE_DEV_REG_EXECVE_PID 2
126 +#define TRACE_DEV_REG_EXECVE_VMSTART 3
127 +#define TRACE_DEV_REG_EXECVE_VMEND 4
128 +#define TRACE_DEV_REG_EXECVE_OFFSET 5
129 +#define TRACE_DEV_REG_EXECVE_EXEPATH 6
130 +#define TRACE_DEV_REG_EXIT 7
131 +#define TRACE_DEV_REG_CMDLINE 8
132 +#define TRACE_DEV_REG_CMDLINE_LEN 9
133 +#define TRACE_DEV_REG_MMAP_EXEPATH 10
134 +#define TRACE_DEV_REG_INIT_PID 11
135 +#define TRACE_DEV_REG_INIT_NAME 12
136 +#define TRACE_DEV_REG_CLONE 13
137 +#define TRACE_DEV_REG_UNMAP_START 14
138 +#define TRACE_DEV_REG_UNMAP_END 15
139 +#define TRACE_DEV_REG_NAME 16
140 +#define TRACE_DEV_REG_TGID 17
141 +#define TRACE_DEV_REG_DYN_SYM 50
142 +#define TRACE_DEV_REG_DYN_SYM_ADDR 51
143 +#define TRACE_DEV_REG_REMOVE_ADDR 52
144 +#define TRACE_DEV_REG_ENABLE 100
145 +
146 +static unsigned char __iomem *qt_base;
147 +static int init_called;
148 +
149 +/* PIDs that start before our device registered */
150 +#define MAX_INIT_PIDS 2048
151 +static int tb_next = 0;
152 +static int init_pids[MAX_INIT_PIDS];
153 +static DEFINE_SPINLOCK(qemu_trace_lock);
154 +
155 +void qemu_trace_start(void)
156 +{
157 + unsigned long irq_flags;
158 +
159 + if (qt_base == NULL)
160 + return;
161 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
162 + writel(1, qt_base + (TRACE_DEV_REG_ENABLE << 2));
163 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
164 +}
165 +
166 +void qemu_trace_stop(void)
167 +{
168 + unsigned long irq_flags;
169 +
170 + if (qt_base == NULL)
171 + return;
172 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
173 + writel(0, qt_base + (TRACE_DEV_REG_ENABLE << 2));
174 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
175 +}
176 +
177 +int qemu_trace_get_tracing(void)
178 +{
179 + int val = 0;
180 + if (qt_base != NULL)
181 + val = readl(qt_base + (TRACE_DEV_REG_ENABLE << 2));
182 + return val;
183 +}
184 +
185 +void qemu_trace_add_mapping(unsigned int addr, const char *symbol)
186 +{
187 + unsigned long irq_flags;
188 +
189 + if (qt_base == NULL)
190 + return;
191 +
192 + /* Write the address first, then the symbol name. */
193 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
194 + writel(addr, qt_base + (TRACE_DEV_REG_DYN_SYM_ADDR << 2));
195 + writel(symbol, qt_base + (TRACE_DEV_REG_DYN_SYM << 2));
196 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
197 +}
198 +
199 +void qemu_trace_remove_mapping(unsigned int addr)
200 +{
201 + unsigned long irq_flags;
202 +
203 + if (qt_base == NULL)
204 + return;
205 +
206 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
207 + writel(addr, qt_base + (TRACE_DEV_REG_REMOVE_ADDR << 2));
208 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
209 +}
210 +
211 +/* trace the context switch */
212 +void qemu_trace_cs(struct task_struct *next)
213 +{
214 + unsigned long irq_flags;
215 +
216 + if (qt_base == NULL)
217 + return;
218 +
219 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
220 + writel(task_pid_nr(next), qt_base);
221 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
222 +}
223 +EXPORT_SYMBOL(qemu_trace_cs);
224 +
225 +/* trace the execve */
226 +void qemu_trace_execve(int argc, char __user * __user *argv)
227 +{
228 + unsigned long irq_flags;
229 + char page[PAGE_SIZE];
230 + char *ptr = page;
231 +
232 + if (qt_base == NULL)
233 + return;
234 +
235 + while (argc-- > 0) {
236 + char __user *str;
237 + int len;
238 + if (get_user(str, argv ++))
239 + return;
240 + len = strnlen_user(str, PAGE_SIZE);
241 + if (len == 0)
242 + return;
243 + if (copy_from_user(ptr, str, len))
244 + return;
245 + ptr += len;
246 + }
247 +
248 + if (ptr > page) {
249 + int len = ptr - page;
250 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
251 + writel(len, qt_base + (TRACE_DEV_REG_CMDLINE_LEN << 2));
252 + writel(page, qt_base + (TRACE_DEV_REG_CMDLINE << 2));
253 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
254 + }
255 +}
256 +EXPORT_SYMBOL(qemu_trace_execve);
257 +
258 +/* trace the mmap */
259 +void qemu_trace_mmap(struct vm_area_struct *vma)
260 +{
261 + unsigned long irq_flags;
262 + char page[PAGE_SIZE];
263 + char *p;
264 +
265 + if (qt_base == NULL)
266 + return;
267 +
268 + if (vma->vm_file == NULL)
269 + return;
270 +
271 + p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
272 + if (IS_ERR(p))
273 + return;
274 +
275 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
276 + writel(vma->vm_start, qt_base + (TRACE_DEV_REG_EXECVE_VMSTART << 2));
277 + writel(vma->vm_end, qt_base + (TRACE_DEV_REG_EXECVE_VMEND << 2));
278 + writel(vma->vm_pgoff * PAGE_SIZE, qt_base + (TRACE_DEV_REG_EXECVE_OFFSET << 2));
279 + writel(p, qt_base + (TRACE_DEV_REG_MMAP_EXEPATH << 2));
280 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
281 +}
282 +EXPORT_SYMBOL(qemu_trace_mmap);
283 +
284 +/* trace the munmap */
285 +void qemu_trace_munmap(unsigned long start, unsigned long end)
286 +{
287 + unsigned long irq_flags;
288 +
289 + if (qt_base == NULL)
290 + return;
291 +
292 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
293 + writel(start, qt_base + (TRACE_DEV_REG_UNMAP_START << 2));
294 + writel(end, qt_base + (TRACE_DEV_REG_UNMAP_END << 2));
295 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
296 +}
297 +EXPORT_SYMBOL(qemu_trace_munmap);
298 +
299 +/* trace the fork */
300 +void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags)
301 +{
302 + unsigned long irq_flags;
303 +
304 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
305 + if (qt_base == NULL) {
306 + if (tb_next >= MAX_INIT_PIDS) {
307 + if (!init_called)
308 + printk(KERN_ERR
309 + "QEMU Trace: too many PIDs before "
310 + "device registered ignoring %d\n",
311 + forked->pid);
312 + } else {
313 + init_pids[tb_next] = task_pid_nr(forked);
314 + tb_next++;
315 + }
316 + } else {
317 + writel(task_tgid_nr(forked), qt_base + (TRACE_DEV_REG_TGID << 2));
318 + if (clone_flags & CLONE_VM)
319 + writel(task_pid_nr(forked), qt_base + (TRACE_DEV_REG_CLONE << 2));
320 + else
321 + writel(task_pid_nr(forked), qt_base + (TRACE_DEV_REG_FORK << 2));
322 + }
323 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
324 +}
325 +EXPORT_SYMBOL(qemu_trace_fork);
326 +
327 +/* trace the exit */
328 +void qemu_trace_exit(int code)
329 +{
330 + unsigned long irq_flags;
331 +
332 + if (qt_base == NULL)
333 + return;
334 +
335 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
336 + writel(code, qt_base + (TRACE_DEV_REG_EXIT << 2));
337 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
338 +}
339 +EXPORT_SYMBOL(qemu_trace_exit);
340 +
341 +/* trace the thread name */
342 +void qemu_trace_thread_name(const char *name)
343 +{
344 + unsigned long irq_flags;
345 +
346 + if (qt_base == NULL)
347 + return;
348 +
349 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
350 + writel(name, qt_base + (TRACE_DEV_REG_NAME << 2));
351 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
352 +}
353 +EXPORT_SYMBOL(qemu_trace_thread_name);
354 +
355 +/* trace the process name */
356 +void qemu_trace_process_name(const char *name)
357 +{
358 + unsigned long irq_flags;
359 +
360 + if (qt_base == NULL)
361 + return;
362 +
363 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
364 + writel(name, qt_base + (TRACE_DEV_REG_NAME << 2));
365 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
366 +}
367 +EXPORT_SYMBOL(qemu_trace_process_name);
368 +
369 +static void qemu_trace_pid_exec(struct task_struct *tsk)
370 +{
371 + unsigned long irq_flags;
372 + char page[PAGE_SIZE];
373 + struct mm_struct *mm = get_task_mm(tsk);
374 + if (mm == NULL)
375 + return;
376 + down_read(&mm->mmap_sem);
377 + {
378 + struct vm_area_struct *vma = mm->mmap;
379 + while (vma) {
380 + if ((vma->vm_flags & VM_EXEC) && vma->vm_file) {
381 + char *p;
382 + p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
383 + if (!IS_ERR(p)) {
384 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
385 + writel(vma->vm_start, qt_base + (TRACE_DEV_REG_EXECVE_VMSTART << 2));
386 + writel(vma->vm_end, qt_base + (TRACE_DEV_REG_EXECVE_VMEND << 2));
387 + writel(vma->vm_pgoff * PAGE_SIZE, qt_base + (TRACE_DEV_REG_EXECVE_OFFSET << 2));
388 + writel(p, qt_base + (TRACE_DEV_REG_EXECVE_EXEPATH << 2));
389 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
390 + }
391 + }
392 + vma = vma->vm_next;
393 + }
394 + }
395 + up_read(&mm->mmap_sem);
396 + mmput(mm);
397 +}
398 +
399 +static void qemu_trace_dump_init_threads(void)
400 +{
401 + unsigned long irq_flags;
402 + int i;
403 +
404 + for (i = 0; i < tb_next; i++) {
405 + struct task_struct *tsk;
406 + struct pid *pid = find_get_pid(init_pids[i]);
407 + if (pid == NULL)
408 + continue;
409 +
410 + if ((tsk = get_pid_task(pid, PIDTYPE_PID)) != NULL) {
411 + /* first give the pid and name */
412 + task_lock(tsk);
413 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
414 + writel(task_tgid_nr(tsk), qt_base + (TRACE_DEV_REG_TGID << 2));
415 + writel(task_pid_nr(tsk), qt_base + (TRACE_DEV_REG_INIT_PID << 2));
416 + writel(tsk->comm, qt_base + (TRACE_DEV_REG_INIT_NAME << 2));
417 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
418 + task_unlock(tsk);
419 + /* check if the task has execs */
420 + qemu_trace_pid_exec(tsk);
421 + }
422 + }
423 +}
424 +
425 +static int qemu_trace_probe(struct platform_device *pdev)
426 +{
427 + struct resource *r;
428 +
429 + /* not thread safe, but this should not happen */
430 + if (qt_base != NULL) {
431 + printk(KERN_ERR "QEMU TRACE Device: already mapped at %p\n", qt_base);
432 + return -ENODEV;
433 + }
434 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
435 + if (r == NULL)
436 + return -EINVAL;
437 + qt_base = ioremap(r->start, PAGE_SIZE);
438 + printk(KERN_INFO "QEMU TRACE Device: The mapped IO base is %p\n", qt_base);
439 +
440 + qemu_trace_dump_init_threads();
441 +
442 + return 0;
443 +}
444 +
445 +static int qemu_trace_remove(struct platform_device *pdev)
446 +{
447 + iounmap(qt_base);
448 + qt_base = NULL;
449 + return 0;
450 +}
451 +
452 +static struct platform_driver qemu_trace = {
453 + .probe = qemu_trace_probe,
454 + .remove = qemu_trace_remove,
455 + .driver = {
456 + .name = "qemu_trace"
457 + }
458 +};
459 +
460 +static int __init qemu_trace_dev_init(void)
461 +{
462 + int ret;
463 + ret = platform_driver_register(&qemu_trace);
464 + init_called = 1;
465 + return ret;
466 +}
467 +
468 +static void qemu_trace_dev_exit(void)
469 +{
470 + platform_driver_unregister(&qemu_trace);
471 +}
472 +
473 +
474 +module_init(qemu_trace_dev_init);
475 +module_exit(qemu_trace_dev_exit);
476 +
477 +MODULE_AUTHOR("Ye Wen <ywen@google.com>");
478 +MODULE_LICENSE("GPL");
479 --- /dev/null
480 +++ b/drivers/misc/qemutrace/qemu_trace.h
481 @@ -0,0 +1,22 @@
482 +/* drivers/misc/qemutrace/qemu_trace.h
483 + *
484 + * Copyright (C) 2007-2008 Google, Inc.
485 + *
486 + * This software is licensed under the terms of the GNU General Public
487 + *
488 + * License version 2, as published by the Free Software Foundation, and
489 + * may be copied, distributed, and modified under those terms.
490 + *
491 + * This program is distributed in the hope that it will be useful,
492 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
493 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
494 + * GNU General Public License for more details.
495 + *
496 + */
497 +
498 +void qemu_trace_start(void);
499 +void qemu_trace_stop(void);
500 +int qemu_trace_get_tracing(void);
501 +void qemu_trace_add_mapping(unsigned int addr, const char *symbol);
502 +void qemu_trace_remove_mapping(unsigned int addr);
503 +void qemu_trace_process_name(const char *name);
504 --- /dev/null
505 +++ b/drivers/misc/qemutrace/qemu_trace_sysfs.c
506 @@ -0,0 +1,182 @@
507 +/* drivers/misc/qemu_sysfs.c
508 + *
509 + * Copyright (C) 2007-2008 Google, Inc.
510 + * Author: Jack Veenstra
511 + *
512 + * This software is licensed under the terms of the GNU General Public
513 + * License version 2, as published by the Free Software Foundation, and
514 + * may be copied, distributed, and modified under those terms.
515 + *
516 + * This program is distributed in the hope that it will be useful,
517 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
518 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
519 + * GNU General Public License for more details.
520 + *
521 + */
522 +
523 +#include <linux/list.h>
524 +#include <linux/module.h>
525 +#include <linux/miscdevice.h>
526 +#include <linux/sysdev.h>
527 +#include <linux/fs.h>
528 +#include <linux/poll.h>
529 +#include <linux/interrupt.h>
530 +#include <linux/delay.h>
531 +#include <linux/clk.h>
532 +#include <linux/wait.h>
533 +#include "qemu_trace.h"
534 +
535 +MODULE_DESCRIPTION("Qemu Trace Driver");
536 +MODULE_LICENSE("GPL");
537 +MODULE_VERSION("1.0");
538 +
539 +static struct kobject *qemu_trace_kobj;
540 +
541 +static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
542 +{
543 + int val = qemu_trace_get_tracing();
544 + buf[0] = '0' + val;
545 + buf[1] = '\n';
546 + return 2;
547 +}
548 +
549 +static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
550 +{
551 + if (n <= 0)
552 + return -EINVAL;
553 + if (buf[0] == '0')
554 + qemu_trace_stop();
555 + else if (buf[0] == '1')
556 + qemu_trace_start();
557 + else
558 + return -EINVAL;
559 + return n;
560 +}
561 +
562 +static ssize_t symbol_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
563 +{
564 + return 0;
565 +}
566 +
567 +// We are expecting a string of the form "addr symbol" where 'addr' is a hex address
568 +// (without the leading '0x') and symbol is a newline-terminated string. This symbol
569 +// with its corresponding address will be added to the trace file.
570 +//
571 +// To remove the mapping for (addr, symbol) in the trace file, write just the
572 +// address. As before, the address is in hex without the leading '0x'. It can
573 +// be newline-terminated or zero-terminated.
574 +static ssize_t symbol_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
575 +{
576 + const char *cp;
577 + unsigned int addr = 0;
578 + int len;
579 + char *sym;
580 +
581 + if (n <= 0 || buf == NULL)
582 + return -EINVAL;
583 + for (cp = buf; *cp != ' '; ++cp) {
584 + unsigned int digit;
585 +
586 + if (*cp >= '0' && *cp <= '9')
587 + digit = *cp - '0';
588 + else if (*cp >= 'a' && *cp <= 'f')
589 + digit = *cp - 'a' + 10;
590 + else if (*cp == 0 || *cp == '\n') {
591 + qemu_trace_remove_mapping(addr);
592 + return n;
593 + } else
594 + return -EINVAL;
595 + addr = (addr << 4) + digit;
596 + }
597 + // Move past the space
598 + cp += 1;
599 +
600 + // Copy the string to a new buffer so that we can replace the newline
601 + // with '\0'.
602 + len = strlen(cp);
603 + sym = kzalloc(len + 1, GFP_KERNEL);
604 + strcpy(sym, cp);
605 + if (sym[len - 1] == '\n')
606 + sym[len - 1] = 0;
607 +
608 + qemu_trace_add_mapping(addr, sym);
609 + kfree(sym);
610 + return n;
611 +}
612 +
613 +static ssize_t process_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
614 +{
615 + return 0;
616 +}
617 +
618 +/* This expects a string that is the process name. If the string contains
619 + * a trailing newline, that is removed in the emulator tracing code because
620 + * it is simpler to do it there.
621 + */
622 +static ssize_t process_name_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
623 +{
624 + if (n <= 0 || buf == NULL)
625 + return -EINVAL;
626 +
627 + qemu_trace_process_name(buf);
628 + return n;
629 +}
630 +
631 +
632 +#define qemu_trace_attr(_name) \
633 +static struct kobj_attribute _name##_attr = { \
634 + .attr = { \
635 + .name = __stringify(_name), \
636 + .mode = 0666, \
637 + }, \
638 + .show = _name##_show, \
639 + .store = _name##_store, \
640 +}
641 +
642 +qemu_trace_attr(state);
643 +qemu_trace_attr(symbol);
644 +qemu_trace_attr(process_name);
645 +
646 +static struct attribute * qemu_trace_attrs[] = {
647 + &state_attr.attr,
648 + &symbol_attr.attr,
649 + &process_name_attr.attr,
650 + NULL,
651 +};
652 +
653 +static struct attribute_group qemu_trace_attr_group = {
654 + .attrs = qemu_trace_attrs,
655 +};
656 +
657 +static int __init qemu_trace_init(void)
658 +{
659 + int ret;
660 +
661 + qemu_trace_kobj = kobject_create_and_add("qemu_trace", NULL);
662 + if (qemu_trace_kobj == NULL) {
663 + printk("qemu_trace_init: kobject_create_and_add failed\n");
664 + ret = -ENOMEM;
665 + return ret;
666 + }
667 + ret = sysfs_create_group(qemu_trace_kobj, &qemu_trace_attr_group);
668 + if (ret) {
669 + printk("qemu_trace_init: sysfs_create_group failed\n");
670 + goto err;
671 + }
672 +
673 + return 0;
674 +
675 +err:
676 + kobject_del(qemu_trace_kobj);
677 + qemu_trace_kobj = NULL;
678 + return ret;
679 +}
680 +
681 +static void __exit qemu_trace_exit(void)
682 +{
683 + sysfs_remove_group(qemu_trace_kobj, &qemu_trace_attr_group);
684 + kobject_del(qemu_trace_kobj);
685 +}
686 +
687 +core_initcall(qemu_trace_init);
688 +module_exit(qemu_trace_exit);
689 --- a/fs/exec.c
690 +++ b/fs/exec.c
691 @@ -59,6 +59,9 @@
692 #include <asm/mmu_context.h>
693 #include <asm/tlb.h>
694 #include "internal.h"
695 +#ifdef CONFIG_QEMU_TRACE
696 + void qemu_trace_thread_name(char *name);
697 +#endif
698
699 int core_uses_pid;
700 char core_pattern[CORENAME_MAX_SIZE] = "core";
701 @@ -922,6 +925,9 @@ void set_task_comm(struct task_struct *t
702 task_lock(tsk);
703 strlcpy(tsk->comm, buf, sizeof(tsk->comm));
704 task_unlock(tsk);
705 +#ifdef CONFIG_QEMU_TRACE
706 + qemu_trace_thread_name(buf);
707 +#endif
708 }
709
710 int flush_old_exec(struct linux_binprm * bprm)
711 @@ -1245,6 +1251,10 @@ void free_bprm(struct linux_binprm *bprm
712 kfree(bprm);
713 }
714
715 +#ifdef CONFIG_QEMU_TRACE
716 +extern void qemu_trace_execve(int argc, char __user * __user * argv);
717 +#endif
718 +
719 /*
720 * sys_execve() executes a new program.
721 */
722 @@ -1324,6 +1334,10 @@ int do_execve(char * filename,
723 goto out;
724
725 current->flags &= ~PF_KTHREAD;
726 +#ifdef CONFIG_QEMU_TRACE
727 + qemu_trace_execve(bprm->argc, argv);
728 +#endif
729 +
730 retval = search_binary_handler(bprm,regs);
731 if (retval < 0)
732 goto out;
733 --- a/kernel/exit.c
734 +++ b/kernel/exit.c
735 @@ -60,6 +60,11 @@ DEFINE_TRACE(sched_process_free);
736 DEFINE_TRACE(sched_process_exit);
737 DEFINE_TRACE(sched_process_wait);
738
739 +#ifdef CONFIG_QEMU_TRACE
740 +void qemu_trace_thread_name(char *name);
741 +void qemu_trace_exit(int code);
742 +#endif
743 +
744 static void exit_mm(struct task_struct * tsk);
745
746 static void __unhash_process(struct task_struct *p)
747 @@ -426,6 +431,9 @@ void daemonize(const char *name, ...)
748 va_start(args, name);
749 vsnprintf(current->comm, sizeof(current->comm), name, args);
750 va_end(args);
751 +#ifdef CONFIG_QEMU_TRACE
752 + qemu_trace_thread_name(current->comm);
753 +#endif
754
755 /*
756 * If we were started as result of loading a module, close all of the
757 @@ -1012,6 +1020,12 @@ NORET_TYPE void do_exit(long code)
758 preempt_disable();
759 /* causes final put_task_struct in finish_task_switch(). */
760 tsk->state = TASK_DEAD;
761 +
762 +#ifdef CONFIG_QEMU_TRACE
763 + /* Emit a trace record for the exit() call. */
764 + qemu_trace_exit(code);
765 +#endif
766 +
767 schedule();
768 BUG();
769 /* Avoid "noreturn function does return". */
770 --- a/kernel/fork.c
771 +++ b/kernel/fork.c
772 @@ -1333,6 +1333,10 @@ struct task_struct * __cpuinit fork_idle
773 return task;
774 }
775
776 +#ifdef CONFIG_QEMU_TRACE
777 +extern void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags);
778 +#endif
779 +
780 /*
781 * Ok, this is the main fork-routine.
782 *
783 @@ -1434,6 +1438,10 @@ long do_fork(unsigned long clone_flags,
784 tracehook_report_clone_complete(trace, regs,
785 clone_flags, nr, p);
786
787 +#ifdef CONFIG_QEMU_TRACE
788 + qemu_trace_fork(p, clone_flags);
789 +#endif
790 +
791 if (clone_flags & CLONE_VFORK) {
792 freezer_do_not_count();
793 wait_for_completion(&vfork);
794 --- a/kernel/sched.c
795 +++ b/kernel/sched.c
796 @@ -2747,6 +2747,10 @@ asmlinkage void schedule_tail(struct tas
797 put_user(task_pid_vnr(current), current->set_child_tid);
798 }
799
800 +#ifdef CONFIG_QEMU_TRACE
801 +void qemu_trace_cs(struct task_struct *next);
802 +#endif
803 +
804 /*
805 * context_switch - switch to the new MM and the new
806 * thread's register state.
807 @@ -2789,6 +2793,11 @@ context_switch(struct rq *rq, struct tas
808 spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
809 #endif
810
811 +#ifdef CONFIG_QEMU_TRACE
812 + /* Emit a trace record for the context switch. */
813 + qemu_trace_cs(next);
814 +#endif
815 +
816 /* Here we just switch the register state and the stack. */
817 switch_to(prev, next, prev);
818
819 --- a/mm/mmap.c
820 +++ b/mm/mmap.c
821 @@ -903,6 +903,11 @@ void vm_stat_account(struct mm_struct *m
822 }
823 #endif /* CONFIG_PROC_FS */
824
825 +#ifdef CONFIG_QEMU_TRACE
826 +extern void qemu_trace_mmap(struct vm_area_struct * vma);
827 +extern void qemu_trace_munmap(unsigned long start, unsigned long end);
828 +#endif
829 +
830 /*
831 * The caller must hold down_write(current->mm->mmap_sem).
832 */
833 @@ -1209,6 +1214,10 @@ munmap_back:
834 pgoff = vma->vm_pgoff;
835 vm_flags = vma->vm_flags;
836
837 +#ifdef CONFIG_QEMU_TRACE
838 + qemu_trace_mmap(vma);
839 +#endif
840 +
841 if (vma_wants_writenotify(vma))
842 vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
843
844 @@ -1935,6 +1944,10 @@ int do_munmap(struct mm_struct *mm, unsi
845 * Remove the vma's, and unmap the actual pages
846 */
847 detach_vmas_to_be_unmapped(mm, vma, prev, end);
848 +
849 +#ifdef CONFIG_QEMU_TRACE
850 + qemu_trace_munmap(start, end);
851 +#endif
852 unmap_region(mm, vma, prev, start, end);
853
854 /* Fix up all other VM information */