]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: record current IP as frame 0 in ustack
authorKris Van Hees <kris.van.hees@oracle.com>
Thu, 2 Jul 2015 22:36:21 +0000 (18:36 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Tue, 21 Jul 2015 06:51:24 +0000 (02:51 -0400)
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 <kris.van.hees@oracle.com>
Acked-by: Nick Alcock <nick.alcock@oracle.com>
dtrace/dtrace_isa.c

index 1e9b2c8d096de2d6e0721939c21c8d4a4ccf7bf5..1b129519fe992b461cf493ae09a17758856c4eef 100644 (file)
@@ -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)