summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorIgor Nabirushkin <inabirushkin@nvidia.com>2015-02-13 23:21:22 +0400
committerWinnie Hsu <whsu@nvidia.com>2015-05-29 14:24:34 -0700
commit73ef5a836aec5c8bee753790e1f6002b7602a342 (patch)
tree6f0cb1ae76491b82111b90572471543a61b3c14b /drivers/misc
parentcce82cdcece7b05d6245a46d2033bdb4a8c710f2 (diff)
misc: tegra-profiler: support debug frame sections
DWARF unwinding: support debug frame sections (AArch32/AArch64). Bug 1611073 Change-Id: Ia7a01c61843d35d8c5466623be7d8e44fc70f5a1 Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com> Reviewed-on: http://git-master/r/707910 (cherry picked from commit d39c08f5f586453c55c42a91bccd8452343c5236) Reviewed-on: http://git-master/r/747747 GVS: Gerrit_Virtual_Submit Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com> Reviewed-by: Winnie Hsu <whsu@nvidia.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/tegra-profiler/dwarf.h4
-rw-r--r--drivers/misc/tegra-profiler/dwarf_unwind.c428
-rw-r--r--drivers/misc/tegra-profiler/eh_unwind.c32
-rw-r--r--drivers/misc/tegra-profiler/eh_unwind.h9
-rw-r--r--drivers/misc/tegra-profiler/version.h2
5 files changed, 294 insertions, 181 deletions
diff --git a/drivers/misc/tegra-profiler/dwarf.h b/drivers/misc/tegra-profiler/dwarf.h
index 4b81ef171331..e7aec6b20c67 100644
--- a/drivers/misc/tegra-profiler/dwarf.h
+++ b/drivers/misc/tegra-profiler/dwarf.h
@@ -77,5 +77,9 @@
#define DW_EH_PE_indirect 0x80
+#define DW_CIE_ID 0xffffffff
+#define DW64_CIE_ID 0xffffffffffffffffULL
+
+#define DW_CIE_VERSION 1
#endif /* __QUADD_DWARF_H */
diff --git a/drivers/misc/tegra-profiler/dwarf_unwind.c b/drivers/misc/tegra-profiler/dwarf_unwind.c
index 9121a83fb49e..b5582a7c55e2 100644
--- a/drivers/misc/tegra-profiler/dwarf_unwind.c
+++ b/drivers/misc/tegra-profiler/dwarf_unwind.c
@@ -114,7 +114,7 @@ struct dwarf_cpu_context {
struct regs_state rs_stack[DW_MAX_RS_STACK_DEPTH];
int depth;
- int dw_word_size;
+ int dw_ptr_size;
};
struct quadd_dwarf_context {
@@ -224,6 +224,33 @@ get_user_reg_size(int mode)
}
static inline int
+get_secid_frame(int is_eh)
+{
+ return is_eh ?
+ QUADD_SEC_TYPE_EH_FRAME :
+ QUADD_SEC_TYPE_DEBUG_FRAME;
+}
+
+static inline int
+get_secid_frame_hdr(int is_eh)
+{
+ return is_eh ?
+ QUADD_SEC_TYPE_EH_FRAME_HDR :
+ QUADD_SEC_TYPE_DEBUG_FRAME_HDR;
+}
+
+static inline int
+is_frame_present(struct ex_region_info *ri, int is_eh)
+{
+ struct extab_info *ti, *ti_hdr;
+
+ ti = &ri->ex_sec[get_secid_frame(is_eh)];
+ ti_hdr = &ri->ex_sec[get_secid_frame_hdr(is_eh)];
+
+ return (ti->length && ti_hdr->length) ? 1 : 0;
+}
+
+static inline int
validate_addr(struct ex_region_info *ri,
unsigned long addr,
unsigned long nbytes,
@@ -554,14 +581,14 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
char encoding,
int st)
{
- int dw_word_size, count = 0;
+ int dw_ptr_size, count = 0;
long stmp = 0, err = 0;
unsigned long utmp, res = 0;
struct dwarf_cpu_context *cpu_ctx = this_cpu_ptr(ctx.cpu_ctx);
pr_debug("encoding: %#x\n", encoding);
- dw_word_size = cpu_ctx->dw_word_size;
+ dw_ptr_size = cpu_ctx->dw_ptr_size;
if (encoding == DW_EH_PE_omit) {
pr_debug("DW_EH_PE_omit\n");
@@ -570,13 +597,13 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
return 0;
} else if (encoding == DW_EH_PE_aligned) {
unsigned long aligned = ALIGN((unsigned long)addr,
- dw_word_size);
+ dw_ptr_size);
pr_debug("DW_EH_PE_aligned\n");
- if (dw_word_size == 4) {
+ if (dw_ptr_size == 4) {
*val = read_mmap_data_u32(ri, (u32 *)aligned, st, &err);
- } else if (dw_word_size == 8) {
+ } else if (dw_ptr_size == 8) {
*val = read_mmap_data_u64(ri, (u64 *)aligned, st, &err);
} else {
pr_err_once("%s: error: encoding\n", __func__);
@@ -586,16 +613,16 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
if (err)
return err;
- return dw_word_size;
+ return dw_ptr_size;
}
switch (encoding & 0x0f) {
case DW_EH_PE_absptr:
pr_debug("%s: absptr encoding\n", __func__);
- if (dw_word_size == 4) {
+ if (dw_ptr_size == 4) {
*val = read_mmap_data_u32(ri, (u32 *)addr, st, &err);
- } else if (dw_word_size == 8) {
+ } else if (dw_ptr_size == 8) {
*val = read_mmap_data_u64(ri, (u64 *)addr, st, &err);
} else {
pr_err_once("error: wrong dwarf size\n");
@@ -605,7 +632,7 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
if (err)
return err;
- return dw_word_size;
+ return dw_ptr_size;
case DW_EH_PE_sdata2:
case DW_EH_PE_udata2:
@@ -694,10 +721,10 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
if (encoding & DW_EH_PE_indirect) {
pr_debug("DW_EH_PE_indirect\n");
- if (dw_word_size == 4) {
+ if (dw_ptr_size == 4) {
res = read_mmap_data_u32(ri, (u32 *)res,
st, &err);
- } else if (dw_word_size == 8) {
+ } else if (dw_ptr_size == 8) {
res = read_mmap_data_u64(ri, (u64 *)res,
st, &err);
} else {
@@ -722,16 +749,19 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
unsigned char *insn_end,
struct dw_cie *cie,
struct stackframe *sf,
- unsigned long pc)
+ unsigned long pc,
+ int is_eh)
{
unsigned char insn;
unsigned char *c_insn;
- unsigned int expr_len, delta;
+ unsigned int expr_len, delta, secid;
unsigned long utmp, reg;
long offset, stmp, err = 0;
struct regs_state *rs, *rs_initial, *rs_stack;
struct dwarf_cpu_context *cpu_ctx = this_cpu_ptr(ctx.cpu_ctx);
+ secid = get_secid_frame(is_eh);
+
rs = &sf->rs;
rs_initial = &sf->rs_initial;
@@ -742,7 +772,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
while (c_insn < insn_end && sf->pc <= pc) {
insn = read_mmap_data_u8(ri, c_insn++,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
@@ -758,8 +788,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_offset:
reg = dw_cfa_operand(insn);
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -787,8 +816,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_advance_loc1:
delta = read_mmap_data_u8(ri, c_insn++,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -800,8 +828,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_advance_loc2:
delta = read_mmap_data_u16(ri, (u16 *)c_insn,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -814,8 +841,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_advance_loc4:
delta = read_mmap_data_u32(ri, (u32 *)c_insn,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -828,15 +854,13 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_offset_extended:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
reg = utmp;
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -847,8 +871,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_restore_extended:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -857,8 +880,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_undefined:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -868,15 +890,13 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
rs->cfa_register = utmp;
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -888,8 +908,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa_register:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -900,8 +919,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa_offset:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -912,8 +930,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa_expression:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -930,16 +947,14 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_expression:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
set_rule_exp(rs, reg, DW_WHERE_EXPR, c_insn);
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -950,14 +965,12 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_offset_extended_sf:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -969,14 +982,12 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_val_offset:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -988,13 +999,12 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_val_offset_sf:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1006,8 +1016,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_GNU_args_size:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1016,14 +1025,12 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_GNU_negative_offset_extended:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1057,14 +1064,12 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa_sf:
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1079,8 +1084,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_def_cfa_offset_sf:
c_insn += dwarf_read_sleb128(ri, c_insn, &stmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1091,8 +1095,7 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_same_value:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1102,15 +1105,13 @@ dwarf_cfa_exec_insns(struct ex_region_info *ri,
case DW_CFA_val_expression:
c_insn += dwarf_read_uleb128(ri, c_insn, &reg,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
set_rule_exp(rs, reg, DW_WHERE_VAL_EXPR, c_insn);
c_insn += dwarf_read_uleb128(ri, c_insn, &utmp,
- QUADD_SEC_TYPE_EH_FRAME,
- &err);
+ secid, &err);
if (err)
return err;
@@ -1132,28 +1133,35 @@ static long
decode_cie_entry(struct ex_region_info *ri,
struct dw_cie *cie,
unsigned char *entry,
- size_t length)
+ size_t length,
+ int is_eh)
{
long err;
unsigned long utmp;
unsigned char *p, *end, *aug;
+ unsigned int secid, cie_id;
unsigned int cie_version, id, len, max_len;
+ secid = get_secid_frame(is_eh);
+
p = entry;
end = entry + length;
p += sizeof(u32);
- id = read_mmap_data_u32(ri, (u32 *)p, QUADD_SEC_TYPE_EH_FRAME, &err);
+ id = read_mmap_data_u32(ri, (u32 *)p, secid, &err);
if (err)
return err;
p += sizeof(u32);
- if (id != 0)
+ cie_id = is_eh ? 0 : DW_CIE_ID;
+ if (id != cie_id) {
+ pr_err_once("error: incorrect cie_id");
return -QUADD_URC_TBL_IS_CORRUPT;
+ }
- cie_version = read_mmap_data_u8(ri, p++, QUADD_SEC_TYPE_EH_FRAME, &err);
+ cie_version = read_mmap_data_u8(ri, p++, secid, &err);
if (err)
return err;
@@ -1176,24 +1184,24 @@ decode_cie_entry(struct ex_region_info *ri,
pr_debug("aug_string: %s\n", cie->aug_string);
p += dwarf_read_uleb128(ri, p, &cie->code_align_factor,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
p += dwarf_read_sleb128(ri, p, &cie->data_align_factor,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
if (cie_version == 1) {
cie->retaddr_reg = read_mmap_data_u8(ri, p++,
- QUADD_SEC_TYPE_EH_FRAME,
+ secid,
&err);
if (err)
return err;
} else {
p += dwarf_read_uleb128(ri, p, &utmp,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
@@ -1210,7 +1218,7 @@ decode_cie_entry(struct ex_region_info *ri,
if (*aug == 'z') {
p += dwarf_read_uleb128(ri, p, &cie->aug_size,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
@@ -1218,8 +1226,6 @@ decode_cie_entry(struct ex_region_info *ri,
aug++;
cie->z_aug = 1;
- } else {
- pr_warn_once("warning: !aug_z\n");
}
cie->fde_encoding = 0;
@@ -1233,7 +1239,7 @@ decode_cie_entry(struct ex_region_info *ri,
if (*aug == 'L') {
cie->lsda_encoding =
read_mmap_data_u8(ri, p++,
- QUADD_SEC_TYPE_EH_FRAME,
+ secid,
&err);
if (err)
return err;
@@ -1242,7 +1248,7 @@ decode_cie_entry(struct ex_region_info *ri,
} else if (*aug == 'R') {
cie->fde_encoding =
read_mmap_data_u8(ri, p++,
- QUADD_SEC_TYPE_EH_FRAME,
+ secid,
&err);
if (err)
return err;
@@ -1260,12 +1266,12 @@ decode_cie_entry(struct ex_region_info *ri,
pcrel_base = (void *)
mmap_addr_to_ex_addr((unsigned long)p,
ri,
- QUADD_SEC_TYPE_EH_FRAME);
+ secid);
cnt = dwarf_read_encoded_value(ri, p, pcrel_base,
&personality,
handler_encoding,
- QUADD_SEC_TYPE_EH_FRAME);
+ secid);
if (cnt < 0) {
pr_err_once("%s: error: personality routine\n",
__func__);
@@ -1305,14 +1311,17 @@ static long
decode_fde_entry(struct ex_region_info *ri,
struct dw_fde *fde,
unsigned char *entry,
- size_t length)
+ size_t length,
+ int is_eh)
{
- int count;
+ int count, secid;
long err = 0;
unsigned long utmp;
unsigned char *p, *end, *pcrel_base;
struct dw_cie *cie = fde->cie;
+ secid = get_secid_frame(is_eh);
+
p = entry;
end = entry + length;
@@ -1320,31 +1329,34 @@ decode_fde_entry(struct ex_region_info *ri,
p += sizeof(u32);
pcrel_base = (unsigned char *)
- mmap_addr_to_ex_addr((unsigned long)p, ri,
- QUADD_SEC_TYPE_EH_FRAME);
+ mmap_addr_to_ex_addr((unsigned long)p, ri, secid);
count = dwarf_read_encoded_value(ri, p, pcrel_base,
&fde->initial_location,
cie->fde_encoding,
- QUADD_SEC_TYPE_EH_FRAME);
+ secid);
if (count < 0)
return count;
p += count;
fde->address_range = read_mmap_data_u32(ri, (u32 *)p,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
p += sizeof(u32);
+ if (fde->initial_location < ri->vm_start)
+ fde->initial_location += ri->vm_start;
+
+ pr_debug("pcrel_base: %p\n", pcrel_base);
pr_debug("init location: %#lx\n", fde->initial_location);
pr_debug("address_range: %#lx\n", fde->address_range);
if (cie->z_aug) {
p += dwarf_read_uleb128(ri, p, &utmp,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
@@ -1409,9 +1421,10 @@ dwarf_get_bs_table(struct ex_region_info *ri,
void *data,
unsigned long length,
unsigned long data_base,
- unsigned long *nr_entries)
+ unsigned long *nr_entries,
+ int is_eh)
{
- int count;
+ int count, secid_hdr;
unsigned char *p, *end;
struct dw_fde_table *bst;
unsigned long fde_count, frame_ptr;
@@ -1424,6 +1437,8 @@ dwarf_get_bs_table(struct ex_region_info *ri,
pr_debug("hdr: %p\n", hdr);
+ secid_hdr = get_secid_frame_hdr(is_eh);
+
if (hdr->version != 1) {
pr_warn_once("warning: unknown eh hdr format\n");
return NULL;
@@ -1434,7 +1449,7 @@ dwarf_get_bs_table(struct ex_region_info *ri,
count = dwarf_read_encoded_value(ri, p, (void *)data_base,
&frame_ptr,
hdr->eh_frame_ptr_enc,
- QUADD_SEC_TYPE_EH_FRAME_HDR);
+ secid_hdr);
if (count < 0)
return NULL;
@@ -1446,7 +1461,7 @@ dwarf_get_bs_table(struct ex_region_info *ri,
count = dwarf_read_encoded_value(ri, p, (void *)data_base,
&fde_count, hdr->fde_count_enc,
- QUADD_SEC_TYPE_EH_FRAME_HDR);
+ secid_hdr);
if (count < 0)
return NULL;
@@ -1466,6 +1481,8 @@ dwarf_get_bs_table(struct ex_region_info *ri,
bst = (struct dw_fde_table *)p;
*nr_entries = fde_count;
+ pr_debug("bst: %lu fde entries\n", fde_count);
+
return bst;
}
@@ -1473,9 +1490,11 @@ static long
dwarf_decode_fde_cie(struct ex_region_info *ri,
unsigned char *fde_p,
struct dw_cie *cie,
- struct dw_fde *fde)
+ struct dw_fde *fde,
+ int is_eh)
{
u32 *p;
+ int secid;
long err;
unsigned char *cie_p;
unsigned long cie_pointer, length;
@@ -1483,26 +1502,27 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
unsigned long frame_len, addr;
struct extab_info *ti;
- ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME];
+ secid = get_secid_frame(is_eh);
+ ti = &ri->ex_sec[secid];
addr = ti->addr;
frame_start = (unsigned char *)
- ex_addr_to_mmap_addr(addr, ri, QUADD_SEC_TYPE_EH_FRAME);
+ ex_addr_to_mmap_addr(addr, ri, secid);
frame_len = ti->length;
- pr_debug("eh frame: %p - %p\n",
+ pr_debug("frame: %p - %p\n",
frame_start, frame_start + frame_len);
p = (u32 *)fde_p;
- length = read_mmap_data_u32(ri, p++, QUADD_SEC_TYPE_EH_FRAME, &err);
+ length = read_mmap_data_u32(ri, p++, secid, &err);
if (err)
return err;
if (length == 0xffffffff) {
- pr_warn_once("warning: 64-bit .eh_frame is not supported\n");
+ pr_warn_once("warning: 64-bit frame is not supported\n");
return -QUADD_URC_UNHANDLED_INSTRUCTION;
}
@@ -1512,20 +1532,22 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
pr_debug("FDE: fde_p: %p, offset: %#lx, len: %#lx\n",
fde_p, fde->offset, fde->length);
- cie_pointer = read_mmap_data_u32(ri, p, QUADD_SEC_TYPE_EH_FRAME, &err);
+ cie_pointer = read_mmap_data_u32(ri, p, secid, &err);
if (err)
return err;
fde->cie_pointer = cie_pointer;
- cie_p = (unsigned char *)p - cie_pointer;
+
+ cie_p = is_eh ? (unsigned char *)p - cie_pointer :
+ frame_start + cie_pointer;
length = read_mmap_data_u32(ri, (u32 *)cie_p,
- QUADD_SEC_TYPE_EH_FRAME, &err);
+ secid, &err);
if (err)
return err;
if (length == 0xffffffff) {
- pr_warn_once("warning: 64-bit .eh_frame is not supported\n");
+ pr_warn_once("warning: 64-bit frame is not supported\n");
return -QUADD_URC_UNHANDLED_INSTRUCTION;
}
@@ -1535,13 +1557,13 @@ dwarf_decode_fde_cie(struct ex_region_info *ri,
pr_debug("CIE: cie_p: %p, offset: %#lx, len: %#lx\n",
cie_p, cie->offset, cie->length);
- err = decode_cie_entry(ri, cie, cie_p, cie->length);
+ err = decode_cie_entry(ri, cie, cie_p, cie->length, is_eh);
if (err < 0)
return err;
fde->cie = cie;
- err = decode_fde_entry(ri, fde, fde_p, fde->length);
+ err = decode_fde_entry(ri, fde, fde_p, fde->length, is_eh);
if (err < 0)
return err;
@@ -1552,19 +1574,25 @@ static void *
dwarf_find_fde(struct ex_region_info *ri,
void *data,
unsigned long length,
- unsigned long pc)
+ unsigned long pc,
+ int is_eh)
{
long err;
+ int secid, secid_hdr;
const struct dw_fde_table *fi;
unsigned long fde_count = 0, data_base;
unsigned long fde_addr, init_loc;
struct dw_fde_table *bst;
struct extab_info *ti;
- ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+ secid = get_secid_frame(is_eh);
+ secid_hdr = get_secid_frame_hdr(is_eh);
+
+ ti = &ri->ex_sec[secid_hdr];
data_base = ti->addr;
- bst = dwarf_get_bs_table(ri, data, length, data_base, &fde_count);
+ bst = dwarf_get_bs_table(ri, data, length, data_base,
+ &fde_count, is_eh);
if (!bst || fde_count == 0) {
pr_warn_once("warning: bs_table\n");
return NULL;
@@ -1573,34 +1601,41 @@ dwarf_find_fde(struct ex_region_info *ri,
fi = &bst[fde_count - 1];
init_loc = dw_bst_get_initial_loc(fi, data_base);
+ pr_debug("pc: %#lx, last bst init_loc: %#lx", pc, init_loc);
+
if (pc >= init_loc) {
unsigned long start, end;
+ struct extab_info *ti = &ri->ex_sec[secid];
fde_addr = dw_bst_get_fde_addr(fi, data_base);
fde_addr = ex_addr_to_mmap_addr(fde_addr, ri,
- QUADD_SEC_TYPE_EH_FRAME);
+ secid);
if (pc == init_loc)
return (void *)fde_addr;
- if (ri->tf_end > 0) {
- start = ri->tf_start;
- end = ri->tf_end;
+ if (ti->tf_end > 0) {
+ start = ti->tf_start;
+ end = ti->tf_end;
} else {
struct dw_cie cie;
struct dw_fde fde;
err = dwarf_decode_fde_cie(ri, (void *)fde_addr,
- &cie, &fde);
+ &cie, &fde, is_eh);
if (err < 0)
return NULL;
start = fde.initial_location;
end = start + fde.address_range;
- quadd_unwind_set_tail_info(ri->vm_start, start, end);
+ quadd_unwind_set_tail_info(ri->vm_start, secid,
+ start, end);
}
+ pr_debug("pc: %#lx, last bst entry: %#lx - %#lx",
+ pc, start, end);
+
return (pc >= start && pc < end) ?
(void *)fde_addr : NULL;
}
@@ -1610,40 +1645,90 @@ dwarf_find_fde(struct ex_region_info *ri,
return NULL;
fde_addr = dw_bst_get_fde_addr(fi, data_base);
- fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, QUADD_SEC_TYPE_EH_FRAME);
+ fde_addr = ex_addr_to_mmap_addr(fde_addr, ri, secid);
return (void *)fde_addr;
}
+static int
+__is_fde_entry_exist(struct ex_region_info *ri, unsigned long addr, int is_eh)
+{
+ int secid_hdr;
+ unsigned char *fde_p;
+ struct extab_info *ti;
+ unsigned char *hdr_start;
+ unsigned long hdr_len, a;
+
+ secid_hdr = get_secid_frame_hdr(is_eh);
+
+ ti = &ri->ex_sec[secid_hdr];
+
+ a = ti->addr;
+
+ hdr_start = (unsigned char *)
+ ex_addr_to_mmap_addr(a, ri, secid_hdr);
+
+ hdr_len = ti->length;
+
+ fde_p = dwarf_find_fde(ri, hdr_start, hdr_len, addr, is_eh);
+
+ return fde_p ? 1 : 0;
+}
+
+static int
+is_fde_entry_exist(struct ex_region_info *ri,
+ unsigned long addr,
+ int *is_eh,
+ int *is_debug)
+{
+ *is_eh = 0;
+ *is_debug = 0;
+
+ if (is_frame_present(ri, 1)) {
+ if (__is_fde_entry_exist(ri, addr, 1))
+ *is_eh = 1;
+ }
+
+ if (is_frame_present(ri, 0)) {
+ if (__is_fde_entry_exist(ri, addr, 0))
+ *is_debug = 1;
+ }
+
+ return (*is_eh || *is_debug) ? 1 : 0;
+}
+
static long
dwarf_decode(struct ex_region_info *ri,
struct dw_cie *cie,
struct dw_fde *fde,
- unsigned long pc)
+ unsigned long pc,
+ int is_eh)
{
long err;
+ int secid_hdr;
unsigned char *fde_p;
unsigned char *hdr_start;
unsigned long hdr_len, addr;
struct extab_info *ti;
- ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+ secid_hdr = get_secid_frame_hdr(is_eh);
+ ti = &ri->ex_sec[secid_hdr];
addr = ti->addr;
hdr_start = (unsigned char *)
- ex_addr_to_mmap_addr(addr, ri, QUADD_SEC_TYPE_EH_FRAME_HDR);
+ ex_addr_to_mmap_addr(addr, ri, secid_hdr);
hdr_len = ti->length;
pr_debug("eh frame hdr: %p - %p\n",
hdr_start, hdr_start + hdr_len);
- fde_p = dwarf_find_fde(ri, hdr_start, hdr_len, pc);
+ fde_p = dwarf_find_fde(ri, hdr_start, hdr_len, pc, is_eh);
if (!fde_p)
return -QUADD_URC_IDX_NOT_FOUND;
- err = dwarf_decode_fde_cie(ri, fde_p, cie, fde);
+ err = dwarf_decode_fde_cie(ri, fde_p, cie, fde, is_eh);
if (err < 0)
return err;
@@ -1680,7 +1765,8 @@ static long
unwind_frame(struct ex_region_info *ri,
struct stackframe *sf,
struct vm_area_struct *vma_sp,
- unsigned int *unw_type)
+ unsigned int *unw_type,
+ int is_eh)
{
int i;
long err;
@@ -1692,7 +1778,7 @@ unwind_frame(struct ex_region_info *ri,
struct regs_state *rs, *rs_initial;
int mode = sf->mode;
- err = dwarf_decode(ri, &cie, &fde, pc);
+ err = dwarf_decode(ri, &cie, &fde, pc, is_eh);
if (err < 0)
return err;
@@ -1711,7 +1797,7 @@ unwind_frame(struct ex_region_info *ri,
if (cie.initial_insn) {
insn_end = cie.initial_insn + cie.initial_insn_len;
err = dwarf_cfa_exec_insns(ri, cie.initial_insn,
- insn_end, &cie, sf, pc);
+ insn_end, &cie, sf, pc, is_eh);
if (err)
return err;
}
@@ -1721,7 +1807,7 @@ unwind_frame(struct ex_region_info *ri,
if (fde.instructions) {
insn_end = fde.instructions + fde.insn_length;
err = dwarf_cfa_exec_insns(ri, fde.instructions,
- insn_end, fde.cie, sf, pc);
+ insn_end, fde.cie, sf, pc, is_eh);
if (err)
return err;
}
@@ -1820,7 +1906,7 @@ unwind_backtrace(struct quadd_callchain *cc,
unsigned long user_reg_size;
struct ex_region_info ri_new;
unsigned int unw_type = QUADD_UNW_TYPE_UT;
- int mode = sf->mode;
+ int is_eh = 1, mode = sf->mode;
cc->unw_rc = QUADD_URC_FAILURE;
user_reg_size = get_user_reg_size(mode);
@@ -1828,10 +1914,10 @@ unwind_backtrace(struct quadd_callchain *cc,
while (1) {
long sp, err;
int nr_added;
+ int __is_eh, __is_debug;
struct vm_area_struct *vma_pc;
unsigned long addr, where = sf->pc;
struct mm_struct *mm = task->mm;
- struct extab_info *ti;
if (!mm)
break;
@@ -1847,28 +1933,55 @@ unwind_backtrace(struct quadd_callchain *cc,
if (!vma_pc)
break;
- ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
- addr = ti->addr;
+ addr = ri->vm_start;
if (!is_vma_addr(addr, vma_pc, user_reg_size)) {
- err = quadd_get_extabs_ehframe(vma_pc->vm_start,
- &ri_new);
+ err = quadd_get_dw_frames(vma_pc->vm_start, &ri_new);
if (err) {
cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
break;
}
+ pr_debug("ri: %#lx ---> %#lx",
+ ri->vm_start, ri_new.vm_start);
+
ri = &ri_new;
}
- err = unwind_frame(ri, sf, vma_sp, &unw_type);
- if (err < 0) {
- cc->unw_rc = -err;
+ if (!is_fde_entry_exist(ri, sf->pc, &__is_eh, &__is_debug)) {
+ pr_debug("eh/debug fde entries are not existed\n");
+ cc->unw_rc = QUADD_URC_IDX_NOT_FOUND;
break;
}
+ pr_debug("is_eh: %d, is_debug: %d\n", __is_eh, __is_debug);
+
+ if (is_eh) {
+ if (!__is_eh)
+ is_eh = 0;
+ } else {
+ if (!__is_debug)
+ is_eh = 1;
+ }
+
+ err = unwind_frame(ri, sf, vma_sp, &unw_type, is_eh);
+ if (err < 0) {
+ if (__is_eh && __is_debug) {
+ is_eh ^= 1;
+
+ err = unwind_frame(ri, sf, vma_sp,
+ &unw_type, is_eh);
+ if (err < 0) {
+ cc->unw_rc = -err;
+ break;
+ }
+ } else {
+ cc->unw_rc = -err;
+ break;
+ }
+ }
- pr_debug("function at [<%08lx>] from [<%08lx>]\n",
- where, sf->pc);
+ 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)];
@@ -1886,13 +1999,10 @@ quadd_is_ex_entry_exist_dwarf(struct pt_regs *regs,
struct task_struct *task)
{
long err;
- unsigned char *fde_p;
+ int is_eh, is_debug;
struct ex_region_info ri;
- unsigned char *hdr_start;
- unsigned long hdr_len, a;
struct vm_area_struct *vma;
struct mm_struct *mm = task->mm;
- struct extab_info *ti;
if (!regs || !mm)
return 0;
@@ -1901,24 +2011,11 @@ quadd_is_ex_entry_exist_dwarf(struct pt_regs *regs,
if (!vma)
return 0;
- err = quadd_get_extabs_ehframe(vma->vm_start, &ri);
+ err = quadd_get_dw_frames(vma->vm_start, &ri);
if (err)
return 0;
- ti = &ri.ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
-
- a = ti->addr;
-
- hdr_start = (unsigned char *)
- ex_addr_to_mmap_addr(a, &ri, QUADD_SEC_TYPE_EH_FRAME_HDR);
-
- hdr_len = ti->length;
-
- fde_p = dwarf_find_fde(&ri, hdr_start, hdr_len, addr);
- if (!fde_p)
- return 0;
-
- return 1;
+ return is_fde_entry_exist(&ri, addr, &is_eh, &is_debug);
}
unsigned int
@@ -1977,7 +2074,6 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
mode = DW_MODE_ARM32;
#endif
-
pr_debug("%s: pc: %#lx, lr: %#lx\n", __func__, ip, lr);
pr_debug("%s: sp: %#lx, fp: %#lx, fp_thumb: %#lx\n",
__func__, sp, fp, fp_thumb);
@@ -1990,7 +2086,7 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
sf.vregs[ARM32_FP_THUMB] = fp_thumb;
- cpu_ctx->dw_word_size = (mode == DW_MODE_ARM32) ?
+ cpu_ctx->dw_ptr_size = (mode == DW_MODE_ARM32) ?
sizeof(u32) : sizeof(u64);
sf.mode = mode;
@@ -2007,7 +2103,7 @@ quadd_get_user_cc_dwarf(struct pt_regs *regs,
if (!vma_sp)
return 0;
- err = quadd_get_extabs_ehframe(vma->vm_start, &ri);
+ err = quadd_get_dw_frames(vma->vm_start, &ri);
if (err) {
cc->unw_rc = QUADD_URC_TBL_NOT_EXIST;
return 0;
@@ -2026,8 +2122,10 @@ int quadd_dwarf_unwind_start(void)
{
if (!atomic_cmpxchg(&ctx.started, 0, 1)) {
ctx.cpu_ctx = alloc_percpu(struct dwarf_cpu_context);
- if (!ctx.cpu_ctx)
+ if (!ctx.cpu_ctx) {
+ atomic_set(&ctx.started, 0);
return -ENOMEM;
+ }
}
return 0;
diff --git a/drivers/misc/tegra-profiler/eh_unwind.c b/drivers/misc/tegra-profiler/eh_unwind.c
index 1c3e68013115..888c2d49b037 100644
--- a/drivers/misc/tegra-profiler/eh_unwind.c
+++ b/drivers/misc/tegra-profiler/eh_unwind.c
@@ -1,5 +1,5 @@
/*
- * drivers/misc/tegra-profiler/eh_unwind.c
+ * drivers/misc/tegra-profiler/exh_tables.c
*
* Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
*
@@ -371,19 +371,25 @@ get_extabs_ehabi(unsigned long key, struct ex_region_info *ri)
}
long
-quadd_get_extabs_ehframe(unsigned long key, struct ex_region_info *ri)
+quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri)
{
long err;
- struct extab_info *ti_ehfr, *ti_ehfr_hdr;
+ struct extab_info *ti, *ti_hdr;
err = search_ex_region(key, ri);
if (err < 0)
return err;
- ti_ehfr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME];
- ti_ehfr_hdr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
+ ti = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME];
+ ti_hdr = &ri->ex_sec[QUADD_SEC_TYPE_EH_FRAME_HDR];
- return (ti_ehfr->length && ti_ehfr_hdr->length) ? 0 : -ENOENT;
+ if (ti->length && ti_hdr->length)
+ return 0;
+
+ ti = &ri->ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME];
+ ti_hdr = &ri->ex_sec[QUADD_SEC_TYPE_DEBUG_FRAME_HDR];
+
+ return (ti->length && ti_hdr->length) ? 0 : -ENOENT;
}
static struct regions_data *rd_alloc(unsigned long size)
@@ -466,14 +472,14 @@ int quadd_unwind_set_extab(struct quadd_sections *extabs,
ri_entry.mmap = mmap;
- ri_entry.tf_start = 0;
- ri_entry.tf_end = 0;
-
for (i = 0; i < QUADD_SEC_TYPE_MAX; i++) {
struct quadd_sec_info *si = &extabs->sec[i];
ti = &ri_entry.ex_sec[i];
+ ti->tf_start = 0;
+ ti->tf_end = 0;
+
if (!si->addr) {
ti->addr = 0;
ti->length = 0;
@@ -521,12 +527,14 @@ error_out:
void
quadd_unwind_set_tail_info(unsigned long vm_start,
+ int secid,
unsigned long tf_start,
unsigned long tf_end)
{
struct ex_region_info *ri;
unsigned long nr_entries, size;
struct regions_data *rd, *rd_new;
+ struct extab_info *ti;
spin_lock(&ctx.lock);
@@ -553,8 +561,10 @@ quadd_unwind_set_tail_info(unsigned long vm_start,
if (!ri)
goto error_free;
- ri->tf_start = tf_start;
- ri->tf_end = tf_end;
+ ti = &ri->ex_sec[secid];
+
+ ti->tf_start = tf_start;
+ ti->tf_end = tf_end;
rcu_assign_pointer(ctx.rd, rd_new);
diff --git a/drivers/misc/tegra-profiler/eh_unwind.h b/drivers/misc/tegra-profiler/eh_unwind.h
index 7ce0f828b9e5..31eb008a7222 100644
--- a/drivers/misc/tegra-profiler/eh_unwind.h
+++ b/drivers/misc/tegra-profiler/eh_unwind.h
@@ -48,6 +48,7 @@ quadd_is_ex_entry_exist_arm32_ehabi(struct pt_regs *regs,
void
quadd_unwind_set_tail_info(unsigned long vm_start,
+ int secid,
unsigned long tf_start,
unsigned long tf_end);
@@ -57,6 +58,9 @@ struct extab_info {
unsigned long length;
unsigned long mmap_offset;
+
+ unsigned long tf_start;
+ unsigned long tf_end;
};
struct ex_region_info {
@@ -67,12 +71,9 @@ struct ex_region_info {
struct quadd_mmap_area *mmap;
struct list_head list;
-
- unsigned long tf_start;
- unsigned long tf_end;
};
long
-quadd_get_extabs_ehframe(unsigned long key, struct ex_region_info *ri);
+quadd_get_dw_frames(unsigned long key, struct ex_region_info *ri);
#endif /* __QUADD_EH_UNWIND_H__ */
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h
index fb60632eb25c..2211061c9f69 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.89"
+#define QUADD_MODULE_VERSION "1.90"
#define QUADD_MODULE_BRANCH "Dev"
#endif /* __QUADD_VERSION_H */