summaryrefslogtreecommitdiff
path: root/drivers/misc/tegra-profiler/backtrace.c
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2014-03-25 13:42:02 +0400
committerBharat Nihalani <bnihalani@nvidia.com>2014-04-08 06:20:52 -0700
commit320dd2b8dced7d3d4a34ddf696907459c3e1a0a8 (patch)
tree8245a071663ff9239e28c22023fabe1c2de77ea8 /drivers/misc/tegra-profiler/backtrace.c
parent6519e5cbca9d23cf0c3a9998e9c3be481bb498b4 (diff)
misc: tegra-profiler: add mixed unwinding mode
Tegra Profiler: do not break the chains for mixed code - code with exception-handling tables and code with frame pointers Bug 1487488 Change-Id: I4fdc6708ef2b4e86b354e5a9daeaa19689abb2dd Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com> Reviewed-on: http://git-master/r/386241 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Tested-by: Maxim Morin <mmorin@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'drivers/misc/tegra-profiler/backtrace.c')
-rw-r--r--drivers/misc/tegra-profiler/backtrace.c75
1 files changed, 72 insertions, 3 deletions
diff --git a/drivers/misc/tegra-profiler/backtrace.c b/drivers/misc/tegra-profiler/backtrace.c
index 96f9477e8852..5d29b9d67aa3 100644
--- a/drivers/misc/tegra-profiler/backtrace.c
+++ b/drivers/misc/tegra-profiler/backtrace.c
@@ -214,6 +214,29 @@ get_user_callchain_fp(struct pt_regs *regs,
return cc->nr;
}
+static unsigned int
+__user_backtrace(struct quadd_callchain *cc)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long __user *tail;
+
+ if (!mm)
+ goto out;
+
+ vma = find_vma(mm, cc->curr_sp);
+ if (!vma)
+ goto out;
+
+ tail = (unsigned long __user *)cc->curr_fp;
+
+ while (tail && !((unsigned long)tail & 0x3))
+ tail = user_backtrace(tail, cc, vma);
+
+out:
+ return cc->nr;
+}
+
#ifdef CONFIG_ARM64
static u32 __user *
user_backtrace_compat(u32 __user *tail,
@@ -338,12 +361,52 @@ get_user_callchain_fp_compat(struct pt_regs *regs,
return cc->nr;
}
+
+static unsigned int
+__user_backtrace_compat(struct quadd_callchain *cc)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ u32 __user *tail;
+
+ if (!mm)
+ goto out;
+
+ vma = find_vma(mm, cc->curr_sp);
+ if (!vma)
+ goto out;
+
+ tail = (u32 __user *)cc->curr_fp;
+
+ while (tail && !((unsigned long)tail & 0x3))
+ tail = user_backtrace_compat(tail, cc, vma);
+
+out:
+ return cc->nr;
+}
+
#endif /* CONFIG_ARM64 */
static unsigned int
__get_user_callchain_fp(struct pt_regs *regs,
struct quadd_callchain *cc)
{
+ if (cc->nr > 0) {
+ int nr, nr_prev = cc->nr;
+#ifdef CONFIG_ARM64
+ if (compat_user_mode(regs))
+ nr = __user_backtrace_compat(cc);
+ else
+ nr = __user_backtrace(cc);
+#else
+ nr = __user_backtrace(cc);
+#endif
+ if (nr != nr_prev)
+ cc->unw_method = QUADD_UNW_METHOD_MIXED;
+
+ return nr;
+ }
+
cc->unw_method = QUADD_UNW_METHOD_FP;
#ifdef CONFIG_ARM64
@@ -358,7 +421,7 @@ quadd_get_user_callchain(struct pt_regs *regs,
struct quadd_callchain *cc,
struct quadd_ctx *ctx)
{
- int unw_fp, unw_eht, nr = 0;
+ int unw_fp, unw_eht, unw_mix, nr = 0;
unsigned int extra;
struct quadd_parameters *param = &ctx->param;
@@ -367,6 +430,9 @@ quadd_get_user_callchain(struct pt_regs *regs,
if (!regs)
return 0;
+ cc->curr_sp = 0;
+ cc->curr_fp = 0;
+
#ifdef CONFIG_ARM64
cc->cs_64 = compat_user_mode(regs) ? 0 : 1;
#else
@@ -377,14 +443,17 @@ quadd_get_user_callchain(struct pt_regs *regs,
unw_fp = extra & QUADD_PARAM_EXTRA_BT_FP;
unw_eht = extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES;
+ unw_mix = extra & QUADD_PARAM_EXTRA_BT_MIXED;
cc->unw_rc = 0;
if (unw_eht)
nr = quadd_get_user_callchain_ut(regs, cc);
- if (!nr && unw_fp)
- nr = __get_user_callchain_fp(regs, cc);
+ if (unw_fp) {
+ if (!nr || unw_mix)
+ nr = __get_user_callchain_fp(regs, cc);
+ }
return nr;
}