| /* Internal definitions for libdw CFI interpreter. |
| Copyright (C) 2009-2010, 2013 Red Hat, Inc. |
| This file is part of elfutils. |
| |
| This file is free software; you can redistribute it and/or modify |
| it under the terms of either |
| |
| * the GNU Lesser General Public License as published by the Free |
| Software Foundation; either version 3 of the License, or (at |
| your option) any later version |
| |
| or |
| |
| * the GNU General Public License as published by the Free |
| Software Foundation; either version 2 of the License, or (at |
| your option) any later version |
| |
| or both in parallel, as here. |
| |
| 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 copies of the GNU General Public License and |
| the GNU Lesser General Public License along with this program. If |
| not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef _UNWINDP_H |
| #define _UNWINDP_H 1 |
| |
| #include "libdwP.h" |
| #include "libelfP.h" |
| struct ebl; |
| |
| /* Cached CIE representation. */ |
| struct dwarf_cie |
| { |
| Dwarf_Off offset; /* Our position, as seen in FDEs' CIE_pointer. */ |
| |
| Dwarf_Word code_alignment_factor; |
| Dwarf_Sword data_alignment_factor; |
| Dwarf_Word return_address_register; |
| |
| size_t fde_augmentation_data_size; |
| |
| // play out to initial state |
| const uint8_t *initial_instructions; |
| const uint8_t *initial_instructions_end; |
| |
| const Dwarf_Frame *initial_state; |
| |
| uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ |
| uint8_t lsda_encoding; /* DW_EH_PE_* for LSDA in FDE augmentation. */ |
| |
| bool sized_augmentation_data; /* Saw 'z': FDEs have self-sized data. */ |
| bool signal_frame; /* Saw 'S': FDE is for a signal frame. */ |
| }; |
| |
| /* Cached FDE representation. */ |
| struct dwarf_fde |
| { |
| struct dwarf_cie *cie; |
| |
| /* This FDE describes PC values in [start, end). */ |
| Dwarf_Addr start; |
| Dwarf_Addr end; |
| |
| const uint8_t *instructions; |
| const uint8_t *instructions_end; |
| }; |
| |
| /* This holds everything we cache about the CFI from each ELF file's |
| .debug_frame or .eh_frame section. */ |
| struct Dwarf_CFI_s |
| { |
| /* Dwarf handle we came from. If null, this is .eh_frame data. */ |
| Dwarf *dbg; |
| #define CFI_IS_EH(cfi) ((cfi)->dbg == NULL) |
| |
| /* Data of the .debug_frame or .eh_frame section. */ |
| Elf_Data_Scn *data; |
| const unsigned char *e_ident; /* For EI_DATA and EI_CLASS. */ |
| |
| Dwarf_Addr frame_vaddr; /* DW_EH_PE_pcrel, address of frame section. */ |
| Dwarf_Addr textrel; /* DW_EH_PE_textrel base address. */ |
| Dwarf_Addr datarel; /* DW_EH_PE_datarel base address. */ |
| |
| /* Location of next unread entry in the section. */ |
| Dwarf_Off next_offset; |
| |
| /* Search tree for the CIEs, indexed by CIE_pointer (section offset). */ |
| void *cie_tree; |
| |
| /* Search tree for the FDEs, indexed by PC address. */ |
| void *fde_tree; |
| |
| /* Search tree for parsed DWARF expressions, indexed by raw pointer. */ |
| void *expr_tree; |
| |
| /* Backend hook. */ |
| struct ebl *ebl; |
| |
| /* Binary search table in .eh_frame_hdr section. */ |
| const uint8_t *search_table; |
| Dwarf_Addr search_table_vaddr; |
| size_t search_table_entries; |
| uint8_t search_table_encoding; |
| |
| /* True if the file has a byte order different from the host. */ |
| bool other_byte_order; |
| |
| /* Default rule for registers not previously mentioned |
| is same_value, not undefined. */ |
| bool default_same_value; |
| }; |
| |
| |
| enum dwarf_frame_rule |
| { |
| reg_unspecified, /* Uninitialized state. */ |
| reg_undefined, /* DW_CFA_undefined */ |
| reg_same_value, /* DW_CFA_same_value */ |
| reg_offset, /* DW_CFA_offset_extended et al */ |
| reg_val_offset, /* DW_CFA_val_offset et al */ |
| reg_register, /* DW_CFA_register */ |
| reg_expression, /* DW_CFA_expression */ |
| reg_val_expression, /* DW_CFA_val_expression */ |
| }; |
| |
| /* This describes what we know about an individual register. */ |
| struct dwarf_frame_register |
| { |
| enum dwarf_frame_rule rule:3; |
| |
| /* The meaning of the value bits depends on the rule: |
| |
| Rule Value |
| ---- ----- |
| undefined unused |
| same_value unused |
| offset(N) N (register saved at CFA + value) |
| val_offset(N) N (register = CFA + value) |
| register(R) R (register = register #value) |
| expression(E) section offset of DW_FORM_block containing E |
| (register saved at address E computes) |
| val_expression(E) section offset of DW_FORM_block containing E |
| (register = value E computes) |
| */ |
| Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3); |
| }; |
| |
| /* This holds instructions for unwinding frame 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, |
| or NULL in an initial_state pseudo-frame. */ |
| Dwarf_Frame *prev; |
| |
| /* The FDE that generated this frame state. This points to its CIE, |
| which has the return_address_register and signal_frame flag. */ |
| struct dwarf_fde *fde; |
| |
| /* The CFA is unknown, is R+N, or is computed by a DWARF expression. |
| A bogon in the CFI can indicate an invalid/incalculable rule. |
| We store that as cfa_invalid rather than barfing when processing it, |
| so callers can ignore the bogon unless they really need that CFA. */ |
| enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule; |
| union |
| { |
| Dwarf_Op offset; |
| Dwarf_Block expr; |
| } cfa_data; |
| /* We store an offset rule as a DW_OP_bregx operation. */ |
| #define cfa_val_reg cfa_data.offset.number |
| #define cfa_val_offset cfa_data.offset.number2 |
| |
| size_t nregs; |
| struct dwarf_frame_register regs[]; |
| }; |
| |
| |
| /* Clean up the data structure and all it points to. */ |
| extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache) |
| __nonnull_attribute__ (1) internal_function; |
| |
| /* Enter a CIE encountered while reading through for FDEs. */ |
| extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, |
| const Dwarf_CIE *info) |
| __nonnull_attribute__ (1, 3) internal_function; |
| |
| /* Look up a CIE_pointer for random access. */ |
| extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) |
| __nonnull_attribute__ (1) internal_function; |
| |
| |
| /* Look for an FDE covering the given PC address. */ |
| extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache, |
| Dwarf_Addr address) |
| __nonnull_attribute__ (1) internal_function; |
| |
| /* Look for an FDE by its offset in the section. */ |
| extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache, |
| Dwarf_Off offset) |
| __nonnull_attribute__ (1) internal_function; |
| |
| /* Process the FDE that contains the given PC address, |
| to yield the frame state when stopped there. |
| The return value is a DWARF_E_* error code. */ |
| extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, |
| Dwarf_Addr address, Dwarf_Frame **frame) |
| __nonnull_attribute__ (1, 2, 4) internal_function; |
| |
| |
| /* Dummy struct for memory-access.h macros. */ |
| #define BYTE_ORDER_DUMMY(var, e_ident) \ |
| const struct { bool other_byte_order; } var = \ |
| { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB) \ |
| || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) } |
| |
| |
| INTDECL (dwarf_next_cfi) |
| INTDECL (dwarf_getcfi) |
| INTDECL (dwarf_getcfi_elf) |
| INTDECL (dwarf_cfi_end) |
| INTDECL (dwarf_cfi_addrframe) |
| |
| #endif /* unwindP.h */ |