summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2014-09-02 00:23:11 +0400
committerWinnie Hsu <whsu@nvidia.com>2015-01-29 22:01:52 -0800
commite1ed05e3358062b7059ae9718e363f3fb8797da1 (patch)
tree61b7615da78a6189fe91bade917511f976c05021
parent6fb43a5f1c04e04b83cef5c1fa22d9f460596efa (diff)
misc: tegra-profiler: fix broken call chains
Dwarf unwinding on AArch64: fix broken call chains for some types of functions. Bug 1549713 Bug 1598009 Change-Id: Ia3d51723f6381befe01481a5d4d3b4041ad7b411 Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com> Reviewed-on: http://git-master/r/494632 (cherry picked from commit ec10a69ec9999ff7937a520caa9e562c38b826c6) Reviewed-on: http://git-master/r/672020 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
-rw-r--r--drivers/misc/tegra-profiler/dwarf_unwind.c59
-rw-r--r--drivers/misc/tegra-profiler/version.h2
2 files changed, 40 insertions, 21 deletions
diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c
index a2e1add126bb..c4c620e6df7e 100644
--- a/drivers/misc/tegra-profiler/dwarf_unwind.c
+++ b/drivers/misc/tegra-profiler/dwarf_unwind.c
@@ -21,7 +21,6 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/err.h>
-#include <linux/ratelimit.h>
#include <asm/unaligned.h>
@@ -130,7 +129,6 @@ struct dw_cie {
unsigned char fde_encoding;
unsigned char lsda_encoding;
- unsigned char per_encoding;
unsigned long code_align_factor;
long data_align_factor;
@@ -139,8 +137,8 @@ struct dw_cie {
unsigned char *initial_insn;
int z_aug;
-
unsigned int retaddr_reg;
+ void *personality;
unsigned char *data;
};
@@ -168,7 +166,6 @@ struct eh_sec_data {
};
typedef u64 dw_word_t;
-#define dw_addr_size sizeof(dw_word_t)
#define read_user_data(addr, retval) \
({ \
@@ -523,13 +520,18 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
long stmp = 0, err = 0;
unsigned long utmp, res = 0;
+ pr_debug("encoding: %#x\n", encoding);
+
if (encoding == DW_EH_PE_omit) {
+ pr_debug("DW_EH_PE_omit\n");
+
*val = 0;
return 0;
} else if (encoding == DW_EH_PE_aligned) {
- unsigned long aligned =
- ((unsigned long)addr + dw_addr_size - 1) &
- -dw_addr_size;
+ unsigned long aligned = ALIGN((unsigned long)addr,
+ sizeof(dw_word_t));
+
+ pr_debug("DW_EH_PE_aligned\n");
if (sizeof(dw_word_t) == 4) {
*val = read_mmap_data_u32(ri, (u32 *)aligned, st, &err);
@@ -543,7 +545,6 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
if (err)
return err;
- pr_debug("DW_EH_PE_aligned\n");
return sizeof(dw_word_t);
}
@@ -556,8 +557,8 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
} else if (sizeof(dw_word_t) == 8) {
*val = read_mmap_data_u64(ri, (u64 *)addr, st, &err);
} else {
- pr_err_once("%s: error: encoding\n", __func__);
- return -QUADD_URC_TBL_IS_CORRUPT;
+ pr_err_once("error: wrong dwarf size\n");
+ return -QUADD_URC_UNHANDLED_INSTRUCTION;
}
if (err)
@@ -659,12 +660,13 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
res = read_mmap_data_u64(ri, (u64 *)res,
st, &err);
} else {
- pr_err_once("%s: error: encoding\n", __func__);
- return -QUADD_URC_TBL_IS_CORRUPT;
+ pr_err_once("error: wrong dwarf size\n");
+ return -QUADD_URC_UNHANDLED_INSTRUCTION;
}
+ /* we ignore links to unloaded sections */
if (err)
- return err;
+ res = 0;
}
}
@@ -1148,8 +1150,8 @@ decode_cie_entry(struct ex_region_info *ri,
}
cie->fde_encoding = 0;
- cie->per_encoding = 0;
cie->lsda_encoding = DW_EH_PE_omit;
+ cie->personality = NULL;
while (*aug != '\0') {
if (p >= end)
@@ -1173,14 +1175,31 @@ decode_cie_entry(struct ex_region_info *ri,
aug++;
pr_debug("fde_encoding: %#x\n", cie->fde_encoding);
} else if (*aug == 'P') {
- cie->per_encoding = read_mmap_data_u8(ri, p++,
- DW_SEC_TYPE_TAB,
- &err);
- if (err)
- return err;
+ int count;
+ void *pcrel_base;
+ unsigned char handler_encoding;
+ unsigned long personality;
+
+ handler_encoding = *p++;
+
+ pcrel_base = (void *)
+ mmap_addr_to_ex_addr((unsigned long)p,
+ ri, DW_SEC_TYPE_TAB);
+
+ count = dwarf_read_encoded_value(ri, p, pcrel_base,
+ &personality,
+ handler_encoding,
+ DW_SEC_TYPE_TAB);
+ if (count < 0) {
+ pr_err_once("%s: error: personality routine\n",
+ __func__);
+ return count;
+ }
+ p += count;
+ pr_debug("personality: %#lx\n", personality);
+ cie->personality = (void *)personality;
aug++;
- pr_debug("%s: aug: P\n", __func__);
} else if (*aug == 'S') {
aug++;
pr_debug("%s: aug: S\n", __func__);
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h
index 0d67c39d1fc0..5da67cea3ab9 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.80"
+#define QUADD_MODULE_VERSION "1.81"
#define QUADD_MODULE_BRANCH "Dev"
#endif /* __QUADD_VERSION_H */