From f1cbdbf27c9c766ae1db854c67dce112703f8a8b Mon Sep 17 00:00:00 2001 From: Soren Sandmann Date: Mon, 17 Sep 2007 01:43:07 +0000 Subject: Add support for looking up kernel symbols from /proc/kallsyms 2007-09-16 Soren Sandmann * process.c (process_lookup_kernel_symbol): Add support for looking up kernel symbols from /proc/kallsyms * sysprof-text.c (dump_data): Print note that the file is being saved. * module/sysprof-module.[ch] (timer_notify): Send a copy of the kernel stack to userspace. * collector.c: Do kernel symbol lookups. svn path=/trunk/; revision=372 --- module/sysprof-module.c | 81 +++++++++++++++++++++++-------------------------- module/sysprof-module.h | 12 +++++--- 2 files changed, 45 insertions(+), 48 deletions(-) (limited to 'module') diff --git a/module/sysprof-module.c b/module/sysprof-module.c index 59b7910..d2f5ab5 100644 --- a/module/sysprof-module.c +++ b/module/sysprof-module.c @@ -106,6 +106,12 @@ read_frame (void *frame_pointer, StackFrame *frame) DEFINE_PER_CPU(int, n_samples); +static int +minimum (int a, int b) +{ + return a > b ? b : a; +} + #ifdef OLD_PROFILE static int timer_notify(struct notifier_block * self, unsigned long val, void * data) #else @@ -123,9 +129,6 @@ timer_notify (struct pt_regs *regs) StackFrame frame; int result; static atomic_t in_timer_notify = ATOMIC_INIT(1); -#if 0 - int stacksize; -#endif int n; n = ++get_cpu_var(n_samples); @@ -135,7 +138,6 @@ timer_notify (struct pt_regs *regs) return 0; /* 0: locked, 1: unlocked */ - if (!atomic_dec_and_test(&in_timer_notify)) goto out; @@ -150,58 +152,51 @@ timer_notify (struct pt_regs *regs) memset(trace, 0, sizeof (SysprofStackTrace)); trace->pid = current->pid; - + + trace->n_kernel_words = 0; + trace->n_addresses = 0; + i = 0; if (!is_user) { - trace->addresses[i++] = (void *)0x01; - regs = (void *)current->thread.REG_STACK_PTR0 - sizeof (struct pt_regs); + int n_bytes; + char *esp; + char *eos; + + trace->kernel_stack[0] = (void *)regs->REG_INS_PTR; + trace->n_kernel_words = 1; + + /* The timer interrupt happened in kernel mode. When this + * happens the registers are pushed on the stack, _except_ + * esp. So we can't use regs->esp to copy the stack pointer. + * Instead we use the fact that the regs pointer itself + * points to the stack. + */ + esp = (char *)regs + sizeof (struct pt_regs); + eos = (char *)current->thread.REG_STACK_PTR0 - sizeof (struct pt_regs); + + n_bytes = minimum ((char *)eos - esp, + sizeof (trace->kernel_stack)); + + if (n_bytes > 0) { + memcpy (&(trace->kernel_stack[1]), esp, n_bytes); + + trace->n_kernel_words += (n_bytes) / sizeof (void *); + } + + /* Now trace the user stack */ + regs = (struct pt_regs *)eos; } + i = 0; trace->addresses[i++] = (void *)regs->REG_INS_PTR; frame_pointer = (void *)regs->REG_FRAME_PTR; - - { -#if 0 - /* In principle we should use get_task_mm() but - * that will use task_lock() leading to deadlock - * if somebody already has the lock - */ - if (spin_is_locked (¤t->alloc_lock)) - printk ("alreadylocked\n"); - { - struct mm_struct *mm = current->mm; - if (mm) - { - printk (KERN_ALERT "stack size: %d (%d)\n", - mm->start_stack - regs->REG_STACK_PTR, - current->pid); - - stacksize = mm->start_stack - regs->REG_STACK_PTR; - } - else - stacksize = 1; - } -#endif -#if 0 - else - printk (KERN_ALERT "could not lock on %d\n", current->pid); -#endif - } -#if 0 - if (stacksize < 100000) - goto out; -#endif - while (((result = read_frame (frame_pointer, &frame)) == 0) && i < SYSPROF_MAX_ADDRESSES && (unsigned long)frame_pointer >= regs->REG_STACK_PTR) { -#if 0 - printk ("frame pointer: %p (retaddr: %p)\n", frame_pointer, frame.return_address); -#endif trace->addresses[i++] = (void *)frame.return_address; frame_pointer = (StackFrame *)frame.next; } diff --git a/module/sysprof-module.h b/module/sysprof-module.h index 9b7e4df..d92886d 100644 --- a/module/sysprof-module.h +++ b/module/sysprof-module.h @@ -25,16 +25,18 @@ typedef struct SysprofStackInfo SysprofStackInfo; typedef struct SysprofMmapArea SysprofMmapArea; #define SYSPROF_N_TRACES 64 -#define SYSPROF_MAX_ADDRESSES 1021 /* to make it one page wide */ +#define SYSPROF_MAX_ADDRESSES 1020 /* to make it three pages wide */ struct SysprofStackTrace { + void *kernel_stack[1024]; + void *addresses[SYSPROF_MAX_ADDRESSES]; + int n_kernel_words; + int n_addresses; /* note: this can be 1 if the process was compiled + * with -fomit-frame-pointer or is otherwise weird + */ int pid; /* -1 if in kernel */ int truncated; - int n_addresses; /* note: this can be 1 if the process was compiled - * with -fomit-frame-pointer or is otherwise weird - */ - void *addresses[SYSPROF_MAX_ADDRESSES]; }; struct SysprofMmapArea -- cgit v1.2.3