misc: tegra-profiler: fix broken call chains
Igor Nabirushkin [Thu, 26 Feb 2015 11:16:21 +0000 (15:16 +0400)]
Fix broken call chains for thumb code with dwarf and
arm ehabi information simultaneously.

Bug 1615165

Change-Id: If34ecfac26657546170121c363cf89b8b7256dbb
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/711611
(cherry picked from commit 7d98345d6f2f1ba476161d91853dd82b23a92d1d)
Reviewed-on: http://git-master/r/747749
GVS: Gerrit_Virtual_Submit
Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

drivers/misc/tegra-profiler/backtrace.c
drivers/misc/tegra-profiler/backtrace.h
drivers/misc/tegra-profiler/dwarf_unwind.c
drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/version.h

index 352095b..a249bfd 100644 (file)
@@ -168,12 +168,12 @@ user_backtrace(struct pt_regs *regs,
                        return NULL;
                }
 
+               if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
+                       return NULL;
+
                cc->curr_fp = value_fp;
                cc->curr_sp = (unsigned long)tail + sizeof(value_fp);
                cc->curr_pc = value_lr = value;
-
-               if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
-                       return NULL;
        }
 
        fp_prev = (unsigned long __user *)value_fp;
@@ -355,12 +355,12 @@ user_backtrace_compat(struct pt_regs *regs,
                        return NULL;
                }
 
+               if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
+                       return NULL;
+
                cc->curr_fp = value_fp;
                cc->curr_sp = (unsigned long)tail + sizeof(value_fp);
                cc->curr_pc = value_lr = value;
-
-               if (!is_vma_addr(value_fp, stack_vma, sizeof(value_fp)))
-                       return NULL;
        }
 
        fp_prev = (u32 __user *)(unsigned long)value_fp;
@@ -561,9 +561,11 @@ get_user_callchain_mixed(struct pt_regs *regs,
                nr_prev = cc->nr;
 
                quadd_get_user_cc_dwarf(regs, cc, task);
-
                quadd_get_user_cc_arm32_ehabi(regs, cc, task);
 
+               if (nr_prev != cc->nr)
+                       continue;
+
                __get_user_callchain_fp(regs, cc, task);
        } while (nr_prev != cc->nr);
 
@@ -587,6 +589,7 @@ quadd_get_user_callchain(struct pt_regs *regs,
 
        cc->curr_sp = 0;
        cc->curr_fp = 0;
+       cc->curr_fp_thumb = 0;
        cc->curr_pc = 0;
 
 #ifdef CONFIG_ARM64
index 3046ac6..5ee544c 100644 (file)
@@ -44,6 +44,7 @@ struct quadd_callchain {
 
        unsigned long curr_sp;
        unsigned long curr_fp;
+       unsigned long curr_fp_thumb;
        unsigned long curr_pc;
 
        struct quadd_hrt_ctx *hrt;
index b5582a7..72062e6 100644 (file)
@@ -1983,8 +1983,13 @@ unwind_backtrace(struct quadd_callchain *cc,
                pr_debug("[%s]: function at [<%08lx>] from [<%08lx>]\n",
                         is_eh ? "eh" : "debug", where, sf->pc);
 
+
                cc->curr_sp = sf->vregs[regnum_sp(mode)];
+
                cc->curr_fp = sf->vregs[regnum_fp(mode)];
+               if (mode == DW_MODE_ARM32)
+                       cc->curr_fp_thumb = sf->vregs[ARM32_FP_THUMB];
+
                cc->curr_pc = sf->pc;
 
                nr_added = quadd_callchain_store(cc, sf->pc, unw_type);
@@ -2044,7 +2049,7 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
                ip = cc->curr_pc;
                sp = cc->curr_sp;
                fp = cc->curr_fp;
-               fp_thumb = 0;
+               fp_thumb = cc->curr_fp_thumb;
                lr = 0;
        } else {
                ip = instruction_pointer(regs);
@@ -2084,7 +2089,8 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
        sf.vregs[regnum_sp(mode)] = sp;
        sf.vregs[regnum_fp(mode)] = fp;
 
-       sf.vregs[ARM32_FP_THUMB] = fp_thumb;
+       if (mode == DW_MODE_ARM32)
+               sf.vregs[ARM32_FP_THUMB] = fp_thumb;
 
        cpu_ctx->dw_ptr_size = (mode == DW_MODE_ARM32) ?
                                sizeof(u32) : sizeof(u64);
index 888c2d4..e97ed5a 100644 (file)
@@ -1120,6 +1120,7 @@ unwind_backtrace(struct quadd_callchain *cc,
 
                cc->curr_sp = frame->sp;
                cc->curr_fp = frame->fp_arm;
+               cc->curr_fp_thumb = frame->fp_thumb;
                cc->curr_pc = frame->pc;
 
                nr_added = quadd_callchain_store(cc, frame->pc, unw_type);
@@ -1159,7 +1160,7 @@ quadd_get_user_cc_arm32_ehabi(struct pt_regs *regs,
                sp = cc->curr_sp;
                lr = 0;
 
-               frame.fp_thumb = 0;
+               frame.fp_thumb = cc->curr_fp_thumb;
                frame.fp_arm = cc->curr_fp;
        } else {
                ip = instruction_pointer(regs);
@@ -1179,6 +1180,10 @@ quadd_get_user_cc_arm32_ehabi(struct pt_regs *regs,
        frame.sp = sp;
        frame.lr = lr;
 
+       pr_debug("pc: %#lx, lr: %#lx\n", ip, lr);
+       pr_debug("sp: %#lx, fp_arm: %#lx, fp_thumb: %#lx\n",
+                sp, frame.fp_arm, frame.fp_thumb);
+
        vma = find_vma(mm, ip);
        if (!vma)
                return 0;
index 2281ec8..2798614 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.91"
+#define QUADD_MODULE_VERSION           "1.92"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */