]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
misc: tegra-profiler: support too deep stack level
authorIgor Nabirushkin <inabirushkin@nvidia.com>
Fri, 16 May 2014 07:24:50 +0000 (11:24 +0400)
committerDhiren Parmar <dparmar@nvidia.com>
Tue, 12 Aug 2014 12:46:17 +0000 (05:46 -0700)
Too deep stack level: handle it properly.
Appropriate unwind reason code has been added.

Unwinding based on frame pointers: add unwind reason codes.

Bug 200005380

Change-Id: I2199df90c746ada6a7f224a8b675638b69dc6da8
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/410717
(cherry picked from commit e96cd9adf0ca020c55545925168671373a67a009)
Reviewed-on: http://git-master/r/454446
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Tested-by: Maxim Morin <mmorin@nvidia.com>
Reviewed-by: Mitch Luban <mluban@nvidia.com>
drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/comm.c
drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/hrt.c
drivers/misc/tegra-profiler/main.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index d2039a5827c7b4c2ea0a20cae4830b739b57768e..371bd24c8ac07898c48700921419ee2ac86815a0 100644 (file)
@@ -81,15 +81,22 @@ int
 quadd_callchain_store(struct quadd_callchain *cc,
                      unsigned long ip)
 {
-       if (ip && cc->nr < QUADD_MAX_STACK_DEPTH) {
-               if (cc->cs_64)
-                       cc->ip_64[cc->nr++] = ip;
-               else
-                       cc->ip_32[cc->nr++] = ip;
+       if (!ip) {
+               cc->unw_rc = QUADD_URC_PC_INCORRECT;
+               return 0;
+       }
 
-               return 1;
+       if (cc->nr >= QUADD_MAX_STACK_DEPTH) {
+               cc->unw_rc = QUADD_URC_LEVEL_TOO_DEEP;
+               return 0;
        }
-       return 0;
+
+       if (cc->cs_64)
+               cc->ip_64[cc->nr++] = ip;
+       else
+               cc->ip_32[cc->nr++] = ip;
+
+       return 1;
 }
 
 static unsigned long __user *
@@ -97,14 +104,17 @@ user_backtrace(unsigned long __user *tail,
               struct quadd_callchain *cc,
               struct vm_area_struct *stack_vma)
 {
+       int nr_added;
        unsigned long value, value_lr = 0, value_fp = 0;
        unsigned long __user *fp_prev = NULL;
 
        if (!is_vma_addr((unsigned long)tail, stack_vma, sizeof(*tail)))
                return NULL;
 
-       if (__copy_from_user_inatomic(&value, tail, sizeof(unsigned long)))
+       if (__copy_from_user_inatomic(&value, tail, sizeof(unsigned long))) {
+               cc->unw_rc = QUADD_URC_EACCESS;
                return NULL;
+       }
 
        if (is_vma_addr(value, stack_vma, sizeof(value))) {
                /* gcc thumb/clang frame */
@@ -115,13 +125,17 @@ user_backtrace(unsigned long __user *tail,
                        return NULL;
 
                if (__copy_from_user_inatomic(&value_lr, tail + 1,
-                                             sizeof(value_lr)))
+                                             sizeof(value_lr))) {
+                       cc->unw_rc = QUADD_URC_EACCESS;
                        return NULL;
+               }
        } else {
                /* gcc arm frame */
                if (__copy_from_user_inatomic(&value_fp, tail - 1,
-                                             sizeof(value_fp)))
+                                             sizeof(value_fp))) {
+                       cc->unw_rc = QUADD_URC_EACCESS;
                        return NULL;
+               }
 
                if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
                        return NULL;
