summaryrefslogtreecommitdiff
path: root/target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch')
-rw-r--r--target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch854
1 files changed, 0 insertions, 854 deletions
diff --git a/target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch b/target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch
deleted file mode 100644
index b31ca03cf0..0000000000
--- a/target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch
+++ /dev/null
@@ -1,854 +0,0 @@
-From fcd69dd4537320a25a294c82362cc7abe4fe773c Mon Sep 17 00:00:00 2001
-From: Ye Wen <ywen@google.com>
-Date: Fri, 14 Jul 2006 14:51:45 +0700
-Subject: [PATCH 129/134] [ARM] goldfish: qemutrace: Kernel instrumentation for tracing the events.
-
-Like fork, context switch, execve and exit.
-This code is to complement Jack's tracing facility.
-
-To turn tracing on:
-echo 1 > /sysfs/qemu_trace/state
-To turn tracing off: echo 0 > /sysfs/qemu_trace/state
-I also added java methods to Debug.java to turn tracing on and off.
-The kernel driver also supports adding dynamic symbols to the trace.
-To add a symbol 'foo' with hex address 'abcd1234' to the trace:
-echo 'abcd1234 foo' > /sysfs/qemu_trace/symbol
-
-Signed-off-by: Mike Chan <mike@android.com>
-
-[ARM] goldfish: qemutrace: Improved support for tracing thread and process names.
-
-Added a new pseudo file /sys/qemu_trace/process_name to allow user
-programs to add a trace record for a process name change. Removed
-the tracing of thread and process names from the exit() system call
-because that was not sufficiently general. Added tracing of thread
-names in set_task_comm() and daemonize(). Added tracing of the
-thread group id to fork() and clone().
-
-Signed-off-by: Jack Veenstra <veenstra@google.com>
-Signed-off-by: Mike Chan <mike@android.com>
----
- arch/arm/kernel/entry-armv.S | 5 +
- drivers/misc/Kconfig | 5 +
- drivers/misc/Makefile | 1 +
- drivers/misc/qemutrace/Makefile | 2 +
- drivers/misc/qemutrace/qemu_trace.c | 386 +++++++++++++++++++++++++++++
- drivers/misc/qemutrace/qemu_trace.h | 22 ++
- drivers/misc/qemutrace/qemu_trace_sysfs.c | 182 ++++++++++++++
- fs/exec.c | 14 +
- kernel/exit.c | 14 +
- kernel/fork.c | 8 +
- kernel/sched.c | 9 +
- mm/mmap.c | 13 +
- 12 files changed, 661 insertions(+), 0 deletions(-)
- create mode 100644 drivers/misc/qemutrace/Makefile
- create mode 100644 drivers/misc/qemutrace/qemu_trace.c
- create mode 100644 drivers/misc/qemutrace/qemu_trace.h
- create mode 100644 drivers/misc/qemutrace/qemu_trace_sysfs.c
-
---- a/arch/arm/kernel/entry-armv.S
-+++ b/arch/arm/kernel/entry-armv.S
-@@ -733,6 +733,11 @@ ENTRY(__switch_to)
- ldr r0, =thread_notify_head
- mov r1, #THREAD_NOTIFY_SWITCH
- bl atomic_notifier_call_chain
-+#ifdef CONFIG_QEMU_TRACE
-+/*
-+ mcr p15, 0, r0, c15, c0, 0 @ signal context switch
-+*/
-+#endif
- mov r0, r5
- ldmia r4, {r4 - sl, fp, sp, pc} @ Load all regs saved previously
- UNWIND(.fnend )
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -233,6 +233,11 @@ config ISL29003
- This driver can also be built as a module. If so, the module
- will be called isl29003.
-
-+config QEMU_TRACE
-+ tristate "Virtual Device for QEMU tracing"
-+ ---help---
-+ This is a virtual device for QEMU tracing.
-+
- source "drivers/misc/c2port/Kconfig"
- source "drivers/misc/eeprom/Kconfig"
-
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -20,4 +20,5 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
- obj-$(CONFIG_HP_ILO) += hpilo.o
- obj-$(CONFIG_ISL29003) += isl29003.o
- obj-$(CONFIG_C2PORT) += c2port/
-+obj-$(CONFIG_QEMU_TRACE) += qemutrace/
- obj-y += eeprom/
---- /dev/null
-+++ b/drivers/misc/qemutrace/Makefile
-@@ -0,0 +1,2 @@
-+obj-$(CONFIG_QEMU_TRACE) := qemu_trace.o
-+obj-$(CONFIG_QEMU_TRACE) += qemu_trace_sysfs.o
---- /dev/null
-+++ b/drivers/misc/qemutrace/qemu_trace.c
-@@ -0,0 +1,386 @@
-+/* drivers/misc/qemutrace/qemu_trace.c
-+ *
-+ * Copyright (C) 2007-2008 Google, Inc.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/spinlock.h>
-+#include <linux/miscdevice.h>
-+#include <linux/pci.h>
-+#include <linux/proc_fs.h>
-+#include <linux/platform_device.h>
-+#include <linux/mm.h>
-+#include <linux/sched.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/sizes.h>
-+#include "qemu_trace.h"
-+
-+/* trace device registers */
-+#define TRACE_DEV_REG_SWITCH 0
-+#define TRACE_DEV_REG_FORK 1
-+#define TRACE_DEV_REG_EXECVE_PID 2
-+#define TRACE_DEV_REG_EXECVE_VMSTART 3
-+#define TRACE_DEV_REG_EXECVE_VMEND 4
-+#define TRACE_DEV_REG_EXECVE_OFFSET 5
-+#define TRACE_DEV_REG_EXECVE_EXEPATH 6
-+#define TRACE_DEV_REG_EXIT 7
-+#define TRACE_DEV_REG_CMDLINE 8
-+#define TRACE_DEV_REG_CMDLINE_LEN 9
-+#define TRACE_DEV_REG_MMAP_EXEPATH 10
-+#define TRACE_DEV_REG_INIT_PID 11
-+#define TRACE_DEV_REG_INIT_NAME 12
-+#define TRACE_DEV_REG_CLONE 13
-+#define TRACE_DEV_REG_UNMAP_START 14
-+#define TRACE_DEV_REG_UNMAP_END 15
-+#define TRACE_DEV_REG_NAME 16
-+#define TRACE_DEV_REG_TGID 17
-+#define TRACE_DEV_REG_DYN_SYM 50
-+#define TRACE_DEV_REG_DYN_SYM_ADDR 51
-+#define TRACE_DEV_REG_REMOVE_ADDR 52
-+#define TRACE_DEV_REG_ENABLE 100
-+
-+static unsigned char __iomem *qt_base;
-+static int init_called;
-+
-+/* PIDs that start before our device registered */
-+#define MAX_INIT_PIDS 2048
-+static int tb_next = 0;
-+static int init_pids[MAX_INIT_PIDS];
-+static DEFINE_SPINLOCK(qemu_trace_lock);
-+
-+void qemu_trace_start(void)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(1, qt_base + (TRACE_DEV_REG_ENABLE << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+
-+void qemu_trace_stop(void)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(0, qt_base + (TRACE_DEV_REG_ENABLE << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+
-+int qemu_trace_get_tracing(void)
-+{
-+ int val = 0;
-+ if (qt_base != NULL)
-+ val = readl(qt_base + (TRACE_DEV_REG_ENABLE << 2));
-+ return val;
-+}
-+
-+void qemu_trace_add_mapping(unsigned int addr, const char *symbol)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ /* Write the address first, then the symbol name. */
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(addr, qt_base + (TRACE_DEV_REG_DYN_SYM_ADDR << 2));
-+ writel(symbol, qt_base + (TRACE_DEV_REG_DYN_SYM << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+
-+void qemu_trace_remove_mapping(unsigned int addr)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(addr, qt_base + (TRACE_DEV_REG_REMOVE_ADDR << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+
-+/* trace the context switch */
-+void qemu_trace_cs(struct task_struct *next)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(task_pid_nr(next), qt_base);
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_cs);
-+
-+/* trace the execve */
-+void qemu_trace_execve(int argc, char __user * __user *argv)
-+{
-+ unsigned long irq_flags;
-+ char page[PAGE_SIZE];
-+ char *ptr = page;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ while (argc-- > 0) {
-+ char __user *str;
-+ int len;
-+ if (get_user(str, argv ++))
-+ return;
-+ len = strnlen_user(str, PAGE_SIZE);
-+ if (len == 0)
-+ return;
-+ if (copy_from_user(ptr, str, len))
-+ return;
-+ ptr += len;
-+ }
-+
-+ if (ptr > page) {
-+ int len = ptr - page;
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(len, qt_base + (TRACE_DEV_REG_CMDLINE_LEN << 2));
-+ writel(page, qt_base + (TRACE_DEV_REG_CMDLINE << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+ }
-+}
-+EXPORT_SYMBOL(qemu_trace_execve);
-+
-+/* trace the mmap */
-+void qemu_trace_mmap(struct vm_area_struct *vma)
-+{
-+ unsigned long irq_flags;
-+ char page[PAGE_SIZE];
-+ char *p;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ if (vma->vm_file == NULL)
-+ return;
-+
-+ p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
-+ if (IS_ERR(p))
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(vma->vm_start, qt_base + (TRACE_DEV_REG_EXECVE_VMSTART << 2));
-+ writel(vma->vm_end, qt_base + (TRACE_DEV_REG_EXECVE_VMEND << 2));
-+ writel(vma->vm_pgoff * PAGE_SIZE, qt_base + (TRACE_DEV_REG_EXECVE_OFFSET << 2));
-+ writel(p, qt_base + (TRACE_DEV_REG_MMAP_EXEPATH << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_mmap);
-+
-+/* trace the munmap */
-+void qemu_trace_munmap(unsigned long start, unsigned long end)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(start, qt_base + (TRACE_DEV_REG_UNMAP_START << 2));
-+ writel(end, qt_base + (TRACE_DEV_REG_UNMAP_END << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_munmap);
-+
-+/* trace the fork */
-+void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags)
-+{
-+ unsigned long irq_flags;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ if (qt_base == NULL) {
-+ if (tb_next >= MAX_INIT_PIDS) {
-+ if (!init_called)
-+ printk(KERN_ERR
-+ "QEMU Trace: too many PIDs before "
-+ "device registered ignoring %d\n",
-+ forked->pid);
-+ } else {
-+ init_pids[tb_next] = task_pid_nr(forked);
-+ tb_next++;
-+ }
-+ } else {
-+ writel(task_tgid_nr(forked), qt_base + (TRACE_DEV_REG_TGID << 2));
-+ if (clone_flags & CLONE_VM)
-+ writel(task_pid_nr(forked), qt_base + (TRACE_DEV_REG_CLONE << 2));
-+ else
-+ writel(task_pid_nr(forked), qt_base + (TRACE_DEV_REG_FORK << 2));
-+ }
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_fork);
-+
-+/* trace the exit */
-+void qemu_trace_exit(int code)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(code, qt_base + (TRACE_DEV_REG_EXIT << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_exit);
-+
-+/* trace the thread name */
-+void qemu_trace_thread_name(const char *name)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(name, qt_base + (TRACE_DEV_REG_NAME << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_thread_name);
-+
-+/* trace the process name */
-+void qemu_trace_process_name(const char *name)
-+{
-+ unsigned long irq_flags;
-+
-+ if (qt_base == NULL)
-+ return;
-+
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(name, qt_base + (TRACE_DEV_REG_NAME << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+}
-+EXPORT_SYMBOL(qemu_trace_process_name);
-+
-+static void qemu_trace_pid_exec(struct task_struct *tsk)
-+{
-+ unsigned long irq_flags;
-+ char page[PAGE_SIZE];
-+ struct mm_struct *mm = get_task_mm(tsk);
-+ if (mm == NULL)
-+ return;
-+ down_read(&mm->mmap_sem);
-+ {
-+ struct vm_area_struct *vma = mm->mmap;
-+ while (vma) {
-+ if ((vma->vm_flags & VM_EXEC) && vma->vm_file) {
-+ char *p;
-+ p = d_path(&vma->vm_file->f_path, page, PAGE_SIZE);
-+ if (!IS_ERR(p)) {
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(vma->vm_start, qt_base + (TRACE_DEV_REG_EXECVE_VMSTART << 2));
-+ writel(vma->vm_end, qt_base + (TRACE_DEV_REG_EXECVE_VMEND << 2));
-+ writel(vma->vm_pgoff * PAGE_SIZE, qt_base + (TRACE_DEV_REG_EXECVE_OFFSET << 2));
-+ writel(p, qt_base + (TRACE_DEV_REG_EXECVE_EXEPATH << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+ }
-+ }
-+ vma = vma->vm_next;
-+ }
-+ }
-+ up_read(&mm->mmap_sem);
-+ mmput(mm);
-+}
-+
-+static void qemu_trace_dump_init_threads(void)
-+{
-+ unsigned long irq_flags;
-+ int i;
-+
-+ for (i = 0; i < tb_next; i++) {
-+ struct task_struct *tsk;
-+ struct pid *pid = find_get_pid(init_pids[i]);
-+ if (pid == NULL)
-+ continue;
-+
-+ if ((tsk = get_pid_task(pid, PIDTYPE_PID)) != NULL) {
-+ /* first give the pid and name */
-+ task_lock(tsk);
-+ spin_lock_irqsave(&qemu_trace_lock, irq_flags);
-+ writel(task_tgid_nr(tsk), qt_base + (TRACE_DEV_REG_TGID << 2));
-+ writel(task_pid_nr(tsk), qt_base + (TRACE_DEV_REG_INIT_PID << 2));
-+ writel(tsk->comm, qt_base + (TRACE_DEV_REG_INIT_NAME << 2));
-+ spin_unlock_irqrestore(&qemu_trace_lock, irq_flags);
-+ task_unlock(tsk);
-+ /* check if the task has execs */
-+ qemu_trace_pid_exec(tsk);
-+ }
-+ }
-+}
-+
-+static int qemu_trace_probe(struct platform_device *pdev)
-+{
-+ struct resource *r;
-+
-+ /* not thread safe, but this should not happen */
-+ if (qt_base != NULL) {
-+ printk(KERN_ERR "QEMU TRACE Device: already mapped at %p\n", qt_base);
-+ return -ENODEV;
-+ }
-+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (r == NULL)
-+ return -EINVAL;
-+ qt_base = ioremap(r->start, PAGE_SIZE);
-+ printk(KERN_INFO "QEMU TRACE Device: The mapped IO base is %p\n", qt_base);
-+
-+ qemu_trace_dump_init_threads();
-+
-+ return 0;
-+}
-+
-+static int qemu_trace_remove(struct platform_device *pdev)
-+{
-+ iounmap(qt_base);
-+ qt_base = NULL;
-+ return 0;
-+}
-+
-+static struct platform_driver qemu_trace = {
-+ .probe = qemu_trace_probe,
-+ .remove = qemu_trace_remove,
-+ .driver = {
-+ .name = "qemu_trace"
-+ }
-+};
-+
-+static int __init qemu_trace_dev_init(void)
-+{
-+ int ret;
-+ ret = platform_driver_register(&qemu_trace);
-+ init_called = 1;
-+ return ret;
-+}
-+
-+static void qemu_trace_dev_exit(void)
-+{
-+ platform_driver_unregister(&qemu_trace);
-+}
-+
-+
-+module_init(qemu_trace_dev_init);
-+module_exit(qemu_trace_dev_exit);
-+
-+MODULE_AUTHOR("Ye Wen <ywen@google.com>");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/misc/qemutrace/qemu_trace.h
-@@ -0,0 +1,22 @@
-+/* drivers/misc/qemutrace/qemu_trace.h
-+ *
-+ * Copyright (C) 2007-2008 Google, Inc.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ *
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+
-+void qemu_trace_start(void);
-+void qemu_trace_stop(void);
-+int qemu_trace_get_tracing(void);
-+void qemu_trace_add_mapping(unsigned int addr, const char *symbol);
-+void qemu_trace_remove_mapping(unsigned int addr);
-+void qemu_trace_process_name(const char *name);
---- /dev/null
-+++ b/drivers/misc/qemutrace/qemu_trace_sysfs.c
-@@ -0,0 +1,182 @@
-+/* drivers/misc/qemu_sysfs.c
-+ *
-+ * Copyright (C) 2007-2008 Google, Inc.
-+ * Author: Jack Veenstra
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/miscdevice.h>
-+#include <linux/sysdev.h>
-+#include <linux/fs.h>
-+#include <linux/poll.h>
-+#include <linux/interrupt.h>
-+#include <linux/delay.h>
-+#include <linux/clk.h>
-+#include <linux/wait.h>
-+#include "qemu_trace.h"
-+
-+MODULE_DESCRIPTION("Qemu Trace Driver");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION("1.0");
-+
-+static struct kobject *qemu_trace_kobj;
-+
-+static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
-+{
-+ int val = qemu_trace_get_tracing();
-+ buf[0] = '0' + val;
-+ buf[1] = '\n';
-+ return 2;
-+}
-+
-+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
-+{
-+ if (n <= 0)
-+ return -EINVAL;
-+ if (buf[0] == '0')
-+ qemu_trace_stop();
-+ else if (buf[0] == '1')
-+ qemu_trace_start();
-+ else
-+ return -EINVAL;
-+ return n;
-+}
-+
-+static ssize_t symbol_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
-+{
-+ return 0;
-+}
-+
-+// We are expecting a string of the form "addr symbol" where 'addr' is a hex address
-+// (without the leading '0x') and symbol is a newline-terminated string. This symbol
-+// with its corresponding address will be added to the trace file.
-+//
-+// To remove the mapping for (addr, symbol) in the trace file, write just the
-+// address. As before, the address is in hex without the leading '0x'. It can
-+// be newline-terminated or zero-terminated.
-+static ssize_t symbol_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
-+{
-+ const char *cp;
-+ unsigned int addr = 0;
-+ int len;
-+ char *sym;
-+
-+ if (n <= 0 || buf == NULL)
-+ return -EINVAL;
-+ for (cp = buf; *cp != ' '; ++cp) {
-+ unsigned int digit;
-+
-+ if (*cp >= '0' && *cp <= '9')
-+ digit = *cp - '0';
-+ else if (*cp >= 'a' && *cp <= 'f')
-+ digit = *cp - 'a' + 10;
-+ else if (*cp == 0 || *cp == '\n') {
-+ qemu_trace_remove_mapping(addr);
-+ return n;
-+ } else
-+ return -EINVAL;
-+ addr = (addr << 4) + digit;
-+ }
-+ // Move past the space
-+ cp += 1;
-+
-+ // Copy the string to a new buffer so that we can replace the newline
-+ // with '\0'.
-+ len = strlen(cp);
-+ sym = kzalloc(len + 1, GFP_KERNEL);
-+ strcpy(sym, cp);
-+ if (sym[len - 1] == '\n')
-+ sym[len - 1] = 0;
-+
-+ qemu_trace_add_mapping(addr, sym);
-+ kfree(sym);
-+ return n;
-+}
-+
-+static ssize_t process_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-+{
-+ return 0;
-+}
-+
-+/* This expects a string that is the process name. If the string contains
-+ * a trailing newline, that is removed in the emulator tracing code because
-+ * it is simpler to do it there.
-+ */
-+static ssize_t process_name_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
-+{
-+ if (n <= 0 || buf == NULL)
-+ return -EINVAL;
-+
-+ qemu_trace_process_name(buf);
-+ return n;
-+}
-+
-+
-+#define qemu_trace_attr(_name) \
-+static struct kobj_attribute _name##_attr = { \
-+ .attr = { \
-+ .name = __stringify(_name), \
-+ .mode = 0666, \
-+ }, \
-+ .show = _name##_show, \
-+ .store = _name##_store, \
-+}
-+
-+qemu_trace_attr(state);
-+qemu_trace_attr(symbol);
-+qemu_trace_attr(process_name);
-+
-+static struct attribute * qemu_trace_attrs[] = {
-+ &state_attr.attr,
-+ &symbol_attr.attr,
-+ &process_name_attr.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group qemu_trace_attr_group = {
-+ .attrs = qemu_trace_attrs,
-+};
-+
-+static int __init qemu_trace_init(void)
-+{
-+ int ret;
-+
-+ qemu_trace_kobj = kobject_create_and_add("qemu_trace", NULL);
-+ if (qemu_trace_kobj == NULL) {
-+ printk("qemu_trace_init: kobject_create_and_add failed\n");
-+ ret = -ENOMEM;
-+ return ret;
-+ }
-+ ret = sysfs_create_group(qemu_trace_kobj, &qemu_trace_attr_group);
-+ if (ret) {
-+ printk("qemu_trace_init: sysfs_create_group failed\n");
-+ goto err;
-+ }
-+
-+ return 0;
-+
-+err:
-+ kobject_del(qemu_trace_kobj);
-+ qemu_trace_kobj = NULL;
-+ return ret;
-+}
-+
-+static void __exit qemu_trace_exit(void)
-+{
-+ sysfs_remove_group(qemu_trace_kobj, &qemu_trace_attr_group);
-+ kobject_del(qemu_trace_kobj);
-+}
-+
-+core_initcall(qemu_trace_init);
-+module_exit(qemu_trace_exit);
---- a/fs/exec.c
-+++ b/fs/exec.c
-@@ -59,6 +59,9 @@
- #include <asm/mmu_context.h>
- #include <asm/tlb.h>
- #include "internal.h"
-+#ifdef CONFIG_QEMU_TRACE
-+ void qemu_trace_thread_name(char *name);
-+#endif
-
- int core_uses_pid;
- char core_pattern[CORENAME_MAX_SIZE] = "core";
-@@ -922,6 +925,9 @@ void set_task_comm(struct task_struct *t
- task_lock(tsk);
- strlcpy(tsk->comm, buf, sizeof(tsk->comm));
- task_unlock(tsk);
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_thread_name(buf);
-+#endif
- }
-
- int flush_old_exec(struct linux_binprm * bprm)
-@@ -1245,6 +1251,10 @@ void free_bprm(struct linux_binprm *bprm
- kfree(bprm);
- }
-
-+#ifdef CONFIG_QEMU_TRACE
-+extern void qemu_trace_execve(int argc, char __user * __user * argv);
-+#endif
-+
- /*
- * sys_execve() executes a new program.
- */
-@@ -1324,6 +1334,10 @@ int do_execve(char * filename,
- goto out;
-
- current->flags &= ~PF_KTHREAD;
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_execve(bprm->argc, argv);
-+#endif
-+
- retval = search_binary_handler(bprm,regs);
- if (retval < 0)
- goto out;
---- a/kernel/exit.c
-+++ b/kernel/exit.c
-@@ -60,6 +60,11 @@ DEFINE_TRACE(sched_process_free);
- DEFINE_TRACE(sched_process_exit);
- DEFINE_TRACE(sched_process_wait);
-
-+#ifdef CONFIG_QEMU_TRACE
-+void qemu_trace_thread_name(char *name);
-+void qemu_trace_exit(int code);
-+#endif
-+
- static void exit_mm(struct task_struct * tsk);
-
- static void __unhash_process(struct task_struct *p)
-@@ -426,6 +431,9 @@ void daemonize(const char *name, ...)
- va_start(args, name);
- vsnprintf(current->comm, sizeof(current->comm), name, args);
- va_end(args);
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_thread_name(current->comm);
-+#endif
-
- /*
- * If we were started as result of loading a module, close all of the
-@@ -1012,6 +1020,12 @@ NORET_TYPE void do_exit(long code)
- preempt_disable();
- /* causes final put_task_struct in finish_task_switch(). */
- tsk->state = TASK_DEAD;
-+
-+#ifdef CONFIG_QEMU_TRACE
-+ /* Emit a trace record for the exit() call. */
-+ qemu_trace_exit(code);
-+#endif
-+
- schedule();
- BUG();
- /* Avoid "noreturn function does return". */
---- a/kernel/fork.c
-+++ b/kernel/fork.c
-@@ -1323,6 +1323,10 @@ struct task_struct * __cpuinit fork_idle
- return task;
- }
-
-+#ifdef CONFIG_QEMU_TRACE
-+extern void qemu_trace_fork(struct task_struct *forked, unsigned long clone_flags);
-+#endif
-+
- /*
- * Ok, this is the main fork-routine.
- *
-@@ -1424,6 +1428,10 @@ long do_fork(unsigned long clone_flags,
- tracehook_report_clone_complete(trace, regs,
- clone_flags, nr, p);
-
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_fork(p, clone_flags);
-+#endif
-+
- if (clone_flags & CLONE_VFORK) {
- freezer_do_not_count();
- wait_for_completion(&vfork);
---- a/kernel/sched.c
-+++ b/kernel/sched.c
-@@ -2748,6 +2748,10 @@ asmlinkage void schedule_tail(struct tas
- put_user(task_pid_vnr(current), current->set_child_tid);
- }
-
-+#ifdef CONFIG_QEMU_TRACE
-+void qemu_trace_cs(struct task_struct *next);
-+#endif
-+
- /*
- * context_switch - switch to the new MM and the new
- * thread's register state.
-@@ -2790,6 +2794,11 @@ context_switch(struct rq *rq, struct tas
- spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
- #endif
-
-+#ifdef CONFIG_QEMU_TRACE
-+ /* Emit a trace record for the context switch. */
-+ qemu_trace_cs(next);
-+#endif
-+
- /* Here we just switch the register state and the stack. */
- switch_to(prev, next, prev);
-
---- a/mm/mmap.c
-+++ b/mm/mmap.c
-@@ -906,6 +906,11 @@ void vm_stat_account(struct mm_struct *m
- }
- #endif /* CONFIG_PROC_FS */
-
-+#ifdef CONFIG_QEMU_TRACE
-+extern void qemu_trace_mmap(struct vm_area_struct * vma);
-+extern void qemu_trace_munmap(unsigned long start, unsigned long end);
-+#endif
-+
- /*
- * The caller must hold down_write(current->mm->mmap_sem).
- */
-@@ -1212,6 +1217,10 @@ munmap_back:
- pgoff = vma->vm_pgoff;
- vm_flags = vma->vm_flags;
-
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_mmap(vma);
-+#endif
-+
- if (vma_wants_writenotify(vma))
- vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);
-
-@@ -1938,6 +1947,10 @@ int do_munmap(struct mm_struct *mm, unsi
- * Remove the vma's, and unmap the actual pages
- */
- detach_vmas_to_be_unmapped(mm, vma, prev, end);
-+
-+#ifdef CONFIG_QEMU_TRACE
-+ qemu_trace_munmap(start, end);
-+#endif
- unmap_region(mm, vma, prev, start, end);
-
- /* Fix up all other VM information */