summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdw/Makefile.am3
-rw-r--r--libdw/dwarf_frame_info.c (renamed from libdw/dwarf_frame_return_address_register.c)15
-rw-r--r--libdw/libdw.map4
-rw-r--r--libdw/unwind.c64
-rw-r--r--libdw/unwind.h23
-rw-r--r--libdw/unwindP.h4
-rw-r--r--tests/addrcfi.c11
7 files changed, 79 insertions, 45 deletions
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 61852284..852e57c3 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
index ef2d7e11..8813c0ad 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 1195109a..93ca3c97 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 82380cb1..48729246 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 486822a0..687a9421 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 b4296419..6b6fc03e 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 79e31e29..e2367f2b 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));