mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-03-24 06:01:26 +00:00
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:
committed by
Søren Sandmann Pedersen
parent
a68837a3ad
commit
05c4a202b3
@ -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>
|
||||
|
||||
* module/sysprof-module.c (sysprof_read): Return ssize_t instead
|
||||
|
||||
@ -112,80 +112,9 @@ minimum (int a, int b)
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
static void
|
||||
framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace)
|
||||
{
|
||||
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,
|
||||
static struct pt_regs *
|
||||
copy_kernel_stack (struct pt_regs *regs,
|
||||
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;
|
||||
char *esp;
|
||||
@ -214,14 +143,113 @@ timer_notify (struct pt_regs *regs)
|
||||
}
|
||||
|
||||
/* 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
|
||||
heuristic_trace (regs, trace);
|
||||
#elif CONFIG_X86
|
||||
framepointer_trace (regs, trace);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (trace->n_addresses == SYSPROF_MAX_ADDRESSES)
|
||||
trace->truncated = 1;
|
||||
|
||||
Reference in New Issue
Block a user