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.
6 Like fork, context switch, execve and exit.
7 This code is to complement Jack's tracing facility.
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
17 Signed-off-by: Mike Chan <mike@android.com>
19 [ARM] goldfish: qemutrace: Improved support for tracing thread and process names.
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().
28 Signed-off-by: Jack Veenstra <veenstra@google.com>
29 Signed-off-by: Mike Chan <mike@android.com>
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 ++++++++++++++
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
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
57 + mcr p15, 0, r0, c15, c0, 0 @ signal context switch
61 ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
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.
70 + tristate "Virtual Device for QEMU tracing"
72 + This is a virtual device for QEMU tracing.
74 source "drivers/misc/c2port/Kconfig"
75 source "drivers/misc/eeprom/Kconfig"
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/
86 +++ b/drivers/misc/qemutrace/Makefile
88 +obj-$(CONFIG_QEMU_TRACE) := qemu_trace.o
89 +obj-$(CONFIG_QEMU_TRACE) += qemu_trace_sysfs.o
91 +++ b/drivers/misc/qemutrace/qemu_trace.c
93 +/* drivers/misc/qemutrace/qemu_trace.c
95 + * Copyright (C) 2007-2008 Google, Inc.
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.
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.
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>
119 +#include <asm/sizes.h>
120 +#include "qemu_trace.h"
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
146 +static unsigned char __iomem *qt_base;
147 +static int init_called;
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);
155 +void qemu_trace_start(void)
157 + unsigned long irq_flags;
159 + if (qt_base == NULL)
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);
166 +void qemu_trace_stop(void)
168 + unsigned long irq_flags;
170 + if (qt_base == NULL)
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);
177 +int qemu_trace_get_tracing(void)
180 + if (qt_base != NULL)
181 + val = readl(qt_base + (TRACE_DEV_REG_ENABLE << 2));
185 +void qemu_trace_add_mapping(unsigned int addr, const char *symbol)
187 + unsigned long irq_flags;
189 + if (qt_base == NULL)
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);
199 +void qemu_trace_remove_mapping(unsigned int addr)
201 + unsigned long irq_flags;
203 + if (qt_base == NULL)
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);
211 +/* trace the context switch */
212 +void qemu_trace_cs(struct task_struct *next)
214 + unsigned long irq_flags;
216 + if (qt_base == NULL)
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);
223 +EXPORT_SYMBOL(qemu_trace_cs);
225 +/* trace the execve */
226 +void qemu_trace_execve(int argc, char __user * __user *argv)
228 + unsigned long irq_flags;
229 + char page[PAGE_SIZE];
232 + if (qt_base == NULL)
235 + while (argc-- > 0) {
238 + if (get_user(str, argv ++))
240 + len = strnlen_user(str, PAGE_SIZE);
243 + if (copy_from_user(ptr, str, len))
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);
256 +EXPORT_SYMBOL(qemu_trace_execve);
258 +/* trace the mmap */
259 +void qemu_trace_mmap(struct vm_area_struct *vma)
261 + unsigned long irq_flags;
262 + char page[PAGE_SIZE];
265 + if (qt_base == NULL)
268 + if (vma->vm_file == NULL)
271 + p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
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);
282 +EXPORT_SYMBOL(qemu_trace_mmap);
284 +/* trace the munmap */
285 +void qemu_trace_munmap(unsigned long start, unsigned long end)
287 + unsigned long irq_flags;
289 + if (qt_base == NULL)
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);
297 +EXPORT_SYMBOL(qemu_trace_munmap);
299 +/* trace the fork */
300 +void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags)
302 + unsigned long irq_flags;
304 + spin_lock_irqsave(&qemu_trace_lock, irq_flags);
305 + if (qt_base == NULL) {
306 + if (tb_next >= MAX_INIT_PIDS) {
309 + "QEMU Trace: too many PIDs before "
310 + "device registered ignoring %d\n",
313 + init_pids[tb_next] = task_pid_nr(forked);
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));
321 + writel(task_pid_nr(forked), qt_base + (TRACE_DEV_REG_FORK << 2));
323 + spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
325 +EXPORT_SYMBOL(qemu_trace_fork);
327 +/* trace the exit */
328 +void qemu_trace_exit(int code)
330 + unsigned long irq_flags;
332 + if (qt_base == NULL)
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);
339 +EXPORT_SYMBOL(qemu_trace_exit);
341 +/* trace the thread name */
342 +void qemu_trace_thread_name(const char *name)
344 + unsigned long irq_flags;
346 + if (qt_base == NULL)
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);
353 +EXPORT_SYMBOL(qemu_trace_thread_name);
355 +/* trace the process name */
356 +void qemu_trace_process_name(const char *name)
358 + unsigned long irq_flags;
360 + if (qt_base == NULL)
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);
367 +EXPORT_SYMBOL(qemu_trace_process_name);
369 +static void qemu_trace_pid_exec(struct task_struct *tsk)
371 + unsigned long irq_flags;
372 + char page[PAGE_SIZE];
373 + struct mm_struct *mm = get_task_mm(tsk);
376 + down_read(&mm->mmap_sem);
378 + struct vm_area_struct *vma = mm->mmap;
380 + if ((vma->vm_flags & VM_EXEC) && vma->vm_file) {
382 + p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
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);
392 + vma = vma->vm_next;
395 + up_read(&mm->mmap_sem);
399 +static void qemu_trace_dump_init_threads(void)
401 + unsigned long irq_flags;
404 + for (i = 0; i < tb_next; i++) {
405 + struct task_struct *tsk;
406 + struct pid *pid = find_get_pid(init_pids[i]);
410 + if ((tsk = get_pid_task(pid, PIDTYPE_PID)) != NULL) {
411 + /* first give the pid and name */
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);
419 + /* check if the task has execs */
420 + qemu_trace_pid_exec(tsk);
425 +static int qemu_trace_probe(struct platform_device *pdev)
427 + struct resource *r;
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);
434 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
437 + qt_base = ioremap(r->start, PAGE_SIZE);
438 + printk(KERN_INFO "QEMU TRACE Device: The mapped IO base is %p\n", qt_base);
440 + qemu_trace_dump_init_threads();
445 +static int qemu_trace_remove(struct platform_device *pdev)
452 +static struct platform_driver qemu_trace = {
453 + .probe = qemu_trace_probe,
454 + .remove = qemu_trace_remove,
456 + .name = "qemu_trace"
460 +static int __init qemu_trace_dev_init(void)
463 + ret = platform_driver_register(&qemu_trace);
468 +static void qemu_trace_dev_exit(void)
470 + platform_driver_unregister(&qemu_trace);
474 +module_init(qemu_trace_dev_init);
475 +module_exit(qemu_trace_dev_exit);
477 +MODULE_AUTHOR("Ye Wen <ywen@google.com>");
478 +MODULE_LICENSE("GPL");
480 +++ b/drivers/misc/qemutrace/qemu_trace.h
482 +/* drivers/misc/qemutrace/qemu_trace.h
484 + * Copyright (C) 2007-2008 Google, Inc.
486 + * This software is licensed under the terms of the GNU General Public
488 + * License version 2, as published by the Free Software Foundation, and
489 + * may be copied, distributed, and modified under those terms.
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.
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);
505 +++ b/drivers/misc/qemutrace/qemu_trace_sysfs.c
507 +/* drivers/misc/qemu_sysfs.c
509 + * Copyright (C) 2007-2008 Google, Inc.
510 + * Author: Jack Veenstra
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.
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.
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"
535 +MODULE_DESCRIPTION("Qemu Trace Driver");
536 +MODULE_LICENSE("GPL");
537 +MODULE_VERSION("1.0");
539 +static struct kobject *qemu_trace_kobj;
541 +static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
543 + int val = qemu_trace_get_tracing();
544 + buf[0] = '0' + val;
549 +static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
555 + else if (buf[0] == '1')
556 + qemu_trace_start();
562 +static ssize_t symbol_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
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.
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)
577 + unsigned int addr = 0;
581 + if (n <= 0 || buf == NULL)
583 + for (cp = buf; *cp != ' '; ++cp) {
584 + unsigned int digit;
586 + if (*cp >= '0' && *cp <= '9')
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);
595 + addr = (addr << 4) + digit;
597 + // Move past the space
600 + // Copy the string to a new buffer so that we can replace the newline
603 + sym = kzalloc(len + 1, GFP_KERNEL);
605 + if (sym[len - 1] == '\n')
608 + qemu_trace_add_mapping(addr, sym);
613 +static ssize_t process_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
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.
622 +static ssize_t process_name_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
624 + if (n <= 0 || buf == NULL)
627 + qemu_trace_process_name(buf);
632 +#define qemu_trace_attr(_name) \
633 +static struct kobj_attribute _name##_attr = { \
635 + .name = __stringify(_name), \
638 + .show = _name##_show, \
639 + .store = _name##_store, \
642 +qemu_trace_attr(state);
643 +qemu_trace_attr(symbol);
644 +qemu_trace_attr(process_name);
646 +static struct attribute * qemu_trace_attrs[] = {
649 + &process_name_attr.attr,
653 +static struct attribute_group qemu_trace_attr_group = {
654 + .attrs = qemu_trace_attrs,
657 +static int __init qemu_trace_init(void)
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");
667 + ret = sysfs_create_group(qemu_trace_kobj, &qemu_trace_attr_group);
669 + printk("qemu_trace_init: sysfs_create_group failed\n");
676 + kobject_del(qemu_trace_kobj);
677 + qemu_trace_kobj = NULL;
681 +static void __exit qemu_trace_exit(void)
683 + sysfs_remove_group(qemu_trace_kobj, &qemu_trace_attr_group);
684 + kobject_del(qemu_trace_kobj);
687 +core_initcall(qemu_trace_init);
688 +module_exit(qemu_trace_exit);
692 #include <asm/mmu_context.h>
694 #include "internal.h"
695 +#ifdef CONFIG_QEMU_TRACE
696 + void qemu_trace_thread_name(char *name);
700 char core_pattern[CORENAME_MAX_SIZE] = "core";
701 @@ -922,6 +925,9 @@ void set_task_comm(struct task_struct *t
703 strlcpy(tsk->comm, buf, sizeof(tsk->comm));
705 +#ifdef CONFIG_QEMU_TRACE
706 + qemu_trace_thread_name(buf);
710 int flush_old_exec(struct linux_binprm * bprm)
711 @@ -1245,6 +1251,10 @@ void free_bprm(struct linux_binprm *bprm
715 +#ifdef CONFIG_QEMU_TRACE
716 +extern void qemu_trace_execve(int argc, char __user * __user * argv);
720 * sys_execve() executes a new program.
722 @@ -1324,6 +1334,10 @@ int do_execve(char * filename,
725 current->flags &= ~PF_KTHREAD;
726 +#ifdef CONFIG_QEMU_TRACE
727 + qemu_trace_execve(bprm->argc, argv);
730 retval = search_binary_handler(bprm,regs);
735 @@ -60,6 +60,11 @@ DEFINE_TRACE(sched_process_free);
736 DEFINE_TRACE(sched_process_exit);
737 DEFINE_TRACE(sched_process_wait);
739 +#ifdef CONFIG_QEMU_TRACE
740 +void qemu_trace_thread_name(char *name);
741 +void qemu_trace_exit(int code);
744 static void exit_mm(struct task_struct * tsk);
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);
751 +#ifdef CONFIG_QEMU_TRACE
752 + qemu_trace_thread_name(current->comm);
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)
759 /* causes final put_task_struct in finish_task_switch(). */
760 tsk->state = TASK_DEAD;
762 +#ifdef CONFIG_QEMU_TRACE
763 + /* Emit a trace record for the exit() call. */
764 + qemu_trace_exit(code);
769 /* Avoid "noreturn function does return". */
772 @@ -1323,6 +1323,10 @@ struct task_struct * __cpuinit fork_idle
776 +#ifdef CONFIG_QEMU_TRACE
777 +extern void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags);
781 * Ok, this is the main fork-routine.
783 @@ -1424,6 +1428,10 @@ long do_fork(unsigned long clone_flags,
784 tracehook_report_clone_complete(trace, regs,
787 +#ifdef CONFIG_QEMU_TRACE
788 + qemu_trace_fork(p, clone_flags);
791 if (clone_flags & CLONE_VFORK) {
792 freezer_do_not_count();
793 wait_for_completion(&vfork);
796 @@ -2748,6 +2748,10 @@ asmlinkage void schedule_tail(struct tas
797 put_user(task_pid_vnr(current), current->set_child_tid);
800 +#ifdef CONFIG_QEMU_TRACE
801 +void qemu_trace_cs(struct task_struct *next);
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_);
811 +#ifdef CONFIG_QEMU_TRACE
812 + /* Emit a trace record for the context switch. */
813 + qemu_trace_cs(next);
816 /* Here we just switch the register state and the stack. */
817 switch_to(prev, next, prev);
821 @@ -906,6 +906,11 @@ void vm_stat_account(struct mm_struct *m
823 #endif /* CONFIG_PROC_FS */
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);
831 * The caller must hold down_write(current->mm->mmap_sem).
833 @@ -1212,6 +1217,10 @@ munmap_back:
834 pgoff = vma->vm_pgoff;
835 vm_flags = vma->vm_flags;
837 +#ifdef CONFIG_QEMU_TRACE
838 + qemu_trace_mmap(vma);
841 if (vma_wants_writenotify(vma))
842 vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
844 @@ -1938,6 +1947,10 @@ int do_munmap(struct mm_struct *mm, unsi
845 * Remove the vma's, and unmap the actual pages
847 detach_vmas_to_be_unmapped(mm, vma, prev, end);
849 +#ifdef CONFIG_QEMU_TRACE
850 + qemu_trace_munmap(start, end);
852 unmap_region(mm, vma, prev, start, end);
854 /* Fix up all other VM information */