diff options
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.patch | 854 |
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 b31ca03..0000000 --- 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 */ |