diff options
author | Roland McGrath <roland@redhat.com> | 2009-04-19 19:11:17 -0700 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2009-04-19 19:11:17 -0700 |
commit | aef9e78a22a0b1083f8413ea7ba4d737997b4bea (patch) | |
tree | 77d233f4e229e713aa6c249baed5a70e1fff505b | |
parent | 927662ce9e6310cc99dcda72b9a09faa1f2ea8e6 (diff) | |
download | elfutils-aef9e78a22a0b1083f8413ea7ba4d737997b4bea.tar.gz |
unwind branch cleanup, closer to merge-ready.
-rw-r--r-- | backends/ChangeLog | 2 | ||||
-rw-r--r-- | libdw/ChangeLog | 108 | ||||
-rw-r--r-- | libdw/Makefile.am | 2 | ||||
-rw-r--r-- | libdw/cfi.c | 2 | ||||
-rw-r--r-- | libdw/cfi.h | 3 | ||||
-rw-r--r-- | libdw/cie.c | 2 | ||||
-rw-r--r-- | libdw/dwarf_getcfi_elf.c | 2 | ||||
-rw-r--r-- | libdw/dwarf_next_cfi.c | 10 | ||||
-rw-r--r-- | libdw/encoded-value.h | 3 | ||||
-rw-r--r-- | libdw/libdw.h | 158 | ||||
-rw-r--r-- | libdw/libdw.map | 7 | ||||
-rw-r--r-- | libdw/unwind.h | 180 | ||||
-rw-r--r-- | libdwfl/ChangeLog | 9 | ||||
-rw-r--r-- | libdwfl/Makefile.am | 3 | ||||
-rw-r--r-- | libdwfl/dwfl_addrframe.c | 38 | ||||
-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.c | 75 | ||||
-rw-r--r-- | libdwfl/libdwfl.h | 22 | ||||
-rw-r--r-- | libdwfl/libdwflP.h | 13 | ||||
-rw-r--r-- | libebl/ChangeLog | 2 | ||||
-rw-r--r-- | libebl/libebl.h | 3 | ||||
-rw-r--r-- | tests/ChangeLog | 2 | ||||
-rw-r--r-- | tests/addrcfi.c | 1 |
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) |