add support for Comtrend AR5381u.
[lede.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 @@ -1323,6 +1323,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 @@ -1424,6 +1428,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 @@ -2748,6 +2748,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 @@ -2790,6 +2794,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 @@ -906,6 +906,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 @@ -1212,6 +1217,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 @@ -1938,6 +1947,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 */