misc: tegra-profiler: fix broken backtraces
Igor Nabirushkin [Sat, 21 Mar 2015 15:39:55 +0000 (19:39 +0400)]
Unwinding based on arm32 ehabi: fix broken backtraces when
all unwind entries are located in exidx section and
extab section is not exist.

Bug 1625585

Change-Id: I800e1347b04aa2c2c8802b81478931985c19feb2
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/720598
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Tested-by: Maxim Morin <mmorin@nvidia.com>
Reviewed-by: Dmitry Antipov <dantipov@nvidia.com>
Reviewed-by: Andrey Trachenko <atrachenko@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

drivers/misc/tegra-profiler/eh_unwind.c
drivers/misc/tegra-profiler/version.h
include/linux/tegra_profiler.h

index e3e0955..11dadb9 100644 (file)
@@ -103,14 +103,14 @@ validate_mmap_addr(struct quadd_mmap_area *mmap,
        if (addr & 0x03) {
                pr_err_once("%s: error: unaligned address: %#lx, data: %#lx-%#lx, vma: %#lx-%#lx\n",
                            __func__, addr, data, data + size,
-                      vma->vm_start, vma->vm_end);
+                           vma->vm_start, vma->vm_end);
                return 0;
        }
 
        if (addr < data || addr >= data + (size - nbytes)) {
                pr_err_once("%s: error: addr: %#lx, data: %#lx-%#lx, vma: %#lx-%#lx\n",
                            __func__, addr, data, data + size,
-                      vma->vm_start, vma->vm_end);
+                           vma->vm_start, vma->vm_end);
                return 0;
        }
 
@@ -155,8 +155,10 @@ ex_addr_to_mmap_addr(unsigned long addr,
        struct extab_info *ti;
 
        ti = &ri->ex_sec[sec_type];
-       offset = addr - ti->addr;
+       if (unlikely(!ti->length))
+               return 0;
 
+       offset = addr - ti->addr;
        return ti->mmap_offset + offset + (unsigned long)ri->mmap->data;
 }
 
@@ -169,8 +171,10 @@ mmap_addr_to_ex_addr(unsigned long addr,
        struct extab_info *ti;
 
        ti = &ri->ex_sec[sec_type];
-       offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data;
+       if (unlikely(!ti->length))
+               return 0;
 
+       offset = addr - ti->mmap_offset - (unsigned long)ri->mmap->data;
        return ti->addr + offset;
 }
 
@@ -200,6 +204,9 @@ mmap_prel31_to_addr(const u32 *ptr, struct ex_region_info *ri,
        offset = (((s32)value) << 1) >> 1;
 
        addr = mmap_addr_to_ex_addr((unsigned long)ptr, ri, src_type);
+       if (unlikely(!addr))
+               return 0;
+
        addr += offset;
        addr_res = addr;
 
@@ -361,16 +368,14 @@ static long
 get_extabs_ehabi(unsigned long key, struct ex_region_info *ri)
 {
        long err;
-       struct extab_info *ti_extab, *ti_exidx;
+       struct extab_info *ti_exidx;
 
        err = search_ex_region(key, ri);
        if (err < 0)
                return err;
 
-       ti_extab = &ri->ex_sec[QUADD_SEC_TYPE_EXTAB];
        ti_exidx = &ri->ex_sec[QUADD_SEC_TYPE_EXIDX];
-
-       return (ti_extab->length && ti_exidx->length) ? 0 : -ENOENT;
+       return ti_exidx->length ? 0 : -ENOENT;
 }
 
 long
@@ -664,13 +669,13 @@ unwind_find_idx(struct ex_region_info *ri, u32 addr, unsigned long *lowaddr)
        value = (u32)mmap_prel31_to_addr(&start->addr_offset, ri,
                                         QUADD_SEC_TYPE_EXIDX,
                                         QUADD_SEC_TYPE_EXTAB, 0);
-       if (addr < value)
+       if (!value || addr < value)
                return NULL;
 
        value = (u32)mmap_prel31_to_addr(&stop->addr_offset, ri,
                                         QUADD_SEC_TYPE_EXIDX,
                                         QUADD_SEC_TYPE_EXTAB, 0);
-       if (addr >= value)
+       if (!value || addr >= value)
                return NULL;
 
        while (start < stop - 1) {
@@ -679,6 +684,8 @@ unwind_find_idx(struct ex_region_info *ri, u32 addr, unsigned long *lowaddr)
                value = (u32)mmap_prel31_to_addr(&mid->addr_offset, ri,
                                                 QUADD_SEC_TYPE_EXIDX,
                                                 QUADD_SEC_TYPE_EXTAB, 0);
+               if (!value)
+                       return NULL;
 
                if (addr < value)
                        stop = mid;
@@ -1018,7 +1025,7 @@ unwind_frame(struct quadd_unw_methods um,
                                                    QUADD_SEC_TYPE_EXIDX,
                                                    QUADD_SEC_TYPE_EXTAB, 1);
                if (!ctrl.insn)
-                       return -QUADD_URC_EACCESS;
+                       return -QUADD_URC_TBL_LINK_INCORRECT;
        } else if ((val & 0xff000000) == 0x80000000) {
                /* only personality routine 0 supported in the index */
                ctrl.insn = &idx->insn;
index c03ad2f..b5b6ef4 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __QUADD_VERSION_H
 #define __QUADD_VERSION_H
 
-#define QUADD_MODULE_VERSION           "1.98"
+#define QUADD_MODULE_VERSION           "1.99"
 #define QUADD_MODULE_BRANCH            "Dev"
 
 #endif /* __QUADD_VERSION_H */
index a289eb7..3462998 100644 (file)
@@ -193,6 +193,7 @@ enum {
        QUADD_URC_FP_INCORRECT,
        QUADD_URC_NONE,
        QUADD_URC_UNWIND_MISMATCH,
+       QUADD_URC_TBL_LINK_INCORRECT,
        QUADD_URC_MAX,
 };