From 0bef92d4b586ef66be0bc5571b8fce76fba79cb1 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Thu, 2 Jul 2015 18:36:21 -0400 Subject: [PATCH] dtrace: record current IP as frame 0 in ustack When requesting a userspace stack trace, the initial frame instruction pointer should be recorded as frame 0, with the remainder of the stack trace being filled in based on the stack content. Previously, all the IP values were taken from the stack. Special handling is provided for obtaining the correct value of the stack pointer because in pre-4.1 kernels, there isn't an arch-independent way to do so. Once support for 4.0 is no longer necessary, this can be generalized by using the current_user_stack_pointer() macro. If the current task is not a userspace task, an empty stack trace is returned (and ustackdepth will also report 0). Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- dtrace/dtrace_isa.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/dtrace/dtrace_isa.c b/dtrace/dtrace_isa.c index 1e9b2c8d096d..1b129519fe99 100644 --- a/dtrace/dtrace_isa.c +++ b/dtrace/dtrace_isa.c @@ -131,20 +131,36 @@ unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, { struct task_struct *p = current; struct mm_struct *mm = p->mm; - unsigned long tos, bos; + unsigned long tos, bos, fpc; unsigned long *sp; unsigned long depth = 0; struct vm_area_struct *stack_vma; struct page *stack_page = NULL; + struct pt_regs *regs = current_pt_regs(); if (pcstack) { - if (unlikely(pcstack_limit < 2)) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return 0; - } - *pcstack++ = (uint64_t)p->pid; + if (unlikely(pcstack_limit < 2)) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return 0; + } + *pcstack++ = (uint64_t)p->pid; *pcstack++ = (uint64_t)p->tgid; - pcstack_limit-=2; + pcstack_limit -= 2; + } + + if (!user_mode(regs)) + goto out; + + /* + * There is always at least one address to report: the instruction + * pointer itself (frame 0). + */ + depth++; + + fpc = instruction_pointer(regs); + if (pcstack) { + *pcstack++ = (uint64_t)fpc; + pcstack_limit--; } /* @@ -161,8 +177,13 @@ unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, goto out; atomic_inc(&mm->mm_users); + /* + * The following construct can be replaced with: + * tos = current_user_stack_pointer(); + * once support for 4.0 is no longer necessary. + */ #ifdef CONFIG_X86_64 - tos = current_user_stack_pointer(); + tos = current_pt_regs()->sp; #else tos = user_stack_pointer(current_pt_regs()); #endif @@ -216,6 +237,9 @@ unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, break; } + if (addr == fpc) + continue; + code_vma = find_user_vma(p, mm, NULL, addr, 0); if (!code_vma || code_vma->vm_start > addr) -- 2.50.1