summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2009-04-19 19:11:17 -0700
committerRoland McGrath <roland@redhat.com>2009-04-19 19:11:17 -0700
commitaef9e78a22a0b1083f8413ea7ba4d737997b4bea (patch)
tree77d233f4e229e713aa6c249baed5a70e1fff505b
parent927662ce9e6310cc99dcda72b9a09faa1f2ea8e6 (diff)
downloadelfutils-aef9e78a22a0b1083f8413ea7ba4d737997b4bea.tar.gz
unwind branch cleanup, closer to merge-ready.
-rw-r--r--backends/ChangeLog2
-rw-r--r--libdw/ChangeLog108
-rw-r--r--libdw/Makefile.am2
-rw-r--r--libdw/cfi.c2
-rw-r--r--libdw/cfi.h3
-rw-r--r--libdw/cie.c2
-rw-r--r--libdw/dwarf_getcfi_elf.c2
-rw-r--r--libdw/dwarf_next_cfi.c10
-rw-r--r--libdw/encoded-value.h3
-rw-r--r--libdw/libdw.h158
-rw-r--r--libdw/libdw.map7
-rw-r--r--libdw/unwind.h180
-rw-r--r--libdwfl/ChangeLog9
-rw-r--r--libdwfl/Makefile.am3
-rw-r--r--libdwfl/dwfl_addrframe.c38
-rw-r--r--libdwfl/dwfl_module_dwarf_cfi.c (renamed from libdwfl/dwfl_module_getcfi.c)60
-rw-r--r--libdwfl/dwfl_module_eh_cfi.c75
-rw-r--r--libdwfl/libdwfl.h22
-rw-r--r--libdwfl/libdwflP.h13
-rw-r--r--libebl/ChangeLog2
-rw-r--r--libebl/libebl.h3
-rw-r--r--tests/ChangeLog2
-rw-r--r--tests/addrcfi.c1
23 files changed, 401 insertions, 306 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog
index 62b5275e..30c0c4c1 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,4 +1,4 @@
-2007-01-18 Roland McGrath <roland@redhat.com>
+2009-04-19 Roland McGrath <roland@redhat.com>
* x86_64_cfi.c (x86_64_abi_cfi): New file.
* Makefile.am (x86_64_SRCS): Add it.
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 8e92fe7d..abc4ffb1 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,52 @@
+2009-04-19 Roland McGrath <roland@redhat.com>
+
+ * libdw.map (ELFUTILS_0.141): Add dwfl_addrframe,
+ dwfl_module_dwarf_cfi, dwfl_module_eh_cfi.
+
+ * libdwP.h (struct Dwarf): Add member `cfi'.
+ * dwarf_end.c (dwarf_end): Call __libdw_destroy_frame_cache on it.
+ * dwarf_getcfi.c: New file.
+ * dwarf_getcfi_elf.c: New file.
+ * dwarf_cfi_end.c: New file.
+ * dwarf_cfi_addrframe.c: New file.
+ * dwarf_frame_cfa.c: New file.
+ * dwarf_frame_register.c: New file.
+ * dwarf_frame_return_address_register.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add them.
+ * unwind.h: Declare those functions.
+ * libdw.map (ELFUTILS_0.141): Export them.
+
+ * dwarf_getlocation.c (__libdw_intern_expression): New function,
+ broken out of ...
+ (getlocation): ... here, call it.
+ * libdwP.h: Declare it.
+
+ * cie.c: New file.
+ * fde.c: New file.
+ * frame-cache.c: New file.
+ * cfi.c: New file.
+ * cfi.h: New file.
+ * encoded-value.h: New file.
+ * Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them.
+ * libdwP.h: Add DWARF_E_INVALID_CFI to errors enum.
+ * dwarf_error.c (errmsgs): Add element for it.
+
+ * dwarf_next_cfi.c: New file.
+ * Makefile.am (libdw_a_SOURCES): Add it.
+ * libdw.h (Dwarf_CIE, Dwarf_FDE, Dwarf_CIE_Entry): New types.
+ Declare dwarf_next_cfi.
+ * libdw.map (ELFUTILS_0.141): Add dwarf_next_cfi.
+
+ * memory-access.h [! ALLOW_UNALIGNED]
+ (read_2ubyte_unaligned): Renamed to ...
+ (read_2ubyte_unaligned_1): ... this. Take bool rather than Dwarf *.
+ (read_2ubyte_unaligned): Define as macro passing dbg->other_byte_order.
+ (read_2sbyte_unaligned): Likewise.
+ (read_4ubyte_unaligned): Likewise.
+ (read_4sbyte_unaligned): Likewise.
+ (read_8ubyte_unaligned): Likewise.
+ (read_8sbyte_unaligned): Likewise.
+
2009-04-03 Roland McGrath <roland@redhat.com>
* libdwP.h (IDX_eh_frame): Remove it.
@@ -243,65 +292,6 @@
2007-02-10 Roland McGrath <roland@redhat.com>
- * libdw.map (ELFUTILS_0.127): Add dwfl_addrframe, dwfl_module_getcfi.
-
- * dwarf.h: Define DW_EH_PE_* constants.
-
- * unwindP.h (struct Dwarf_CFI_s): Add `ebl' member.
- * dwarf_cfi_setebl.c: New file.
- * Makefile.am (libdw_a_SOURCES): Add it.
- * unwind.h: Declare dwarf_cfi_setebl.
- * unwindP.h: Add INTDECL.
-
- * libdwP.h (struct Dwarf): Add member `cfi'.
- * dwarf_end.c (dwarf_end): Call __libdw_destroy_frame_cache on it.
- * dwarf_getcfi.c: New file.
- * dwarf_getcfi_elf.c: New file.
- * dwarf_cfi_end.c: New file.
- * dwarf_cfi_addrframe.c: New file.
- * dwarf_frame_cfa.c: New file.
- * dwarf_frame_register.c: New file.
- * dwarf_frame_return_address_register.c: New file.
- * Makefile.am (libdw_a_SOURCES): Add them.
- * unwind.h: Declare those functions.
- * libdw.map (ELFUTILS_0.127): Export them.
-
- * dwarf_getlocation.c (__libdw_intern_expression): New function,
- broken out of ...
- (getlocation): ... here, call it.
- * libdwP.h: Declare it.
-
- * cie.c: New file.
- * fde.c: New file.
- * frame-cache.c: New file.
- * unwind.c: New file.
- * unwindP.h: New file.
- * encoded-value.h: New file.
- * Makefile.am (libdw_a_SOURCES, noinst_HEADERS): Add them.
- * libdwP.h: Add DWARF_E_INVALID_CFI to errors enum.
- * dwarf_error.c (errmsgs): Add element for it.
-
- * dwarf.h (DW_CFA_low_user, DW_CFA_high_user): Renamed to
- DW_CFA_lo_user, DW_CFA_hi_user, to match DWARF 3 spec.
-
- * unwind.h: New file.
- * dwarf_next_cfi.c: New file.
- * Makefile.am (euinclude_HEADERS, libdw_a_SOURCES): Add them.
- * libdw.map (ELFUTILS_0.127): New set inheriting from ELFUTILS_0.126.
- Add dwarf_next_cfi.
-
- * memory-access.h [! ALLOW_UNALIGNED]
- (read_2ubyte_unaligned): Renamed to ...
- (read_2ubyte_unaligned_1): ... this. Take bool rather than Dwarf *.
- (read_2ubyte_unaligned): Define as macro passing dbg->other_byte_order.
- (read_2sbyte_unaligned): Likewise.
- (read_4ubyte_unaligned): Likewise.
- (read_4sbyte_unaligned): Likewise.
- (read_8ubyte_unaligned): Likewise.
- (read_8sbyte_unaligned): Likewise.
-
-2007-02-10 Roland McGrath <roland@redhat.com>
-
* dwarf.h (DW_OP_fbreg): Comment fix.
2007-02-03 Roland McGrath <roland@redhat.com>
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 62eafb7e..4d041cf7 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -47,7 +47,7 @@ noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
endif
include_HEADERS = dwarf.h
-pkginclude_HEADERS = libdw.h unwind.h
+pkginclude_HEADERS = libdw.h
libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
diff --git a/libdw/cfi.c b/libdw/cfi.c
index 0be13d4a..d9065ecd 100644
--- a/libdw/cfi.c
+++ b/libdw/cfi.c
@@ -412,7 +412,7 @@ cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie)
First we'll let the backend fill in the default initial
state for this machine's ABI. */
- Dwarf_CIE abi_info = { CIE_ID, 1, 1, -1, "", NULL, 0, 0, NULL, NULL };
+ Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 };
/* Make sure we have a backend handle cached. */
if (unlikely (cache->ebl == NULL))
diff --git a/libdw/cfi.h b/libdw/cfi.h
index 8390fd82..2f8a1a18 100644
--- a/libdw/cfi.h
+++ b/libdw/cfi.h
@@ -52,9 +52,10 @@
#include "libdwP.h"
#include "libelfP.h"
-#include "unwind.h" /* XXX */
struct ebl;
+#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == DW_CIE_ID_64)
+
/* Cached CIE representation. */
struct dwarf_cie
{
diff --git a/libdw/cie.c b/libdw/cie.c
index e698a4b9..eed9aa89 100644
--- a/libdw/cie.c
+++ b/libdw/cie.c
@@ -167,7 +167,7 @@ __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
&cache->data->d, cache->eh_frame,
offset, &next_offset, &entry);
- if (result != 0 || entry.cie.CIE_id != CIE_ID)
+ if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
diff --git a/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c
index f68e6418..ae6c1baa 100644
--- a/libdw/dwarf_getcfi_elf.c
+++ b/libdw/dwarf_getcfi_elf.c
@@ -265,7 +265,7 @@ getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
return cfi;
}
-/* Search for the section named ".eh_frame". */
+/* Search for the sections named ".eh_frame" and ".eh_frame_hdr". */
static Dwarf_CFI *
getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
{
diff --git a/libdw/dwarf_next_cfi.c b/libdw/dwarf_next_cfi.c
index 698e31c8..ae911b81 100644
--- a/libdw/dwarf_next_cfi.c
+++ b/libdw/dwarf_next_cfi.c
@@ -89,7 +89,7 @@ dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry)
uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes);
size_t offset_size = 4;
- if (length == 0xffffffffu)
+ if (length == DWARF3_LENGTH_64_BIT)
{
/* This is the 64-bit DWARF format. */
offset_size = 8;
@@ -120,14 +120,14 @@ dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry)
{
entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
/* Canonicalize the 32-bit CIE_ID value to 64 bits. */
- if (!eh_frame_p && entry->cie.CIE_id == 0xffffffffu)
- entry->cie.CIE_id = CIE_ID;
+ if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32)
+ entry->cie.CIE_id = DW_CIE_ID_64;
}
if (eh_frame_p)
{
/* Canonicalize the .eh_frame CIE pointer to .debug_frame format. */
if (entry->cie.CIE_id == 0)
- entry->cie.CIE_id = CIE_ID;
+ entry->cie.CIE_id = DW_CIE_ID_64;
else
{
/* In .eh_frame format, a CIE pointer is the distance from where
@@ -140,7 +140,7 @@ dwarf_next_cfi (e_ident, data, eh_frame_p, off, next_off, entry)
}
}
- if (entry->cie.CIE_id == CIE_ID)
+ if (entry->cie.CIE_id == DW_CIE_ID_64)
{
/* Read the version stamp. Always an 8-bit value. */
uint8_t version = *bytes++;
diff --git a/libdw/encoded-value.h b/libdw/encoded-value.h
index b9985992..0bd09e49 100644
--- a/libdw/encoded-value.h
+++ b/libdw/encoded-value.h
@@ -52,7 +52,8 @@
#include <dwarf.h>
#include <stdlib.h>
-#include "unwind.h" /* XXX */
+#include "libdwP.h"
+
static size_t __attribute__ ((unused))
encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 3f3e5a09..81c2b73e 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -1,5 +1,5 @@
/* Interfaces for libdw.
- Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
+ Copyright (C) 2002-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
@@ -190,6 +190,70 @@ typedef struct
} Dwarf_Op;
+/* This describes one Common Information Entry read from a CFI section.
+ Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */
+typedef struct
+{
+ Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */
+
+ /* Instruction stream describing initial state used by FDEs. If
+ we did not understand the whole augmentation string and it did
+ not use 'z', then there might be more augmentation data here
+ (and in FDEs) before the actual instructions. */
+ const uint8_t *initial_instructions;
+ const uint8_t *initial_instructions_end;
+
+ Dwarf_Word code_alignment_factor;
+ Dwarf_Sword data_alignment_factor;
+ Dwarf_Word return_address_register;
+
+ const char *augmentation; /* Augmentation string. */
+
+ /* Augmentation data, might be NULL. The size is correct only if
+ we understood the augmentation string sufficiently. */
+ const uint8_t *augmentation_data;
+ size_t augmentation_data_size;
+ size_t fde_augmentation_data_size;
+} Dwarf_CIE;
+
+/* This describes one Frame Description Entry read from a CFI section.
+ Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */
+typedef struct
+{
+ /* Section offset of CIE this FDE refers to. This will never be
+ DW_CIE_ID_64 in an FDE. If this value is DW_CIE_ID_64, this is
+ actually a Dwarf_CIE structure. */
+ Dwarf_Off CIE_pointer;
+
+ /* We can't really decode anything further without looking up the CIE
+ and checking its augmentation string. Here follows the encoded
+ initial_location and address_range, then any augmentation data,
+ then the instruction stream. This FDE describes PC locations in
+ the byte range [initial_location, initial_location+address_range).
+ When the CIE augmentation string uses 'z', the augmentation data is
+ a DW_FORM_block (self-sized). Otherwise, when we understand the
+ augmentation string completely, fde_augmentation_data_size gives
+ the number of bytes of augmentation data before the instructions. */
+ const uint8_t *start;
+ const uint8_t *end;
+} Dwarf_FDE;
+
+/* Each entry in a CFI section is either a CIE described by Dwarf_CIE or
+ an FDE described by Dward_FDE. Check CIE_id to see which you have. */
+typedef union
+{
+ Dwarf_Off CIE_id; /* Always DW_CIE_ID_64 in Dwarf_CIE structures. */
+ Dwarf_CIE cie;
+ Dwarf_FDE fde;
+} Dwarf_CFI_Entry;
+
+/* Opaque type representing a frame state described by CFI. */
+typedef struct Dwarf_Frame_s Dwarf_Frame;
+
+/* Opaque type representing a CFI section found in a DWARF or ELF file. */
+typedef struct Dwarf_CFI_s Dwarf_CFI;
+
+
/* Handle for debug sessions. */
typedef struct Dwarf Dwarf;
@@ -229,6 +293,47 @@ extern int dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
__nonnull_attribute__ (3);
+/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
+ The E_IDENT from the originating ELF file indicates the address
+ size and byte order used in the CFI section contained in DATA;
+ EH_FRAME_P should be true for .eh_frame format and false for
+ .debug_frame format. OFFSET is the byte position in the section
+ to start at; on return *NEXT_OFFSET is filled in with the byte
+ position immediately after this entry.
+
+ On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to
+ see whether ENTRY->cie or ENTRY->fde is valid.
+
+ On errors, returns -1. Some format errors will permit safely
+ skipping to the next CFI entry though the current one is unusable.
+ In that case, *NEXT_OFF will be updated before a -1 return.
+
+ If there are no more CFI entries left in the section,
+ returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1. */
+extern int dwarf_next_cfi (const unsigned char e_ident[],
+ Elf_Data *data, bool eh_frame_p,
+ Dwarf_Off offset, Dwarf_Off *next_offset,
+ Dwarf_CFI_Entry *entry)
+ __nonnull_attribute__ (1, 2, 5, 6);
+
+/* Use the CFI in the DWARF .debug_frame section.
+ Returns NULL if there is no such section (not an error).
+ The pointer returned can be used until dwarf_end is called on DWARF,
+ and must not be passed to dwarf_cfi_end.
+ Calling this more than once returns the same pointer. */
+extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf);
+
+/* Use the CFI in the ELF file's exception-handling data.
+ Returns NULL if there is no such data.
+ The pointer returned can be used until elf_end is called on ELF,
+ and must be passed to dwarf_cfi_end before then.
+ Calling this more than once allocates independent data structures. */
+extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf);
+
+/* Release resources allocated by dwarf_getcfi_elf. */
+extern int dwarf_cfi_end (Dwarf_CFI *cache);
+
+
/* Return DIE at given offset. */
extern Dwarf_Die *dwarf_offdie (Dwarf *dbg, Dwarf_Off offset,
Dwarf_Die *result) __nonnull_attribute__ (3);
@@ -626,6 +731,57 @@ extern int dwarf_macro_param2 (Dwarf_Macro *macro, Dwarf_Word *paramp,
const char **strp);
+/* Compute what's known about a call frame when the PC is at ADDRESS.
+ Returns 0 for success or -1 for errors.
+ On success, *FRAME is a malloc'd pointer. */
+extern int dwarf_cfi_addrframe (Dwarf_CFI *cache,
+ Dwarf_Addr address, Dwarf_Frame **frame)
+ __nonnull_attribute__ (3);
+
+/* Return the DWARF register number used in FRAME to denote
+ 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_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.
+
+ Returns -1 for errors, 0 if REGNO has an accessible location,
+ or 1 if REGNO has only a computable value. Stores at *NOPS
+ the number of operations in the array stored at *OPS.
+ With return value 0, this is a DWARF location expression.
+ With return value 1, this is a DWARF expression that computes the value.
+
+ Return value 1 with *NOPS zero means CFI says the caller's REGNO is
+ "undefined" here, i.e. it's call-clobbered and cannot be recovered.
+
+ Return value 0 with *NOPS zero means CFI says the caller's REGNO is
+ "same_value" here, i.e. this frame did not change it; ask the caller
+ frame where to find it.
+
+ For common simple expressions *OPS is OPS_MEM. For arbitrary DWARF
+ expressions in the CFI, *OPS is an internal pointer that can be used as
+ long as the Dwarf_CFI used to create FRAME remains alive. */
+extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
+ Dwarf_Op ops_mem[2],
+ Dwarf_Op **ops, size_t *nops)
+ __nonnull_attribute__ (3, 4, 5);
+
+
/* Return error code of last failing function call. This value is kept
separately for each thread. */
extern int dwarf_errno (void);
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 598c9de7..8b37bfe2 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -195,9 +195,8 @@ ELFUTILS_0.138 {
*;
} ELFUTILS_0.136;
-ELFUTILS_0.140_UNWIND {
+ELFUTILS_0.141_UNWIND {
global:
- # XXX new unwind stuff not decided yet
dwarf_next_cfi;
dwarf_getcfi;
dwarf_getcfi_elf;
@@ -206,6 +205,8 @@ ELFUTILS_0.140_UNWIND {
dwarf_frame_cfa;
dwarf_frame_register;
dwarf_frame_info;
+
dwfl_addrframe;
- dwfl_module_getcfi;
+ dwfl_module_dwarf_cfi;
+ dwfl_module_eh_cfi;
} ELFUTILS_0.138;
diff --git a/libdw/unwind.h b/libdw/unwind.h
deleted file mode 100644
index d5169ba7..00000000
--- a/libdw/unwind.h
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifndef _libdw_unwind_h /* XXX */
-#define _libdw_unwind_h 1
-
-#include "libdw.h"
-
-/* This describes one Common Information Entry read from a CFI section.
- Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */
-typedef struct
-{
- Dwarf_Off CIE_id; /* Always CIE_ID in Dwarf_CIE structures. */
-#define CIE_ID ((Dwarf_Off) -1l)
-
- Dwarf_Word code_alignment_factor;
- Dwarf_Sword data_alignment_factor;
- Dwarf_Word return_address_register;
-
- const char *augmentation; /* Augmentation string. */
-
- /* Augmentation data, might be NULL. The size is correct only if
- we understood the augmentation string sufficiently. */
- const uint8_t *augmentation_data;
- size_t augmentation_data_size;
- size_t fde_augmentation_data_size;
-
- /* Instruction stream describing initial state used by FDEs. If
- we did not understand the whole augmentation string and it did
- not use 'z', then there might be more augmentation data here
- (and in FDEs) before the actual instructions. */
- const uint8_t *initial_instructions;
- const uint8_t *initial_instructions_end;
-} Dwarf_CIE;
-
-/* This describes one Frame Description Entry read from a CFI section.
- Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi. */
-typedef struct
-{
- /* Section offset of CIE this FDE refers to. This will never be
- CIE_ID in an FDE. If this value is CIE_ID, this is actually a
- Dwarf_CIE structure. */
- Dwarf_Off CIE_pointer;
-
- /* We can't really decode anything further without looking up the CIE
- and checking its augmentation string. Here follows the encoded
- initial_location and address_range, then any augmentation data,
- then the instruction stream. This FDE describes PC locations in
- the byte range [initial_location, initial_location+address_range).
- When the CIE augmentation string uses 'z', the augmentation data is
- a DW_FORM_block (self-sized). Otherwise, when we understand the
- augmentation string completely, fde_augmentation_data_size gives
- the number of bytes of augmentation data before the instructions. */
- const uint8_t *start;
- const uint8_t *end;
-} Dwarf_FDE;
-
-typedef union
-{
- Dwarf_CIE cie;
- Dwarf_FDE fde;
-} Dwarf_CFI_Entry;
-
-#define dwarf_cfi_cie_p(entry) ((entry)->cie.CIE_id == CIE_ID)
-
-/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
- The E_IDENT from the originating ELF file indicates the address
- size and byte order used in the CFI section contained in DATA;
- EH_FRAME_P should be true for .eh_frame format and false for
- .debug_frame format. OFFSET is the byte position in the section
- to start at; on return *NEXT_OFFSET is filled in with the byte
- position immediately after this entry.
-
- On success, returns 0 and fills in *ENTRY; use dwarf_cfi_cie_p to
- see whether ENTRY->cie or ENTRY->fde is valid.
-
- On errors, returns -1. Some format errors will permit safely
- skipping to the next CFI entry though the current one is unusable.
- In that case, *NEXT_OFF will be updated before a -1 return.
-
- If there are no more CFI entries left in the section,
- returns 1 and sets *NEXT_OFFSET to (Dwarf_Off) -1. */
-extern int dwarf_next_cfi (const unsigned char e_ident[],
- Elf_Data *data, bool eh_frame_p,
- Dwarf_Off offset, Dwarf_Off *next_offset,
- Dwarf_CFI_Entry *entry)
- __nonnull_attribute__ (1, 2, 5, 6);
-
-
-/* Opaque type representing a frame state described by CFI. */
-typedef struct Dwarf_Frame_s Dwarf_Frame;
-
-/* Opaque type representing a CFI section found in a DWARF or ELF file. */
-typedef struct Dwarf_CFI_s Dwarf_CFI;
-
-/* Use the CFI in the DWARF .debug_frame section.
- Returns NULL if there is no such section (not an error).
- The pointer returned can be used until dwarf_end is called on DWARF,
- and must not be passed to dwarf_cfi_end.
- Calling this more than once returns the same pointer. */
-extern Dwarf_CFI *dwarf_getcfi (Dwarf *dwarf);
-
-/* Use the CFI in the ELF file's exception-handling data.
- Returns NULL if there is no such data.
- The pointer returned can be used until elf_end is called on ELF,
- and must be passed to dwarf_cfi_end before then.
- Calling this more than once allocates independent data structures. */
-extern Dwarf_CFI *dwarf_getcfi_elf (Elf *elf);
-
-/* Release resources allocated by dwarf_getcfi_elf. */
-extern int dwarf_cfi_end (Dwarf_CFI *cache);
-
-
-/* Compute what's known about a call frame when the PC is at ADDRESS.
- Returns 0 for success or -1 for errors.
- On success, *FRAME is a malloc'd pointer. */
-extern int dwarf_cfi_addrframe (Dwarf_CFI *cache,
- Dwarf_Addr address, Dwarf_Frame **frame)
- __nonnull_attribute__ (3);
-
-/* Return the DWARF register number used in FRAME to denote
- 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_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.
-
- Returns -1 for errors, 0 if REGNO has an accessible location,
- or 1 if REGNO has only a computable value. Stores at *NOPS
- the number of operations in the array stored at *OPS.
- With return value 0, this is a DWARF location expression.
- With return value 1, this is a DWARF expression that computes the value.
-
- Return value 1 with *NOPS zero means CFI says the caller's REGNO is
- "undefined" here, i.e. it's call-clobbered and cannot be recovered.
-
- Return value 0 with *NOPS zero means CFI says the caller's REGNO is
- "same_value" here, i.e. this frame did not change it; ask the caller
- frame where to find it.
-
- For common simple expressions *OPS is OPS_MEM. For arbitrary DWARF
- expressions in the CFI, *OPS is an internal pointer that can be used as
- long as the Dwarf_CFI used to create FRAME remains alive. */
-extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
- Dwarf_Op ops_mem[2],
- Dwarf_Op **ops, size_t *nops)
- __nonnull_attribute__ (3, 4, 5);
-
-
-// XXX libdwfl front-end
-#include "../libdwfl/libdwfl.h"
-
-
-/* Find the CFI for this module. Returns NULL if there is no CFI.
- On success, fills in *BIAS with the difference between addresses
- within the loaded module and those in the CFI referring to it.
- The pointer returned can be used until the module is cleaned up.
- Calling this more than once returns the same pointer. */
-extern Dwarf_CFI *dwfl_module_getcfi (Dwfl_Module *mod, Dwarf_Addr *bias);
-
-// XXX needs module bias? for DW_OP_addr in exprs?
-/* Compute what's known about a call frame when the PC is at ADDRESS.
- Returns 0 for success or -1 for errors.
- On success, *FRAME is a malloc'd pointer. */
-extern int dwfl_addrframe (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Frame **frame)
- __nonnull_attribute__ (3);
-
-#endif /* XXX */
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 4092e913..9115b299 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,10 +1,11 @@
-2007-02-10 Roland McGrath <roland@redhat.com>
+2009-04-19 Roland McGrath <roland@redhat.com>
- * libdwflP.h (struct Dwfl_Module): New members `cfi', `cfi_elf'.
- Add INTDECL for dwfl_module_getcfi.
- * dwfl_module_getcfi.c: New file.
+ * dwfl_module_dwarf_cfi.c: New file.
+ * dwfl_module_eh_cfi.c: New file.
* dwfl_addrframe.c: New file.
* Makefile.am (libdwfl_a_SOURCES): Add them.
+ * libdwflP.h (struct Dwfl_Module): New members `dwarf_cfi', `eh_cfi.
+ Add INTDECL for dwfl_module_eh_cfi, dwfl_module_dwarf_cfi.
2009-04-19 Roland McGrath <roland@redhat.com>
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 9470c3dc..d271c575 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -68,7 +68,8 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
dwfl_module_getsrc_file.c \
libdwfl_crc32.c libdwfl_crc32_file.c \
elf-from-memory.c \
- dwfl_module_getcfi.c dwfl_addrframe.c \
+ dwfl_module_dwarf_cfi.c dwfl_module_eh_cfi.c \
+ dwfl_addrframe.c \
dwfl_module_getsym.c \
dwfl_module_addrname.c dwfl_module_addrsym.c \
dwfl_module_return_value_location.c \
diff --git a/libdwfl/dwfl_addrframe.c b/libdwfl/dwfl_addrframe.c
index 21548e77..cd0a9a5b 100644
--- a/libdwfl/dwfl_addrframe.c
+++ b/libdwfl/dwfl_addrframe.c
@@ -48,7 +48,28 @@
<http://www.openinventionnetwork.com>. */
#include "libdwflP.h"
-#include "../libdw/cfi.h" /* XXX */
+#include "../libdw/cfi.h"
+
+/* Return -1 for hard error, 0 for address match, 1 for no match. */
+static int
+try_cfi (Dwarf_CFI *cfi, Dwarf_Addr *bias, bool hard,
+ Dwarf_Addr address, Dwarf_Frame **frame)
+{
+ int result = INTUSE(dwarf_cfi_addrframe) (cfi, address - *bias, frame);
+ if (result != 0)
+ {
+ if (hard)
+ __libdwfl_seterrno (DWFL_E_LIBDW);
+ else
+ {
+ int err = INTUSE(dwarf_errno) ();
+ if (err == DWARF_E_NO_MATCH)
+ return 1;
+ __libdwfl_seterrno (DWFL_E (LIBDW, err));
+ }
+ }
+ return result;
+}
int
dwfl_addrframe (dwfl, address, frame)
@@ -56,14 +77,17 @@ dwfl_addrframe (dwfl, address, frame)
Dwarf_Addr address;
Dwarf_Frame **frame;
{
- Dwarf_Addr dwbias;
Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, address);
- Dwarf_CFI *cfi = INTUSE(dwfl_module_getcfi) (mod, &dwbias);
- if (cfi == NULL)
+ if (mod == NULL)
return -1;
- int result = INTUSE(dwarf_cfi_addrframe) (cfi, address - dwbias, frame);
- if (result != 0)
- __libdwfl_seterrno (DWFL_E_LIBDW);
+ /* Try to get a .debug_frame match first, then a .eh_frame match. */
+ Dwarf_Addr bias;
+ int result = try_cfi (INTUSE(dwfl_module_dwarf_cfi) (mod, &bias), &bias,
+ false, address, frame);
+ if (result > 0)
+ result = try_cfi (INTUSE(dwfl_module_eh_cfi) (mod, &bias), &bias,
+ true, address, frame);
+
return result;
}
diff --git a/libdwfl/dwfl_module_getcfi.c b/libdwfl/dwfl_module_dwarf_cfi.c
index 21f25905..eeca31a6 100644
--- a/libdwfl/dwfl_module_getcfi.c
+++ b/libdwfl/dwfl_module_dwarf_cfi.c
@@ -1,5 +1,5 @@
-/* Find CFI for a module in libdwfl.
- Copyright (C) 2006, 2007, 2009 Red Hat, Inc.
+/* Find DWARF CFI for a module in libdwfl.
+ 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
@@ -51,39 +51,39 @@
#include "../libdw/cfi.h"
Dwarf_CFI *
-dwfl_module_getcfi (mod, bias)
+internal_function
+__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, Dwarf_CFI *cfi)
+{
+ if (cfi != NULL && cfi->ebl == NULL)
+ {
+ Dwfl_Error error = __libdwfl_module_getebl (mod);
+ if (error == DWFL_E_NOERROR)
+ cfi->ebl = mod->ebl;
+ else
+ {
+ if (slot == &mod->eh_cfi)
+ INTUSE(dwarf_cfi_end) (cfi);
+ __libdwfl_seterrno (error);
+ return NULL;
+ }
+ }
+
+ return *slot = cfi;
+}
+
+Dwarf_CFI *
+dwfl_module_dwarf_cfi (mod, bias)
Dwfl_Module *mod;
Dwarf_Addr *bias;
{
if (mod == NULL)
return NULL;
- if (mod->cfi == NULL)
- {
- mod->cfi = INTUSE(dwarf_getcfi) (INTUSE(dwfl_module_getdwarf) (mod,
- bias));
- if (mod->cfi == NULL && mod->main.elf != NULL)
- {
- mod->cfi_elf = true;
- *bias = mod->main.bias;
- mod->cfi = INTUSE(dwarf_getcfi_elf) (mod->main.elf);
- }
-
- if (mod->cfi != NULL && mod->cfi->ebl == NULL)
- {
- Dwfl_Error error = __libdwfl_module_getebl (mod);
- if (error == DWFL_E_NOERROR)
- mod->cfi->ebl = mod->ebl;
- else
- {
- if (mod->cfi_elf)
- INTUSE(dwarf_cfi_end) (mod->cfi);
- mod->cfi = NULL;
- __libdwfl_seterrno (error);
- }
- }
- }
+ if (mod->dwarf_cfi != NULL)
+ return mod->dwarf_cfi;
- return mod->cfi;
+ return __libdwfl_set_cfi (mod, &mod->dwarf_cfi,
+ INTUSE(dwarf_getcfi)
+ (INTUSE(dwfl_module_getdwarf) (mod, bias)));
}
-INTDEF (dwfl_module_getcfi)
+INTDEF (dwfl_module_dwarf_cfi)
diff --git a/libdwfl/dwfl_module_eh_cfi.c b/libdwfl/dwfl_module_eh_cfi.c
new file mode 100644
index 00000000..a3cf6243
--- /dev/null
+++ b/libdwfl/dwfl_module_eh_cfi.c
@@ -0,0 +1,75 @@
+/* Find EH CFI for a module in libdwfl.
+ Copyright (C) 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
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ In addition, as a special exception, Red Hat, Inc. gives You the
+ additional right to link the code of Red Hat elfutils with code licensed
+ under any Open Source Initiative certified open source license
+ (http://www.opensource.org/licenses/index.php) which requires the
+ distribution of source code with any binary distribution and to
+ distribute linked combinations of the two. Non-GPL Code permitted under
+ this exception must only link to the code of Red Hat elfutils through
+ those well defined interfaces identified in the file named EXCEPTION
+ found in the source code files (the "Approved Interfaces"). The files
+ of Non-GPL Code may instantiate templates or use macros or inline
+ functions from the Approved Interfaces without causing the resulting
+ work to be covered by the GNU General Public License. Only Red Hat,
+ Inc. may make changes or additions to the list of Approved Interfaces.
+ Red Hat's grant of this exception is conditioned upon your not adding
+ any new exceptions. If you wish to add a new Approved Interface or
+ exception, please contact Red Hat. You must obey the GNU General Public
+ License in all respects for all of the Red Hat elfutils code and other
+ code used in conjunction with Red Hat elfutils except the Non-GPL Code
+ covered by this exception. If you modify this file, you may extend this
+ exception to your version of the file, but you are not obligated to do
+ so. If you do not wish to provide this exception without modification,
+ you must delete this exception statement from your version and license
+ this file solely under the GPL without exception.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#include "libdwflP.h"
+#include "../libdw/cfi.h"
+
+Dwarf_CFI *
+dwfl_module_eh_cfi (mod, bias)
+ Dwfl_Module *mod;
+ Dwarf_Addr *bias;
+{
+ if (mod == NULL)
+ return NULL;
+
+ if (mod->eh_cfi != NULL)
+ return mod->eh_cfi;
+
+ __libdwfl_getelf (mod);
+ if (mod->elferr != DWFL_E_NOERROR)
+ {
+ __libdwfl_seterrno (mod->elferr);
+ return NULL;
+ }
+
+ *bias = mod->main.bias;
+ return __libdwfl_set_cfi (mod, &mod->eh_cfi,
+ INTUSE(dwarf_getcfi_elf) (mod->main.elf));
+}
+INTDEF (dwfl_module_eh_cfi)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 91d43802..4af6a65d 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -552,6 +552,28 @@ extern int dwfl_module_register_names (Dwfl_Module *mod,
void *arg);
+/* Find the CFI for this module. Returns NULL if there is no CFI.
+ On success, fills in *BIAS with the difference between addresses
+ within the loaded module and those in the CFI referring to it.
+ The pointer returned can be used until the module is cleaned up.
+ Calling these more than once returns the same pointers.
+
+ dwfl_module_dwarf_cfi gets the '.debug_frame' information found with the
+ rest of the DWARF information. dwfl_module_eh_cfi gets the '.eh_frame'
+ information found linked into the text. A module might have either or
+ both. */
+extern Dwarf_CFI *dwfl_module_dwarf_cfi (Dwfl_Module *mod, Dwarf_Addr *bias);
+extern Dwarf_CFI *dwfl_module_eh_cfi (Dwfl_Module *mod, Dwarf_Addr *bias);
+
+// XXX needs module bias? for DW_OP_addr in exprs?
+/* Compute what's known about a call frame when the PC is at ADDRESS.
+ This integrates both DWARF proper and EH information as available.
+ Returns 0 for success or -1 for errors.
+ On success, *FRAME is a malloc'd pointer. */
+extern int dwfl_addrframe (Dwfl *dwfl, Dwarf_Addr address, Dwarf_Frame **frame)
+ __nonnull_attribute__ (3);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index c91ff8f0..b5bcd9bd 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -62,7 +62,6 @@
#include <string.h>
#include "../libdw/libdwP.h" /* We need its INTDECLs. */
-#include "../libdw/unwind.h" /* XXX */
/* gettext helper macros. */
#define _(Str) dgettext ("elfutils", Str)
@@ -183,8 +182,8 @@ struct Dwfl_Module
struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */
unsigned int naranges;
- Dwarf_CFI *cfi; /* Cached CFI for this module. */
- bool cfi_elf; /* cfi is from dwarf_getcfi_elf. */
+ Dwarf_CFI *dwarf_cfi; /* Cached DWARF CFI for this module. */
+ Dwarf_CFI *eh_cfi; /* Cached EH CFI for this module. */
int segment; /* Index of first segment table entry. */
bool gc; /* Mark/sweep flag. */
@@ -278,6 +277,11 @@ extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf,
/* Ensure that MOD->ebl is set up. */
extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function;
+/* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi). */
+extern Dwarf_CFI *__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot,
+ Dwarf_CFI *cfi)
+ internal_function;
+
/* Iterate through all the CU's in the module. Start by passing a null
LASTCU, and then pass the last *CU returned. Success return with null
*CU no more CUs. */
@@ -429,7 +433,8 @@ INTDECL (dwfl_linux_kernel_report_modules)
INTDECL (dwfl_linux_kernel_report_offline)
INTDECL (dwfl_offline_section_address)
INTDECL (dwfl_module_relocate_address)
-INTDECL (dwfl_module_getcfi)
+INTDECL (dwfl_module_dwarf_cfi)
+INTDECL (dwfl_module_eh_cfi)
/* Leading arguments standard to callbacks passed a Dwfl_Module. */
#define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index 2d501a36..52b46cd3 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,4 +1,4 @@
-2007-01-18 Roland McGrath <roland@redhat.com>
+2009-04-19 Roland McGrath <roland@redhat.com>
* ebl-hooks.h: Add abi_cfi hook.
* eblopenbackend.c (default_abi_cfi): New function.
diff --git a/libebl/libebl.h b/libebl/libebl.h
index 11de24aa..1a56b966 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -1,5 +1,5 @@
/* Interface for libebl.
- Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
+ Copyright (C) 2000, 2001-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
@@ -52,7 +52,6 @@
#include <gelf.h>
#include "libdw.h"
-#include "unwind.h" /* XXX */
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
diff --git a/tests/ChangeLog b/tests/ChangeLog
index bc22309c..151dcabf 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,4 +1,4 @@
-2007-02-10 Roland McGrath <roland@redhat.com>
+2009-04-19 Roland McGrath <roland@redhat.com>
* addrcfi.c: New file.
* Makefile.am (noinst_PROGRAMS): Add it.
diff --git a/tests/addrcfi.c b/tests/addrcfi.c
index e2367f2b..101c5c0b 100644
--- a/tests/addrcfi.c
+++ b/tests/addrcfi.c
@@ -36,7 +36,6 @@
#include <error.h>
#include <string.h>
-#include "../libdw/unwind.h" /* XXX */
static void
print_detail (int result, const Dwarf_Op *ops, size_t nops)