Crude heuristic stack scanning on x86-64.

Sun Nov 18 18:12:09 2007  Søren Sandmann  <sandmann@redhat.com>

       * module/sysprof-module.c (heuristic_trace): Crude heuristic stack
       scanning on x86-64.

       * module/sysprof-module.c (copy_kernel_stack): New function



svn path=/trunk/; revision=392
This commit is contained in:
Søren Sandmann
2007-11-18 23:11:52 +00:00
committed by Søren Sandmann Pedersen
parent a68837a3ad
commit 05c4a202b3
2 changed files with 74 additions and 39 deletions

View File

@ -1,3 +1,10 @@
Sun Nov 18 18:12:09 2007 Søren Sandmann <sandmann@redhat.com>
* module/sysprof-module.c (heuristic_trace): Crude heuristic stack
scanning on x86-64.
* module/sysprof-module.c (copy_kernel_stack): New function
Sun Nov 18 13:23:39 2007 Søren Sandmann <sandmann@redhat.com> Sun Nov 18 13:23:39 2007 Søren Sandmann <sandmann@redhat.com>
* module/sysprof-module.c (sysprof_read): Return ssize_t instead * module/sysprof-module.c (sysprof_read): Return ssize_t instead

View File

@ -112,80 +112,9 @@ minimum (int a, int b)
return a > b ? b : a; return a > b ? b : a;
} }
static void static struct pt_regs *
framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace) copy_kernel_stack (struct pt_regs *regs,
{
void *framepointer;
int i;
StackFrame frame;
i = 0;
trace->addresses[i++] = (void *)regs->REG_INS_PTR;
framepointer = (void *)regs->REG_FRAME_PTR;
while (read_frame (framepointer, &frame) == 0 &&
i < SYSPROF_MAX_ADDRESSES &&
(unsigned long)framepointer >= regs->REG_STACK_PTR)
{
trace->addresses[i++] = (void *)frame.return_address;
framepointer = (StackFrame *)frame.next;
}
trace->n_addresses = i;
}
static void
heuristic_trace (struct pt_regs *regs,
SysprofStackTrace *trace) SysprofStackTrace *trace)
{
return framepointer_trace (regs, trace);
}
#ifdef OLD_PROFILE
static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
#else
static int
timer_notify (struct pt_regs *regs)
#endif
{
#ifdef OLD_PROFILE
struct pt_regs * regs = (struct pt_regs *)data;
#endif
SysprofStackTrace *trace = &(area->traces[area->head]);
int i;
int is_user;
static atomic_t in_timer_notify = ATOMIC_INIT(1);
int n;
n = ++get_cpu_var(n_samples);
put_cpu_var(n_samples);
if (n % INTERVAL != 0)
return 0;
/* 0: locked, 1: unlocked */
if (!atomic_dec_and_test(&in_timer_notify))
goto out;
is_user = user_mode(regs);
if (!current || current->pid == 0 || !current->mm)
goto out;
if (is_user && current->state != TASK_RUNNING)
goto out;
memset(trace, 0, sizeof (SysprofStackTrace));
trace->pid = current->pid;
trace->n_kernel_words = 0;
trace->n_addresses = 0;
i = 0;
if (!is_user)
{ {
int n_bytes; int n_bytes;
char *esp; char *esp;
@ -214,14 +143,113 @@ timer_notify (struct pt_regs *regs)
} }
/* Now trace the user stack */ /* Now trace the user stack */
regs = (struct pt_regs *)eos; return (struct pt_regs *)eos;
} }
static void
framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace)
{
void *framepointer;
int i;
StackFrame frame;
i = 1;
framepointer = (void *)regs->REG_FRAME_PTR;
while (read_frame (framepointer, &frame) == 0 &&
i < SYSPROF_MAX_ADDRESSES &&
(unsigned long)framepointer >= regs->REG_STACK_PTR)
{
trace->addresses[i++] = (void *)frame.return_address;
framepointer = (StackFrame *)frame.next;
}
trace->n_addresses = i;
}
static void
heuristic_trace (struct pt_regs *regs,
SysprofStackTrace *trace)
{
unsigned long esp = regs->REG_STACK_PTR;
unsigned long eos = current->mm->start_stack;
if (esp < eos - (current->mm->stack_vm << PAGE_SHIFT)) {
/* Stack pointer is not in stack map */
return;
}
if (eos > esp) {
unsigned long i;
int j;
j = 1;
for (i = esp; i < eos && j < SYSPROF_MAX_ADDRESSES; i += sizeof (void *)) {
void *x;
if (__copy_from_user_inatomic (
&x, (char *)i, sizeof (x)) == 0)
trace->addresses[j++] = x;
}
trace->n_addresses = j;
}
}
#ifdef OLD_PROFILE
static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
#else
static int
timer_notify (struct pt_regs *regs)
#endif
{
#ifdef OLD_PROFILE
struct pt_regs * regs = (struct pt_regs *)data;
#endif
SysprofStackTrace *trace = &(area->traces[area->head]);
int is_user;
static atomic_t in_timer_notify = ATOMIC_INIT(1);
int n;
n = ++get_cpu_var(n_samples);
put_cpu_var(n_samples);
if (n % INTERVAL != 0)
return 0;
/* 0: locked, 1: unlocked */
if (!atomic_dec_and_test(&in_timer_notify))
goto out;
is_user = user_mode(regs);
if (!current || current->pid == 0)
goto out;
if (is_user && current->state != TASK_RUNNING)
goto out;
memset(trace, 0, sizeof (SysprofStackTrace));
trace->pid = current->pid;
trace->n_kernel_words = 0;
trace->n_addresses = 0;
if (!is_user)
regs = copy_kernel_stack (regs, trace);
trace->addresses[0] = (void *)regs->REG_INS_PTR;
trace->n_addresses = 1;
if (current->mm) {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
heuristic_trace (regs, trace); heuristic_trace (regs, trace);
#elif CONFIG_X86 #elif CONFIG_X86
framepointer_trace (regs, trace); framepointer_trace (regs, trace);
#endif #endif
}
if (trace->n_addresses == SYSPROF_MAX_ADDRESSES) if (trace->n_addresses == SYSPROF_MAX_ADDRESSES)
trace->truncated = 1; trace->truncated = 1;