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,6 +112,40 @@ minimum (int a, int b)
|
|||||||
return a > b ? b : a;
|
return a > b ? b : a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct pt_regs *
|
||||||
|
copy_kernel_stack (struct pt_regs *regs,
|
||||||
|
SysprofStackTrace *trace)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
return (struct pt_regs *)eos;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace)
|
framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace)
|
||||||
{
|
{
|
||||||
@ -119,10 +153,8 @@ framepointer_trace (struct pt_regs *regs, SysprofStackTrace *trace)
|
|||||||
int i;
|
int i;
|
||||||
StackFrame frame;
|
StackFrame frame;
|
||||||
|
|
||||||
i = 0;
|
i = 1;
|
||||||
|
|
||||||
trace->addresses[i++] = (void *)regs->REG_INS_PTR;
|
|
||||||
|
|
||||||
framepointer = (void *)regs->REG_FRAME_PTR;
|
framepointer = (void *)regs->REG_FRAME_PTR;
|
||||||
|
|
||||||
while (read_frame (framepointer, &frame) == 0 &&
|
while (read_frame (framepointer, &frame) == 0 &&
|
||||||
@ -140,7 +172,29 @@ static void
|
|||||||
heuristic_trace (struct pt_regs *regs,
|
heuristic_trace (struct pt_regs *regs,
|
||||||
SysprofStackTrace *trace)
|
SysprofStackTrace *trace)
|
||||||
{
|
{
|
||||||
return framepointer_trace (regs, 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
|
#ifdef OLD_PROFILE
|
||||||
@ -154,7 +208,6 @@ timer_notify (struct pt_regs *regs)
|
|||||||
struct pt_regs * regs = (struct pt_regs *)data;
|
struct pt_regs * regs = (struct pt_regs *)data;
|
||||||
#endif
|
#endif
|
||||||
SysprofStackTrace *trace = &(area->traces[area->head]);
|
SysprofStackTrace *trace = &(area->traces[area->head]);
|
||||||
int i;
|
|
||||||
int is_user;
|
int is_user;
|
||||||
static atomic_t in_timer_notify = ATOMIC_INIT(1);
|
static atomic_t in_timer_notify = ATOMIC_INIT(1);
|
||||||
int n;
|
int n;
|
||||||
@ -171,7 +224,7 @@ timer_notify (struct pt_regs *regs)
|
|||||||
|
|
||||||
is_user = user_mode(regs);
|
is_user = user_mode(regs);
|
||||||
|
|
||||||
if (!current || current->pid == 0 || !current->mm)
|
if (!current || current->pid == 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (is_user && current->state != TASK_RUNNING)
|
if (is_user && current->state != TASK_RUNNING)
|
||||||
@ -184,45 +237,20 @@ timer_notify (struct pt_regs *regs)
|
|||||||
trace->n_kernel_words = 0;
|
trace->n_kernel_words = 0;
|
||||||
trace->n_addresses = 0;
|
trace->n_addresses = 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
if (!is_user)
|
if (!is_user)
|
||||||
{
|
regs = copy_kernel_stack (regs, trace);
|
||||||
int n_bytes;
|
|
||||||
char *esp;
|
|
||||||
char *eos;
|
|
||||||
|
|
||||||
trace->kernel_stack[0] = (void *)regs->REG_INS_PTR;
|
trace->addresses[0] = (void *)regs->REG_INS_PTR;
|
||||||
trace->n_kernel_words = 1;
|
trace->n_addresses = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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;
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user