mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-12 16:10:54 +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>
|
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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user