PROTECTED int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; int ret = -UNW_EUNSPEC; Debug (1, "(cursor=%p)\n", c); /* Check if this is a signal frame. */ if (unw_is_signal_frame (cursor)) return unw_handle_signal_frame (cursor); #ifdef CONFIG_DEBUG_FRAME /* First, try DWARF-based unwinding. */ if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) { ret = dwarf_step (&c->dwarf); Debug(1, "dwarf_step()=%d\n", ret); if (likely (ret > 0)) return 1; else if (unlikely (ret == -UNW_ESTOPUNWIND)) return ret; if (ret < 0 && ret != -UNW_ENOINFO) { Debug (2, "returning %d\n", ret); return ret; } } #endif /* CONFIG_DEBUG_FRAME */ /* Next, try extbl-based unwinding. */ if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)) { ret = arm_exidx_step (c); if (ret > 0) return 1; if (ret == -UNW_ESTOPUNWIND || ret == 0) return ret; } /* Fall back on APCS frame parsing. Note: This won't work in case the ARM EABI is used. */ if (unlikely (ret < 0)) { if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME)) { ret = UNW_ESUCCESS; /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */ unw_word_t instr, i; Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); dwarf_loc_t ip_loc, fp_loc; unw_word_t frame; /* Mark all registers unsaved, since we don't know where they are saved (if at all), except for the EBP and EIP. */ if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0) { return 0; } for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) { c->dwarf.loc[i] = DWARF_NULL_LOC; } if (frame) { if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0) { return 0; } instr -= 8; if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0) { return 0; } if ((instr & 0xFFFFD800) == 0xE92DD800) { /* Standard APCS frame. */ ip_loc = DWARF_LOC(frame - 4, 0); fp_loc = DWARF_LOC(frame - 12, 0); } else { /* Codesourcery optimized normal frame. */ ip_loc = DWARF_LOC(frame, 0); fp_loc = DWARF_LOC(frame - 4, 0); } if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0) { return 0; } c->dwarf.loc[UNW_ARM_R12] = ip_loc; c->dwarf.loc[UNW_ARM_R11] = fp_loc; Debug(15, "ip=%lx\n", c->dwarf.ip); } else { ret = -UNW_ENOINFO; } } } return ret == -UNW_ENOINFO ? 0 : 1; }
PROTECTED int unw_step (unw_cursor_t *cursor) { struct cursor *c = (struct cursor *) cursor; int ret = -UNW_EUNSPEC; Debug (1, "(cursor=%p)\n", c); /* Try DWARF-based unwinding... this is the only method likely to work for ARM. */ if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) { ret = dwarf_step (&c->dwarf); Debug(1, "dwarf_step()=%d\n", ret); if (unlikely (ret == -UNW_ESTOPUNWIND)) return ret; if (ret < 0 && ret != -UNW_ENOINFO) { Debug (2, "returning %d\n", ret); return ret; } } if (unlikely (ret < 0)) { if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME)) { ret = UNW_ESUCCESS; /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */ unw_word_t instr, i; Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); dwarf_loc_t ip_loc, fp_loc; unw_word_t frame; /* Mark all registers unsaved, since we don't know where they are saved (if at all), except for the EBP and EIP. */ if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0) { return 0; } for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) { c->dwarf.loc[i] = DWARF_NULL_LOC; } if (frame) { if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0) { return 0; } instr -= 8; if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0) { return 0; } if ((instr & 0xFFFFD800) == 0xE92DD800) { /* Standard APCS frame. */ ip_loc = DWARF_LOC(frame - 4, 0); fp_loc = DWARF_LOC(frame - 12, 0); } else { /* Codesourcery optimized normal frame. */ ip_loc = DWARF_LOC(frame, 0); fp_loc = DWARF_LOC(frame - 4, 0); } if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0) { return 0; } c->dwarf.loc[UNW_ARM_R12] = ip_loc; c->dwarf.loc[UNW_ARM_R11] = fp_loc; Debug(15, "ip=%lx\n", c->dwarf.ip); } else { ret = -UNW_ENOINFO; } } } return ret == -UNW_ENOINFO ? 0 : 1; }