diff options
Diffstat (limited to 'libdwfl/frame_unwind.c')
| -rw-r--r-- | libdwfl/frame_unwind.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c index 4dc9c432..8da691ee 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -442,7 +442,7 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops, } if (val1 == 0) break; - /* FALLTHRU */ + FALLTHROUGH; case DW_OP_skip:; Dwarf_Word offset = op->offset + 1 + 2 + (int16_t) op->number; const Dwarf_Op *found = bsearch ((void *) (uintptr_t) offset, ops, nops, @@ -632,24 +632,38 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) ra_set = true; } } - if (unwound->pc_state == DWFL_FRAME_STATE_ERROR - && __libdwfl_frame_reg_get (unwound, - frame->fde->cie->return_address_register, - &unwound->pc)) + if (unwound->pc_state == DWFL_FRAME_STATE_ERROR) { - /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. Currently - none of the archs supported for unwinding have zero as a valid PC. */ - if (unwound->pc == 0) - unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + if (__libdwfl_frame_reg_get (unwound, + frame->fde->cie->return_address_register, + &unwound->pc)) + { + /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. + Currently none of the archs supported for unwinding have + zero as a valid PC. */ + if (unwound->pc == 0) + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + else + { + unwound->pc_state = DWFL_FRAME_STATE_PC_SET; + /* In SPARC the return address register actually contains + the address of the call instruction instead of the return + address. Therefore we add here an offset defined by the + backend. Most likely 0. */ + unwound->pc += ebl_ra_offset (ebl); + } + } else - { - unwound->pc_state = DWFL_FRAME_STATE_PC_SET; - /* In SPARC the return address register actually contains - the address of the call instruction instead of the return - address. Therefore we add here an offset defined by the - backend. Most likely 0. */ - unwound->pc += ebl_ra_offset (ebl); - } + { + /* We couldn't set the return register, either it was bogus, + or the return pc is undefined, maybe end of call stack. */ + unsigned pcreg = frame->fde->cie->return_address_register; + if (! ebl_dwarf_to_regno (ebl, &pcreg) + || pcreg >= ebl_frame_nregs (ebl)) + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + else + unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + } } free (frame); } |
