diff options
author | xiabin <snyh@snyh.org> | 2018-12-12 23:28:32 +0800 |
---|---|---|
committer | Dave Watson <davejwatson@fb.com> | 2018-12-12 07:28:32 -0800 |
commit | 5eec9a2ecb9a93996d566bbfbcdbe006f64b7e16 (patch) | |
tree | dcbccfc5cb7f808030b530d69bbdfd2e7e4df122 | |
parent | d7528ef9643e479aa22040e59d796f9a18a5cf12 (diff) | |
download | libunwind-5eec9a2ecb9a93996d566bbfbcdbe006f64b7e16.tar.gz |
mips: Handle Gstep according the N64/N32 ABI if Dwarf way failed (#100)
- gp at 8(sp)
- fp at 16(sp)
- ra at 24(sp)
-rw-r--r-- | src/mips/Gget_proc_info.c | 11 | ||||
-rw-r--r-- | src/mips/Gstep.c | 92 |
2 files changed, 96 insertions, 7 deletions
diff --git a/src/mips/Gget_proc_info.c b/src/mips/Gget_proc_info.c index 7b84be87..04c4326d 100644 --- a/src/mips/Gget_proc_info.c +++ b/src/mips/Gget_proc_info.c @@ -30,11 +30,14 @@ unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi) struct cursor *c = (struct cursor *) cursor; int ret; - /* We can only unwind using Dwarf into on MIPS: return failure code - if it's not present. */ ret = dwarf_make_proc_info (&c->dwarf); - if (ret < 0) - return ret; + if (ret < 0) { + /* Construct a dummy proc info if Dwarf failed */ + memset (pi, 0, sizeof (*pi)); + pi->start_ip = c->dwarf.ip; + pi->end_ip = c->dwarf.ip + 4; + return 0; + } *pi = c->dwarf.pi; return 0; diff --git a/src/mips/Gstep.c b/src/mips/Gstep.c index 937136ae..f5a742e1 100644 --- a/src/mips/Gstep.c +++ b/src/mips/Gstep.c @@ -110,6 +110,90 @@ mips_handle_signal_frame (unw_cursor_t *cursor) return 1; } + +int _step_n64(struct cursor *c) +{ + //TODO:handle plt entry + struct dwarf_loc fp_loc, pc_loc; + int ret; + unw_word_t fp = 0; + unw_word_t ra = 0; + + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R30], &fp); + if (ret < 0) + { + Debug (2, "returning %d [FP=0x%lx]\n", ret, + DWARF_GET_LOC (c->dwarf.loc[UNW_MIPS_R30])); + return ret; + } + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R31], &ra); + if (ret < 0) + { + Debug (2, "returning %d [RA=0x%lx]\n", ret, + DWARF_GET_LOC (c->dwarf.loc[UNW_MIPS_R31])); + return ret; + } + + if (!fp) { + fp_loc = DWARF_NULL_LOC; + pc_loc = DWARF_NULL_LOC; + } else { + fp_loc = DWARF_LOC(fp+16, 0); + pc_loc = DWARF_LOC (fp+24, 0); +#if UNW_DEBUG + unw_word_t fp1 = 0; + ret = dwarf_get (&c->dwarf, fp_loc, &fp1); + Debug (1, "RET:%d [FP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx. SAVED PC:0x%lx\n", + ret, + (unsigned long) DWARF_GET_LOC (c->dwarf.loc[UNW_MIPS_R30]), + fp, c->dwarf.cfa, fp1, ra); +#endif + /* Heuristic to determine incorrect guess. For FP to be a + valid frame it needs to be above current CFA, but don't + let it go more than a little. Note that we can't deduce + anything about new FP (fp1) since it may not be a frame + pointer in the frame above. Just check we get the value. */ + if (ret < 0 + || fp < c->dwarf.cfa + || (fp - c->dwarf.cfa) > 0x4000) + { + pc_loc = DWARF_NULL_LOC; + fp_loc = DWARF_NULL_LOC; + } + } + + c->dwarf.loc[UNW_MIPS_R30] = fp_loc; + + c->dwarf.loc[UNW_MIPS_PC] = c->dwarf.loc[UNW_MIPS_R31]; + c->dwarf.loc[UNW_MIPS_R31] = pc_loc; + c->dwarf.use_prev_instr = 1; + + if (DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_MIPS_R30])) + { + ret = 0; + Debug (2, "NULL %%fp loc, returning %d\n", ret); + return ret; + } + + if (!DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_MIPS_PC])) + { + ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_PC], &c->dwarf.ip); + Debug (1, "Frame Chain [IP=0x%Lx] = 0x%Lx\n", + (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[UNW_MIPS_PC]), + (unsigned long long) c->dwarf.ip); + if (ret < 0) + { + Debug (2, "returning %d\n", ret); + return ret; + } + ret = 1; + } + else { + c->dwarf.ip = 0; + } + return (c->dwarf.ip == 0) ? 0 : 1; +} + int unw_step (unw_cursor_t *cursor) { @@ -124,9 +208,11 @@ unw_step (unw_cursor_t *cursor) if (unlikely (ret == -UNW_ESTOPUNWIND)) return ret; - /* Dwarf unwinding didn't work, stop. */ +#if _MIPS_SIM == _ABI64 if (unlikely (ret < 0)) - return 0; - + { + return _step_n64(c); + } +#endif return (c->dwarf.ip == 0) ? 0 : 1; } |