@@ -131,10 +145,14 @@ user_backtrace(unsigned long __user *tail,
 
        fp_prev = (unsigned long __user *)value_fp;
 
-       if (value_lr < QUADD_USER_SPACE_MIN_ADDR)
+       if (value_lr < QUADD_USER_SPACE_MIN_ADDR) {
+               cc->unw_rc = QUADD_URC_PC_INCORRECT;
                return NULL;
+       }
 
-       quadd_callchain_store(cc, value_lr);
+       nr_added = quadd_callchain_store(cc, value_lr);
+       if (nr_added == 0)
+               return NULL;
 
        if (fp_prev <= tail)
                return NULL;
@@ -153,10 +171,12 @@ get_user_callchain_fp(struct pt_regs *regs,
        struct mm_struct *mm = task->mm;
 
        cc->nr = 0;
-       cc->unw_method = QUADD_UNW_METHOD_FP;
+       cc->unw_rc = QUADD_URC_FP_INCORRECT;
 
-       if (!regs || !mm)
+       if (!regs || !mm) {
+               cc->unw_rc = QUADD_URC_FAILURE;
                return 0;
+       }
 
        sp = quadd_user_stack_pointer(regs);
        pc = instruction_pointer(regs);
@@ -166,8 +186,10 @@ get_user_callchain_fp(struct pt_regs *regs,
                return 0;
 
        vma = find_vma(mm, sp);
-       if (!vma)
+       if (!vma) {
+               cc->unw_rc = QUADD_URC_SP_INCORRECT;
                return 0;
+       }
 
        if (!is_vma_addr(fp, vma, sizeof(fp)))
                return 0;
@@ -176,6 +198,7 @@ get_user_callchain_fp(struct pt_regs *regs,
                pr_warn_once("frame error: sp/fp: %#lx/%#lx, pc/lr: %#lx/%#lx, vma: %#lx-%#lx\n",
                             sp, fp, pc, quadd_user_link_register(regs),
                             vma->vm_start, vma->vm_end);
+               cc->unw_rc = QUADD_URC_EACCESS;
                return 0;
        }
 
@@ -191,8 +214,10 @@ get_user_callchain_fp(struct pt_regs *regs,
                        if (__copy_from_user_inatomic(
                                        &value,
                                        (unsigned long __user *)fp + 1,
-                                       sizeof(unsigned long)))
+                                       sizeof(unsigned long))) {
+                               cc->unw_rc = QUADD_URC_EACCESS;
                                return 0;
+                       }
 
                        vma_pc = find_vma(mm, pc);
                        read_lr = 1;
@@ -200,12 +225,18 @@ get_user_callchain_fp(struct pt_regs *regs,
 
                if (!read_lr || !is_vma_addr(value, vma_pc, sizeof(value))) {
                        /* gcc: fp --> short frame tail (fp) */
+                       int nr_added;
                        unsigned long lr = quadd_user_link_register(regs);
 
-                       if (lr < QUADD_USER_SPACE_MIN_ADDR)
+                       if (lr < QUADD_USER_SPACE_MIN_ADDR) {
+                               cc->unw_rc = QUADD_URC_PC_INCORRECT;
                                return 0;
+                       }
+
+                       nr_added = quadd_callchain_store(cc, lr);
+                       if (nr_added == 0)
+                               return cc->nr;
 
-                       quadd_callchain_store(cc, lr);
                        tail = (unsigned long __user *)reg;
                }
        }
@@ -226,19 +257,24 @@ __user_backtrace(struct quadd_callchain *cc, struct task_struct *task)
        struct vm_area_struct *vma;
        unsigned long __user *tail;
 
-       if (!mm)
-               goto out;
+       cc->unw_rc = QUADD_URC_FP_INCORRECT;
+
+       if (!mm) {
+               cc->unw_rc = QUADD_URC_FAILURE;
+               return cc->nr;
+       }
 
        vma = find_vma(mm, cc->curr_sp);
-       if (!vma)
-               goto out;
+       if (!vma) {
+               cc->unw_rc = QUADD_URC_SP_INCORRECT;
+               return cc->nr;
+       }
 
        tail = (unsigned long __user *)cc->curr_fp;
 
        while (tail && !((unsigned long)tail & 0x3))
                tail = user_backtrace(tail, cc, vma);
 
-out:
        return cc->nr;
 }
 
@@ -248,14 +284,17 @@ user_backtrace_compat(u32 __user *tail,
               struct quadd_callchain *cc,
               struct vm_area_struct *stack_vma)
 {
+       int nr_added;
        u32 value, value_lr = 0, value_fp = 0;
        u32 __user *fp_prev = NULL;
 
        if (!is_vma_addr((unsigned long)tail, stack_vma, sizeof(*tail)))
                return NULL;
 
-       if (__copy_from_user_inatomic(&value, tail, sizeof(value)))
+       if (__copy_from_user_inatomic(&value, tail, sizeof(value))) {
+               cc->unw_rc = QUADD_URC_EACCESS;
                return NULL;
+       }
 
        if (is_vma_addr(value, stack_vma, sizeof(value))) {
                /* gcc thumb/clang frame */
@@ -266,13 +305,17 @@ user_backtrace_compat(u32 __user *tail,
                        return NULL;
 
                if (__copy_from_user_inatomic(&value_lr, tail + 1,
-                                             sizeof(value_lr)))
+                                             sizeof(value_lr))) {
+                       cc->unw_rc = QUADD_URC_EACCESS;
                        return NULL;
+               }
        } else {
                /* gcc arm frame */
                if (__copy_from_user_inatomic(&value_fp, tail - 1,
-                                             sizeof(value_fp)))
+                                             sizeof(value_fp))) {
+                       cc->unw_rc = QUADD_URC_EACCESS;
                        return NULL;
+               }
 
                if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
                        return NULL;
