Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame] | 1 | /* Internal definitions for libdw CFI interpreter. |
| 2 | Copyright (C) 2009-2010, 2013, 2015 Red Hat, Inc. |
| 3 | This file is part of elfutils. |
| 4 | |
| 5 | This file is free software; you can redistribute it and/or modify |
| 6 | it under the terms of either |
| 7 | |
| 8 | * the GNU Lesser General Public License as published by the Free |
| 9 | Software Foundation; either version 3 of the License, or (at |
| 10 | your option) any later version |
| 11 | |
| 12 | or |
| 13 | |
| 14 | * the GNU General Public License as published by the Free |
| 15 | Software Foundation; either version 2 of the License, or (at |
| 16 | your option) any later version |
| 17 | |
| 18 | or both in parallel, as here. |
| 19 | |
| 20 | elfutils is distributed in the hope that it will be useful, but |
| 21 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 23 | General Public License for more details. |
| 24 | |
| 25 | You should have received copies of the GNU General Public License and |
| 26 | the GNU Lesser General Public License along with this program. If |
| 27 | not, see <http://www.gnu.org/licenses/>. */ |
| 28 | |
| 29 | #ifndef _UNWINDP_H |
| 30 | #define _UNWINDP_H 1 |
| 31 | |
| 32 | #include "libdwP.h" |
| 33 | #include "libelfP.h" |
| 34 | struct ebl; |
| 35 | |
| 36 | /* Cached CIE representation. */ |
| 37 | struct dwarf_cie |
| 38 | { |
| 39 | Dwarf_Off offset; /* Our position, as seen in FDEs' CIE_pointer. */ |
| 40 | |
| 41 | Dwarf_Word code_alignment_factor; |
| 42 | Dwarf_Sword data_alignment_factor; |
| 43 | Dwarf_Word return_address_register; |
| 44 | |
| 45 | size_t fde_augmentation_data_size; |
| 46 | |
| 47 | // play out to initial state |
| 48 | const uint8_t *initial_instructions; |
| 49 | const uint8_t *initial_instructions_end; |
| 50 | |
| 51 | const Dwarf_Frame *initial_state; |
| 52 | |
| 53 | uint8_t fde_encoding; /* DW_EH_PE_* for addresses in FDEs. */ |
| 54 | uint8_t lsda_encoding; /* DW_EH_PE_* for LSDA in FDE augmentation. */ |
| 55 | |
| 56 | bool sized_augmentation_data; /* Saw 'z': FDEs have self-sized data. */ |
| 57 | bool signal_frame; /* Saw 'S': FDE is for a signal frame. */ |
| 58 | }; |
| 59 | |
| 60 | /* Cached FDE representation. */ |
| 61 | struct dwarf_fde |
| 62 | { |
| 63 | struct dwarf_cie *cie; |
| 64 | |
| 65 | /* This FDE describes PC values in [start, end). */ |
| 66 | Dwarf_Addr start; |
| 67 | Dwarf_Addr end; |
| 68 | |
| 69 | const uint8_t *instructions; |
| 70 | const uint8_t *instructions_end; |
| 71 | }; |
| 72 | |
| 73 | /* This holds everything we cache about the CFI from each ELF file's |
| 74 | .debug_frame or .eh_frame section. */ |
| 75 | struct Dwarf_CFI_s |
| 76 | { |
| 77 | /* Dwarf handle we came from. If null, this is .eh_frame data. */ |
| 78 | Dwarf *dbg; |
| 79 | #define CFI_IS_EH(cfi) ((cfi)->dbg == NULL) |
| 80 | |
| 81 | /* Data of the .debug_frame or .eh_frame section. */ |
| 82 | Elf_Data_Scn *data; |
| 83 | const unsigned char *e_ident; /* For EI_DATA and EI_CLASS. */ |
| 84 | |
| 85 | Dwarf_Addr frame_vaddr; /* DW_EH_PE_pcrel, address of frame section. */ |
| 86 | Dwarf_Addr textrel; /* DW_EH_PE_textrel base address. */ |
| 87 | Dwarf_Addr datarel; /* DW_EH_PE_datarel base address. */ |
| 88 | |
| 89 | /* Location of next unread entry in the section. */ |
| 90 | Dwarf_Off next_offset; |
| 91 | |
| 92 | /* Search tree for the CIEs, indexed by CIE_pointer (section offset). */ |
| 93 | void *cie_tree; |
| 94 | |
| 95 | /* Search tree for the FDEs, indexed by PC address. */ |
| 96 | void *fde_tree; |
| 97 | |
| 98 | /* Search tree for parsed DWARF expressions, indexed by raw pointer. */ |
| 99 | void *expr_tree; |
| 100 | |
| 101 | /* Backend hook. */ |
| 102 | struct ebl *ebl; |
| 103 | |
| 104 | /* Binary search table in .eh_frame_hdr section. */ |
| 105 | const uint8_t *search_table; |
| 106 | size_t search_table_len; |
| 107 | Dwarf_Addr search_table_vaddr; |
| 108 | size_t search_table_entries; |
| 109 | uint8_t search_table_encoding; |
| 110 | |
| 111 | /* True if the file has a byte order different from the host. */ |
| 112 | bool other_byte_order; |
| 113 | |
| 114 | /* Default rule for registers not previously mentioned |
| 115 | is same_value, not undefined. */ |
| 116 | bool default_same_value; |
| 117 | }; |
| 118 | |
| 119 | |
| 120 | enum dwarf_frame_rule |
| 121 | { |
| 122 | reg_unspecified, /* Uninitialized state. */ |
| 123 | reg_undefined, /* DW_CFA_undefined */ |
| 124 | reg_same_value, /* DW_CFA_same_value */ |
| 125 | reg_offset, /* DW_CFA_offset_extended et al */ |
| 126 | reg_val_offset, /* DW_CFA_val_offset et al */ |
| 127 | reg_register, /* DW_CFA_register */ |
| 128 | reg_expression, /* DW_CFA_expression */ |
| 129 | reg_val_expression, /* DW_CFA_val_expression */ |
| 130 | }; |
| 131 | |
| 132 | /* This describes what we know about an individual register. */ |
| 133 | struct dwarf_frame_register |
| 134 | { |
| 135 | enum dwarf_frame_rule rule:3; |
| 136 | |
| 137 | /* The meaning of the value bits depends on the rule: |
| 138 | |
| 139 | Rule Value |
| 140 | ---- ----- |
| 141 | undefined unused |
| 142 | same_value unused |
| 143 | offset(N) N (register saved at CFA + value) |
| 144 | val_offset(N) N (register = CFA + value) |
| 145 | register(R) R (register = register #value) |
| 146 | expression(E) section offset of DW_FORM_block containing E |
| 147 | (register saved at address E computes) |
| 148 | val_expression(E) section offset of DW_FORM_block containing E |
| 149 | (register = value E computes) |
| 150 | */ |
| 151 | Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3); |
| 152 | }; |
| 153 | |
| 154 | /* This holds instructions for unwinding frame at a particular PC location |
| 155 | described by an FDE. */ |
| 156 | struct Dwarf_Frame_s |
| 157 | { |
| 158 | /* This frame description covers PC values in [start, end). */ |
| 159 | Dwarf_Addr start; |
| 160 | Dwarf_Addr end; |
| 161 | |
| 162 | Dwarf_CFI *cache; |
| 163 | |
| 164 | /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state, |
| 165 | or NULL in an initial_state pseudo-frame. */ |
| 166 | Dwarf_Frame *prev; |
| 167 | |
| 168 | /* The FDE that generated this frame state. This points to its CIE, |
| 169 | which has the return_address_register and signal_frame flag. */ |
| 170 | struct dwarf_fde *fde; |
| 171 | |
| 172 | /* The CFA is unknown, is R+N, or is computed by a DWARF expression. |
| 173 | A bogon in the CFI can indicate an invalid/incalculable rule. |
| 174 | We store that as cfa_invalid rather than barfing when processing it, |
| 175 | so callers can ignore the bogon unless they really need that CFA. */ |
| 176 | enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule; |
| 177 | union |
| 178 | { |
| 179 | Dwarf_Op offset; |
| 180 | Dwarf_Block expr; |
| 181 | } cfa_data; |
| 182 | /* We store an offset rule as a DW_OP_bregx operation. */ |
| 183 | #define cfa_val_reg cfa_data.offset.number |
| 184 | #define cfa_val_offset cfa_data.offset.number2 |
| 185 | |
| 186 | size_t nregs; |
| 187 | struct dwarf_frame_register regs[]; |
| 188 | }; |
| 189 | |
| 190 | |
| 191 | /* Clean up the data structure and all it points to. */ |
| 192 | extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache) |
| 193 | __nonnull_attribute__ (1) internal_function; |
| 194 | |
| 195 | /* Enter a CIE encountered while reading through for FDEs. */ |
| 196 | extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, |
| 197 | const Dwarf_CIE *info) |
| 198 | __nonnull_attribute__ (1, 3) internal_function; |
| 199 | |
| 200 | /* Look up a CIE_pointer for random access. */ |
| 201 | extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) |
| 202 | __nonnull_attribute__ (1) internal_function; |
| 203 | |
| 204 | |
| 205 | /* Look for an FDE covering the given PC address. */ |
| 206 | extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache, |
| 207 | Dwarf_Addr address) |
| 208 | __nonnull_attribute__ (1) internal_function; |
| 209 | |
| 210 | /* Look for an FDE by its offset in the section. */ |
| 211 | extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache, |
| 212 | Dwarf_Off offset) |
| 213 | __nonnull_attribute__ (1) internal_function; |
| 214 | |
| 215 | /* Process the FDE that contains the given PC address, |
| 216 | to yield the frame state when stopped there. |
| 217 | The return value is a DWARF_E_* error code. */ |
| 218 | extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, |
| 219 | Dwarf_Addr address, Dwarf_Frame **frame) |
| 220 | __nonnull_attribute__ (1, 2, 4) internal_function; |
| 221 | |
| 222 | |
| 223 | /* Dummy struct for memory-access.h macros. */ |
| 224 | #define BYTE_ORDER_DUMMY(var, e_ident) \ |
| 225 | const struct { bool other_byte_order; } var = \ |
| 226 | { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB) \ |
| 227 | || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) } |
| 228 | |
| 229 | |
| 230 | INTDECL (dwarf_next_cfi) |
| 231 | INTDECL (dwarf_getcfi) |
| 232 | INTDECL (dwarf_getcfi_elf) |
| 233 | INTDECL (dwarf_cfi_end) |
| 234 | INTDECL (dwarf_cfi_addrframe) |
| 235 | |
| 236 | #endif /* unwindP.h */ |