Root/target/linux/goldfish/patches-2.6.30/0129--ARM-goldfish-qemutrace-Kernel-instrumentation-fo.patch

1From fcd69dd4537320a25a294c82362cc7abe4fe773c Mon Sep 17 00:00:00 2001
2From: Ye Wen <ywen@google.com>
3Date: Fri, 14 Jul 2006 14:51:45 +0700
4Subject: [PATCH 129/134] [ARM] goldfish: qemutrace: Kernel instrumentation for tracing the events.
5
6Like fork, context switch, execve and exit.
7This code is to complement Jack's tracing facility.
8
9To turn tracing on:
10echo 1 > /sysfs/qemu_trace/state
11To turn tracing off: echo 0 > /sysfs/qemu_trace/state
12I also added java methods to Debug.java to turn tracing on and off.
13The kernel driver also supports adding dynamic symbols to the trace.
14To add a symbol 'foo' with hex address 'abcd1234' to the trace:
15echo 'abcd1234 foo' > /sysfs/qemu_trace/symbol
16
17Signed-off-by: Mike Chan <mike@android.com>
18
19[ARM] goldfish: qemutrace: Improved support for tracing thread and process names.
20
21Added a new pseudo file /sys/qemu_trace/process_name to allow user
22programs to add a trace record for a process name change. Removed
23the tracing of thread and process names from the exit() system call
24because that was not sufficiently general. Added tracing of thread
25names in set_task_comm() and daemonize(). Added tracing of the
26thread group id to fork() and clone().
27
28Signed-off-by: Jack Veenstra <veenstra@google.com>
29Signed-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 */
855

Archive Download this file



interactive