From: Roland McGrath Date: Sun, 29 Mar 2009 00:15:23 +0000 (-0700) Subject: dwarf_frame_return_address_register -> dwarf_frame_info: return address range too X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fbd13ee52dd9062ac2db6af1a78add0431606a70;p=thirdparty%2Felfutils.git dwarf_frame_return_address_register -> dwarf_frame_info: return address range too --- diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 61852284d..852e57c39 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -86,8 +86,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ dwarf_entry_breakpoints.c \ dwarf_next_cfi.c \ cie.c fde.c unwind.c frame-cache.c \ - dwarf_frame_cfa.c dwarf_frame_register.c \ - dwarf_frame_return_address_register.c \ + dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \ dwarf_cfi_addrframe.c \ dwarf_getcfi.c dwarf_getcfi_elf.c \ dwarf_cfi_setebl.c dwarf_cfi_end.c diff --git a/libdw/dwarf_frame_return_address_register.c b/libdw/dwarf_frame_info.c similarity index 90% rename from libdw/dwarf_frame_return_address_register.c rename to libdw/dwarf_frame_info.c index ef2d7e112..8813c0ad2 100644 --- a/libdw/dwarf_frame_return_address_register.c +++ b/libdw/dwarf_frame_info.c @@ -54,10 +54,21 @@ #include "unwindP.h" int -dwarf_frame_return_address_register (fs, signalp) +dwarf_frame_info (fs, start, end, signalp) Dwarf_Frame *fs; + Dwarf_Addr *start; + Dwarf_Addr *end; bool *signalp; { - *signalp = fs->fde->cie->signal_frame; + /* Maybe there was a previous error. */ + if (fs == NULL) + return -1; + + if (start != NULL) + *start = fs->start; + if (end != NULL) + *end = fs->end; + if (signalp != NULL) + *signalp = fs->fde->cie->signal_frame; return fs->fde->cie->return_address_register; } diff --git a/libdw/libdw.map b/libdw/libdw.map index 1195109a7..93ca3c97f 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -195,7 +195,7 @@ ELFUTILS_0.138 { *; } ELFUTILS_0.136; -ELFUTILS_0.138_UNWIND { +ELFUTILS_0.140_UNWIND { global: # XXX new unwind stuff not decided yet dwarf_next_cfi; @@ -206,7 +206,7 @@ ELFUTILS_0.138_UNWIND { dwarf_cfi_setebl; dwarf_frame_cfa; dwarf_frame_register; - dwarf_frame_return_address_register; + dwarf_frame_info; dwfl_addrframe; dwfl_module_getcfi; } ELFUTILS_0.138; diff --git a/libdw/unwind.c b/libdw/unwind.c index 82380cb1d..487292468 100644 --- a/libdw/unwind.c +++ b/libdw/unwind.c @@ -133,6 +133,8 @@ execute_cfi (Dwarf_CFI *cache, Dwarf_Word operand = opcode & CFI_PRIMARY_MAX; switch (opcode) { + /* These cases move LOC, i.e. "create a new table row". */ + case DW_CFA_advance_loc1: operand = *program++; case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX: @@ -154,6 +156,10 @@ execute_cfi (Dwarf_CFI *cache, loc = read_encoded_value (cache, cie->fde_encoding, &program); break; + /* Now all following cases affect this row, but do not touch LOC. + These cases end with 'continue'. We only get out of the + switch block for the row-copying (LOC-moving) cases above. */ + case DW_CFA_def_cfa: get_uleb128 (operand, program); get_uleb128 (offset, program); @@ -164,13 +170,13 @@ execute_cfi (Dwarf_CFI *cache, /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */ fs->cfa_data.offset.atom = DW_OP_bregx; fs->cfa_data.offset.offset = 0; - break; + continue; case DW_CFA_def_cfa_register: get_uleb128 (regno, program); cfi_assert (fs->cfa_rule == cfa_offset); fs->cfa_val_reg = regno; - break; + continue; case DW_CFA_def_cfa_sf: get_uleb128 (operand, program); @@ -183,7 +189,7 @@ execute_cfi (Dwarf_CFI *cache, def_cfa_offset: cfi_assert (fs->cfa_rule == cfa_offset); fs->cfa_val_offset = offset; - break; + continue; case DW_CFA_def_cfa_offset_sf: get_sleb128 (sf_offset, program); @@ -198,17 +204,17 @@ execute_cfi (Dwarf_CFI *cache, fs->cfa_data.expr.data = (unsigned char *) program; fs->cfa_data.expr.length = operand; program += operand; - break; + continue; case DW_CFA_undefined: get_uleb128 (regno, program); register_rule (regno, undefined, 0); - break; + continue; case DW_CFA_same_value: get_uleb128 (regno, program); register_rule (regno, same_value, 0); - break; + continue; case DW_CFA_offset_extended: get_uleb128 (operand, program); @@ -217,7 +223,7 @@ execute_cfi (Dwarf_CFI *cache, offset *= cie->data_alignment_factor; offset_extended: register_rule (operand, offset, offset); - break; + continue; case DW_CFA_offset_extended_sf: get_uleb128 (operand, program); @@ -231,7 +237,7 @@ execute_cfi (Dwarf_CFI *cache, offset *= cie->data_alignment_factor; val_offset: register_rule (operand, val_offset, offset); - break; + continue; case DW_CFA_val_offset_sf: get_uleb128 (operand, program); @@ -243,7 +249,7 @@ execute_cfi (Dwarf_CFI *cache, get_uleb128 (regno, program); get_uleb128 (operand, program); register_rule (regno, register, operand); - break; + continue; case DW_CFA_expression: get_uleb128 (regno, program); @@ -253,7 +259,7 @@ execute_cfi (Dwarf_CFI *cache, cfi_assert (operand <= (Dwarf_Word) (end - program)); register_rule (regno, expression, offset); program += operand; - break; + continue; case DW_CFA_val_expression: get_uleb128 (regno, program); @@ -263,7 +269,7 @@ execute_cfi (Dwarf_CFI *cache, cfi_assert (operand <= (Dwarf_Word) (end - program)); register_rule (regno, val_expression, offset); program += operand; - break; + continue; case DW_CFA_restore_extended: get_uleb128 (operand, program); @@ -273,7 +279,7 @@ execute_cfi (Dwarf_CFI *cache, { /* Special case hack to give backend abi_cfi a shorthand. */ cache->default_same_value = true; - break; + continue; } /* This can't be used in the CIE's own initial instructions. */ @@ -286,7 +292,7 @@ execute_cfi (Dwarf_CFI *cache, fs->regs[operand] = cie->initial_state->regs[operand]; else fs->regs[operand].rule = reg_unspecified; - break; + continue; case DW_CFA_remember_state: { @@ -298,7 +304,7 @@ execute_cfi (Dwarf_CFI *cache, goto out; } fs = copy; - break; + continue; } case DW_CFA_restore_state: @@ -309,10 +315,10 @@ execute_cfi (Dwarf_CFI *cache, free (fs); fs = prev; } - break; + continue; case DW_CFA_nop: - break; + continue; case DW_CFA_GNU_window_save: /* This is magic shorthand used only by SPARC. It's equivalent @@ -333,22 +339,29 @@ execute_cfi (Dwarf_CFI *cache, fs->regs[regno].rule = reg_offset; fs->regs[regno].value = (regno - 16) * address_size; } - break; + continue; case DW_CFA_GNU_args_size: /* XXX is this useful for anything? */ get_uleb128 (operand, program); - break; + continue; default: cfi_assert (false); - break; + continue; } - if (find_pc < loc) - /* We have just advanced past the address we're looking for. - The state currently described is what we want to see. */ - break; + /* We get here only for the cases that have just moved LOC. */ + if (find_pc >= loc) + /* This advance has not yet reached FIND_PC. */ + fs->start = loc; + else + { + /* We have just advanced past the address we're looking for. + The state currently described is what we want to see. */ + fs->end = loc; + break; + } } /* "The end of the instruction stream can be thought of as a @@ -357,7 +370,8 @@ execute_cfi (Dwarf_CFI *cache, When we fall off the end of the program without an advance_loc/set_loc that put us past FIND_PC, the final state left by the FDE program - applies to this address (the caller ensured it was inside the FDE). */ + applies to this address (the caller ensured it was inside the FDE). + This address (FDE->end) is already in FS->end as set by the caller. */ #undef register_rule #undef cfi_assert @@ -440,6 +454,8 @@ __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, return DWARF_E_NOMEM; fs->fde = fde; + fs->start = fde->start; + fs->end = fde->end; int result = execute_cfi (cache, fde->cie, &fs, fde->instructions, fde->instructions_end, false, diff --git a/libdw/unwind.h b/libdw/unwind.h index 486822a0a..687a94216 100644 --- a/libdw/unwind.h +++ b/libdw/unwind.h @@ -120,23 +120,24 @@ extern int dwarf_cfi_addrframe (Dwarf_CFI *cache, Dwarf_Addr address, Dwarf_Frame **frame) __nonnull_attribute__ (3); -/* Deliver a DWARF expression that yields the Canonical Frame Address at - this frame state. Returns -1 for errors, or the number of operations - stored at *OPS. That pointer can be used only as long as FRAME is alive - and unchanged. Returns zero if the CFA cannot be determined here. */ -extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops) - __nonnull_attribute__ (2); - /* Return the DWARF register number used in FRAME to denote - the return address in FRAME's caller frame. + the return address in FRAME's caller frame. The remaining + arguments can be non-null to fill in more information. + Fill [*START, *END) with the PC range to which FRAME's information applies. Fill in *SIGNALP to indicate whether this is a signal-handling frame. If true, this is the implicit call frame that calls a signal handler. This frame's "caller" is actually the interrupted state, not a call; its return address is an exact PC, not a PC after a call instruction. */ -extern int dwarf_frame_return_address_register (Dwarf_Frame *frame, - bool *signalp) - __nonnull_attribute__ (1, 2); +extern int dwarf_frame_info (Dwarf_Frame *frame, + Dwarf_Addr *start, Dwarf_Addr *end, bool *signalp); + +/* Deliver a DWARF expression that yields the Canonical Frame Address at + this frame state. Returns -1 for errors, or the number of operations + stored at *OPS. That pointer can be used only as long as FRAME is alive + and unchanged. Returns zero if the CFA cannot be determined here. */ +extern int dwarf_frame_cfa (Dwarf_Frame *frame, Dwarf_Op **ops) + __nonnull_attribute__ (2); /* Deliver a DWARF expression that yields the location or value of DWARF register number REGNO in the state described by FRAME. diff --git a/libdw/unwindP.h b/libdw/unwindP.h index b42964197..6b6fc03e3 100644 --- a/libdw/unwindP.h +++ b/libdw/unwindP.h @@ -176,6 +176,10 @@ struct dwarf_frame_register at a particular PC location described by an FDE. */ struct Dwarf_Frame_s { + /* This frame description covers PC values in [start, end). */ + Dwarf_Addr start; + Dwarf_Addr end; + Dwarf_CFI *cache; /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state, diff --git a/tests/addrcfi.c b/tests/addrcfi.c index 79e31e295..e2367f2b4 100644 --- a/tests/addrcfi.c +++ b/tests/addrcfi.c @@ -1,5 +1,5 @@ /* Test program for CFI handling. - Copyright (C) 2006 Red Hat, Inc. + Copyright (C) 2006, 2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -94,10 +94,13 @@ handle_address (GElf_Addr pc, Dwfl *dwfl) if (result != 0) error (EXIT_FAILURE, 0, "dwfl_addrframe: %s", dwfl_errmsg (-1)); - printf ("%#" PRIx64 ":\n", pc); - + Dwarf_Addr start = pc; + Dwarf_Addr end = pc; bool signalp; - int ra_regno = dwarf_frame_return_address_register (frame, &signalp); + int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp); + + printf ("%#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n", pc, start, end); + if (ra_regno < 0) printf ("\treturn address register unavailable (%s)\n", dwarf_errmsg (0));