@@ -282,10 +325,14 @@ user_backtrace_compat(u32 __user *tail,
 
        fp_prev = (u32 __user *)(unsigned long)value_fp;
 
-       if (value_lr < QUADD_USER_SPACE_MIN_ADDR)
+       if (value_lr < QUADD_USER_SPACE_MIN_ADDR) {
+               cc->unw_rc = QUADD_URC_PC_INCORRECT;
                return NULL;
+       }
 
-       quadd_callchain_store(cc, value_lr);
+       nr_added = quadd_callchain_store(cc, value_lr);
+       if (nr_added == 0)
+               return NULL;
 
        if (fp_prev <= tail)
                return NULL;
@@ -304,9 +351,12 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
        struct mm_struct *mm = task->mm;
 
        cc->nr = 0;
+       cc->unw_rc = QUADD_URC_FP_INCORRECT;
 
-       if (!regs || !mm)
+       if (!regs || !mm) {
+               cc->unw_rc = QUADD_URC_FAILURE;
                return 0;
+       }
 
        sp = quadd_user_stack_pointer(regs);
        pc = instruction_pointer(regs);
@@ -316,8 +366,10 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
                return 0;
 
        vma = find_vma(mm, sp);
-       if (!vma)
+       if (!vma) {
+               cc->unw_rc = QUADD_URC_SP_INCORRECT;
                return 0;
+       }
 
        if (!is_vma_addr(fp, vma, sizeof(fp)))
                return 0;
@@ -326,6 +378,7 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
                pr_warn_once("frame error: sp/fp: %#x/%#x, pc/lr: %#x/%#x, vma: %#lx-%#lx\n",
                             sp, fp, pc, (u32)quadd_user_link_register(regs),
                             vma->vm_start, vma->vm_end);
+               cc->unw_rc = QUADD_URC_EACCESS;
                return 0;
        }
 
@@ -341,8 +394,10 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
                        if (__copy_from_user_inatomic(
                                        &value,
                                        (u32 __user *)(fp + sizeof(u32)),
-                                       sizeof(value)))
+                                       sizeof(value))) {
+                               cc->unw_rc = QUADD_URC_EACCESS;
                                return 0;
+                       }
 
                        vma_pc = find_vma(mm, pc);
                        read_lr = 1;
@@ -350,12 +405,18 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
 
                if (!read_lr || !is_vma_addr(value, vma_pc, sizeof(value))) {
                        /* gcc: fp --> short frame tail (fp) */
+                       int nr_added;
                        u32 lr = quadd_user_link_register(regs);
 
-                       if (lr < QUADD_USER_SPACE_MIN_ADDR)
+                       if (lr < QUADD_USER_SPACE_MIN_ADDR) {
+                               cc->unw_rc = QUADD_URC_PC_INCORRECT;
                                return 0;
+                       }
+
+                       nr_added = quadd_callchain_store(cc, lr);
+                       if (nr_added == 0)
+                               return cc->nr;
 
-                       quadd_callchain_store(cc, lr);
                        tail = (u32 __user *)(unsigned long)reg;
                }
        }
@@ -376,19 +437,24 @@ __user_backtrace_compat(struct quadd_callchain *cc, struct task_struct *task)
        struct vm_area_struct *vma;
        u32 __user *tail;
 
-       if (!mm)
-               goto out;
+       cc->unw_rc = QUADD_URC_FP_INCORRECT;
+
+       if (!mm) {
+               cc->unw_rc = QUADD_URC_FAILURE;
+               return cc->nr;
+       }
 
        vma = find_vma(mm, cc->curr_sp);
-       if (!vma)
-               goto out;
+       if (!vma) {
+               cc->unw_rc = QUADD_URC_SP_INCORRECT;
+               return cc->nr;
+       }
 
        tail = (u32 __user *)cc->curr_fp;
 
        while (tail && !((unsigned long)tail & 0x3))
                tail = user_backtrace_compat(tail, cc, vma);
 
