summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2015-03-21 20:33:09 +0400
committerWinnie Hsu <whsu@nvidia.com>2015-05-29 14:28:17 -0700
commit79352cdce0bb4d1960ed912216fc9cb43d9b1efa (patch)
treeab5254b53bc07f531fea646e8714a9e124d0c1c9
parent628479e4e44c3b647d0affefb4c4a1018d8cc44f (diff)
misc: tegra-profiler: cleanup unwinding rules
DWARF unwinding: cleanup unwinding rules for frames. It fixes some broken backtraces. Bug 1626528 Change-Id: Iaa62528cc0b6b97f1763934ef641791f196897b0 Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com> Reviewed-on: http://git-master/r/720600 (cherry picked from commit 3d68bdc1d81dce7176a8efec54dc5501e55e5eb5) Reviewed-on: http://git-master/r/748090 GVS: Gerrit_Virtual_Submit Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com> Reviewed-by: Winnie Hsu <whsu@nvidia.com>
-rw-r--r--drivers/misc/tegra-profiler/dwarf_unwind.c47
-rw-r--r--drivers/misc/tegra-profiler/version.h2
2 files changed, 31 insertions, 18 deletions
diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c
index d48e4b8da817..3a57a61b58bd 100644
--- a/drivers/misc/tegra-profiler/dwarf_unwind.c
+++ b/drivers/misc/tegra-profiler/dwarf_unwind.c
@@ -573,6 +573,19 @@ dw_cfa_operand(unsigned int insn)
return insn & 0x3f;
}
+static void
+rules_cleanup(struct regs_state *rs, int mode)
+{
+ int i, num_regs;
+
+ num_regs = (mode == DW_MODE_ARM32) ?
+ QUADD_AARCH32_REGISTERS :
+ QUADD_AARCH64_REGISTERS;
+
+ for (i = 0; i < num_regs; i++)
+ set_rule(rs, i, DW_WHERE_UNDEF, 0);
+}
+
static int
dwarf_read_encoded_value(struct ex_region_info *ri,
void *addr,
@@ -1767,7 +1780,7 @@ unwind_frame(struct ex_region_info *ri,
struct vm_area_struct *vma_sp,
int is_eh)
{
- int i;
+ int i, num_regs;
long err;
unsigned char *insn_end;
unsigned long addr, return_addr, val, user_reg_size;
@@ -1789,7 +1802,7 @@ unwind_frame(struct ex_region_info *ri,
rs->cfa_register = -1;
rs_initial->cfa_register = -1;
- set_rule(rs, regnum_lr(mode), DW_WHERE_UNDEF, 0);
+ rules_cleanup(rs, mode);
if (cie.initial_insn) {
insn_end = cie.initial_insn + cie.initial_insn_len;
@@ -1818,7 +1831,8 @@ unwind_frame(struct ex_region_info *ri,
if (err < 0)
return err;
- pr_debug("pc: %#lx, lr: %#lx\n", sf->pc, sf->vregs[regnum_lr(mode)]);
+ pr_debug("pc: %#lx, exec pc: %#lx, lr: %#lx\n",
+ pc, sf->pc, sf->vregs[regnum_lr(mode)]);
pr_debug("sp: %#lx, fp: %#lx, fp_thumb: %#lx\n",
sf->vregs[regnum_sp(mode)],
@@ -1845,7 +1859,11 @@ unwind_frame(struct ex_region_info *ri,
pr_debug("cfa_register: %u\n", rs->cfa_register);
pr_debug("new cfa: %#lx\n", sf->cfa);
- for (i = 0; i < QUADD_NUM_REGS; i++) {
+ num_regs = (mode == DW_MODE_ARM32) ?
+ QUADD_AARCH32_REGISTERS :
+ QUADD_AARCH64_REGISTERS;
+
+ for (i = 0; i < num_regs; i++) {
switch (rs->reg[i].where) {
case DW_WHERE_UNDEF:
break;
@@ -1875,8 +1893,8 @@ unwind_frame(struct ex_region_info *ri,
break;
default:
- pr_err_once("[r%d] error: unsupported rule\n",
- rs->reg[i].where);
+ pr_err_once("[r%d] error: unsupported rule (%d)\n",
+ i, rs->reg[i].where);
break;
}
}
@@ -2028,7 +2046,7 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
struct task_struct *task)
{
long err;
- int i, mode, nr_prev = cc->nr;
+ int mode, nr_prev = cc->nr;
unsigned long ip, lr, sp, fp, fp_thumb;
struct vm_area_struct *vma, *vma_sp;
struct mm_struct *mm = task->mm;
@@ -2057,10 +2075,10 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
#ifdef CONFIG_ARM64
if (compat_user_mode(regs)) {
- fp = regs->compat_usr(11);
- fp_thumb = regs->compat_usr(7);
+ fp = regs->compat_usr(ARM32_FP);
+ fp_thumb = regs->compat_usr(ARM32_FP_THUMB);
} else {
- fp = regs->regs[29];
+ fp = regs->regs[ARM64_FP];
fp_thumb = 0;
}
#else
@@ -2070,10 +2088,8 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
}
#ifdef CONFIG_ARM64
- if (compat_user_mode(regs))
- mode = DW_MODE_ARM32;
- else
- mode = DW_MODE_ARM64;
+ mode = compat_user_mode(regs) ?
+ DW_MODE_ARM32 : DW_MODE_ARM64;
#else
mode = DW_MODE_ARM32;
#endif
@@ -2097,9 +2113,6 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
sf.mode = mode;
sf.cfa = 0;
- for (i = 0; i < QUADD_NUM_REGS; i++)
- set_rule(&sf.rs, i, DW_WHERE_UNDEF, 0);
-
vma = find_vma(mm, ip);
if (!vma)
return 0;
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h
index b5b6ef4c8eee..b26eb4e09f63 100644
--- a/drivers/misc/tegra-profiler/version.h
+++ b/drivers/misc/tegra-profiler/version.h
@@ -18,7 +18,7 @@
#ifndef __QUADD_VERSION_H
#define __QUADD_VERSION_H
-#define QUADD_MODULE_VERSION "1.99"
+#define QUADD_MODULE_VERSION "1.100"
#define QUADD_MODULE_BRANCH "Dev"
#endif /* __QUADD_VERSION_H */