diff options
author | Igor Nabirushkin <inabirushkin@nvidia.com> | 2014-12-02 15:48:47 +0400 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2015-01-29 22:04:47 -0800 |
commit | 35b5c2255719adc77d7dade3da0ad41e55f7d295 (patch) | |
tree | 01c76e70859a8414c2a5178a7da993a210293f85 /drivers/misc/tegra-profiler/eh_unwind.c | |
parent | 091550d652f58ecbb8772e18ef1471ddeb96cc8b (diff) |
misc: tegra-profiler: fix vsp increment
Decode the unwinding instructions (AArch32): fix incorrect
increment of virtual stack pointer (vsp).
Bug 1584541
Bug 1598009
Change-Id: I4ec64eb21a758b9283df9e6bd6b87a0555180eab
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: http://git-master/r/658441
(cherry picked from commit c963ce2532586098ddae159d19a2e241fc25cd1a)
Reviewed-on: http://git-master/r/672040
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers/misc/tegra-profiler/eh_unwind.c')
-rw-r--r-- | drivers/misc/tegra-profiler/eh_unwind.c | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/drivers/misc/tegra-profiler/eh_unwind.c b/drivers/misc/tegra-profiler/eh_unwind.c index 728ca6394f99..a097fd8d1067 100644 --- a/drivers/misc/tegra-profiler/eh_unwind.c +++ b/drivers/misc/tegra-profiler/eh_unwind.c @@ -667,6 +667,39 @@ unwind_get_byte(struct quadd_mmap_area *mmap, return ret; } +static long +read_uleb128(struct quadd_mmap_area *mmap, + struct unwind_ctrl_block *ctrl, + unsigned long *ret) +{ + long err = 0; + unsigned long result; + unsigned char byte; + int shift, count; + + result = 0; + shift = 0; + count = 0; + + while (1) { + byte = unwind_get_byte(mmap, ctrl, &err); + if (err < 0) + return err; + + count++; + + result |= (byte & 0x7f) << shift; + shift += 7; + + if (!(byte & 0x80)) + break; + } + + *ret = result; + + return count; +} + /* * Execute the current unwind instruction. */ @@ -790,14 +823,21 @@ unwind_exec_insn(struct quadd_mmap_area *mmap, ctrl->vrs[SP] = (u32)(unsigned long)vsp; pr_debug("new vsp: %#x\n", ctrl->vrs[SP]); } else if (insn == 0xb2) { - unsigned long uleb128 = unwind_get_byte(mmap, ctrl, &err); - if (err < 0) - return err; + long count; + unsigned long uleb128 = 0; + + count = read_uleb128(mmap, ctrl, &uleb128); + if (count < 0) + return count; + + if (count == 0) + return -QUADD_URC_TBL_IS_CORRUPT; ctrl->vrs[SP] += 0x204 + (uleb128 << 2); - pr_debug("CMD_DATA_POP: vsp = vsp + %lu, new vsp: %#x\n", - 0x204 + (uleb128 << 2), ctrl->vrs[SP]); + pr_debug("CMD_DATA_POP: vsp = vsp + %lu (%#lx), new vsp: %#x\n", + 0x204 + (uleb128 << 2), 0x204 + (uleb128 << 2), + ctrl->vrs[SP]); } else if (insn == 0xb3 || insn == 0xc8 || insn == 0xc9) { unsigned long data, reg_from, reg_to; u32 *vsp = (u32 *)(unsigned long)ctrl->vrs[SP]; |