misc: tegra-profiler: fix validate_addr errors
Igor Nabirushkin [Fri, 11 Nov 2016 09:22:49 +0000 (13:22 +0400)]
DWARF unwinding: do not try to read from unloaded sections

Bug 200176624

Change-Id: I2c0f90857a036a59ef80f905a5d7c7d2faea78b3
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/1168215
(cherry picked from commit b099bf6ed21bb3ff57ad5fe2f18849e67dc8b437)
Reviewed-on: http://git-master/r/1249596
(cherry picked from commit a2edf3f388259bf4b2bca0e0bd4cdec1707bf75e)

drivers/misc/tegra-profiler/dwarf_unwind.c

index 0344d48..191368d 100644 (file)
@@ -414,6 +414,29 @@ mmap_addr_to_ex_addr(unsigned long addr,
        return ti->addr + offset;
 }
 
+static int
+get_section_index_by_address(struct ex_region_info *ri,
+                            unsigned long addr)
+{
+       int i;
+       struct extab_info *ti;
+       unsigned long start, end;
+
+       for (i = 0; i < ARRAY_SIZE(ri->ex_sec); i++) {
+               ti = &ri->ex_sec[i];
+
+               if (ti->length > 0) {
+                       start = ti->addr;
+                       end = start + ti->length;
+
+                       if (addr >= start && addr < end)
+                               return i;
+               }
+       }
+
+       return -QUADD_URC_IDX_NOT_FOUND;
+}
+
 static inline int validate_regnum(struct regs_state *rs, int regnum)
 {
        if (unlikely(regnum >= ARRAY_SIZE(rs->reg))) {
@@ -438,6 +461,20 @@ set_rule_offset(struct regs_state *rs, int regnum, int where, long offset)
        r->loc.offset = offset;
 }
 
+static inline void __maybe_unused
+set_rule_reg(struct regs_state *rs, int regnum, int where, unsigned long reg)
+{
+       struct reg_info *r;
+
+       if (!validate_regnum(rs, regnum))
+               return;
+
+       r = &rs->reg[regnum];
+
+       r->where = where;
+       r->loc.reg = reg;
+}
+
 static inline void
 set_rule_exp(struct regs_state *rs, int regnum,
             int where, const unsigned char *exp)
@@ -719,22 +756,28 @@ dwarf_read_encoded_value(struct ex_region_info *ri,
 
        if (res != 0) {
                if (encoding & DW_EH_PE_indirect) {
-                       pr_debug("DW_EH_PE_indirect\n");
-
-                       if (dw_ptr_size == 4) {
-                               res = read_mmap_data_u32(ri, (u32 *)res,
-                                                        st, &err);
-                       } else if (dw_ptr_size == 8) {
-                               res = read_mmap_data_u64(ri, (u64 *)res,
-                                                        st, &err);
-                       } else {
-                               pr_err_once("error: wrong dwarf size\n");
-                               return -QUADD_URC_UNHANDLED_INSTRUCTION;
-                       }
+                       int sec_idx;
+
+                       pr_debug("DW_EH_PE_indirect, addr: %#lx\n", res);
+
+                       sec_idx = get_section_index_by_address(ri, res);
+                       if (sec_idx >= 0) {
+                               if (dw_ptr_size == 4) {
+                                       res = read_mmap_data_u32(ri, (u32 *)res,
+                                                                sec_idx, &err);
+                               } else if (dw_ptr_size == 8) {
+                                       res = read_mmap_data_u64(ri, (u64 *)res,
+                                                                sec_idx, &err);
+                               } else {
+                                       return -QUADD_URC_UNHANDLED_INSTRUCTION;
+                               }
 
-                       /* we ignore links to unloaded sections */
-                       if (err)
+                               if (err)
+                                       return err;
+                       } else {
+                               /* we ignore links to unloaded sections */
                                res = 0;
+                       }
                }
        }