-out:
        return cc->nr;
 }
 
@@ -401,6 +467,10 @@ __get_user_callchain_fp(struct pt_regs *regs,
 {
        if (cc->nr > 0) {
                int nr, nr_prev = cc->nr;
+
+               if (cc->unw_rc == QUADD_URC_LEVEL_TOO_DEEP)
+                       return nr_prev;
+
 #ifdef CONFIG_ARM64
                if (compat_user_mode(regs))
                        nr = __user_backtrace_compat(cc, task);
@@ -435,6 +505,7 @@ quadd_get_user_callchain(struct pt_regs *regs,
        struct quadd_parameters *param = &ctx->param;
 
        cc->nr = 0;
+       cc->unw_method = QUADD_URC_FAILURE;
 
        if (!regs)
                return 0;
index 3fed6c571d457bfc91e2fccb5de39dde97e51ac8..9820f428c54c897fb3dd47b5011b346328a22f10 100644 (file)
@@ -890,6 +890,7 @@ static int comm_init(void)
        res = misc_register(misc_dev);
        if (res < 0) {
                pr_err("Error: misc_register: %d\n", res);
+               kfree(misc_dev);
                return res;
        }
        comm_ctx.misc_dev = misc_dev;
index 7ef25ed22848b8e2e4ca39f3a45dcf4989003c36..9121b965b96c8a9562448720995898acffa7b756 100644 (file)
@@ -965,6 +965,7 @@ unwind_backtrace(struct quadd_callchain *cc,
 
        while (1) {
                long err;
+               int nr_added;
                unsigned long where = frame.pc;
                struct vm_area_struct *vma_pc;
                struct mm_struct *mm = task->mm;
@@ -1001,10 +1002,12 @@ unwind_backtrace(struct quadd_callchain *cc,
                pr_debug("function at [<%08lx>] from [<%08lx>]\n",
                         where, frame.pc);
 
-               quadd_callchain_store(cc, frame.pc);
-
                cc->curr_sp = frame.sp;
                cc->curr_fp = frame.fp_arm;
+
+               nr_added = quadd_callchain_store(cc, frame.pc);
+               if (nr_added == 0)
+                       break;
        }
 }
 
index c25384429cfdbff54d52851709d8c654b92a9112..8c2b6b706dc028163217f5639533ead177d3c7bb 100644 (file)
@@ -292,6 +292,7 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
        vec_idx++;
 
        s->reserved = 0;
+       cc->unw_method = QUADD_URC_SUCCESS;
 
        if (ctx->param.backtrace) {
                bt_size = quadd_get_user_callchain(user_regs, cc, ctx, task);
@@ -318,10 +319,7 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task)
                }
 
                extra_data |= cc->unw_method << QUADD_SED_UNW_METHOD_SHIFT;
-
-               if (cc->unw_method == QUADD_UNW_METHOD_EHT ||
-                   cc->unw_method == QUADD_UNW_METHOD_MIXED)
-                       s->reserved |= cc->unw_rc << QUADD_SAMPLE_URC_SHIFT;
+               s->reserved |= cc->unw_rc << QUADD_SAMPLE_URC_SHIFT;
        }
        s->callchain_nr = bt_size;
 
index 487d984a1b11734effb4c270f31da65cee091da5..786cb1bdfb876c992ed94fa2e5b24abeac05f237 100644 (file)
@@ -179,7 +179,7 @@ set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid)
        unsigned int extra;
 
        if (!validate_freq(p->freq)) {
-               pr_err("%s: incorrect frequency: %u", __func__, p->freq);
+               pr_err("%s: incorrect frequency: %u\n", __func__, p->freq);
                return -EINVAL;
        }
 
index 0dc8129a6b5f19f50df386ebfa0ea79a68ee27e5..1414cdd63bc6bde55a90e65225dabe695882ba23 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.67"
+#define QUADD_MODULE_VERSION           "1.68"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index 30bec737e39fc47505333a5cb8b330548a12b312..fe65583f9f3f58270c4468f46d28320b545f5ce7 100644 (file)
@@ -165,6 +165,8 @@ enum {
        QUADD_URC_SPARE_ENCODING,
        QUADD_URC_UNSUPPORTED_PR,
        QUADD_URC_PC_INCORRECT,
+       QUADD_URC_LEVEL_TOO_DEEP,
+       QUADD_URC_FP_INCORRECT,
        QUADD_URC_MAX,
 };