diff options
author | Igor Nabirushkin <inabirushkin@nvidia.com> | 2014-03-25 13:42:02 +0400 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2014-04-08 06:20:52 -0700 |
commit | 320dd2b8dced7d3d4a34ddf696907459c3e1a0a8 (patch) | |
tree | 8245a071663ff9239e28c22023fabe1c2de77ea8 /drivers/misc/tegra-profiler/backtrace.c | |
parent | 6519e5cbca9d23cf0c3a9998e9c3be481bb498b4 (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.c | 75 |
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; } |