1 /* CIE reading. 2 Copyright (C) 2009-2010 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 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif 32 33 #include "cfi.h" 34 #include "encoded-value.h" 35 #include <assert.h> 36 #include <search.h> 37 #include <stdlib.h> 38 39 40 static int 41 compare_cie (const void *a, const void *b) 42 { 43 const struct dwarf_cie *cie1 = a; 44 const struct dwarf_cie *cie2 = b; 45 if (cie1->offset < cie2->offset) 46 return -1; 47 if (cie1->offset > cie2->offset) 48 return 1; 49 return 0; 50 } 51 52 /* There is no CIE at OFFSET in the tree. Add it. */ 53 static struct dwarf_cie * 54 intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 55 { 56 struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie)); 57 if (cie == NULL) 58 { 59 __libdw_seterrno (DWARF_E_NOMEM); 60 return NULL; 61 } 62 63 cie->offset = offset; 64 cie->code_alignment_factor = info->code_alignment_factor; 65 cie->data_alignment_factor = info->data_alignment_factor; 66 cie->return_address_register = info->return_address_register; 67 68 cie->fde_augmentation_data_size = 0; 69 cie->sized_augmentation_data = false; 70 cie->signal_frame = false; 71 72 cie->fde_encoding = DW_EH_PE_absptr; 73 cie->lsda_encoding = DW_EH_PE_omit; 74 75 /* Grok the augmentation string and its data. */ 76 const uint8_t *data = info->augmentation_data; 77 for (const char *ap = info->augmentation; *ap != '\0'; ++ap) 78 { 79 uint8_t encoding; 80 switch (*ap) 81 { 82 case 'z': 83 cie->sized_augmentation_data = true; 84 continue; 85 86 case 'S': 87 cie->signal_frame = true; 88 continue; 89 90 case 'L': /* LSDA pointer encoding byte. */ 91 cie->lsda_encoding = *data++; 92 if (!cie->sized_augmentation_data) 93 cie->fde_augmentation_data_size 94 += encoded_value_size (&cache->data->d, cache->e_ident, 95 cie->lsda_encoding, NULL); 96 continue; 97 98 case 'R': /* FDE address encoding byte. */ 99 cie->fde_encoding = *data++; 100 continue; 101 102 case 'P': /* Skip personality routine. */ 103 encoding = *data++; 104 data += encoded_value_size (&cache->data->d, cache->e_ident, 105 encoding, data); 106 continue; 107 108 default: 109 /* Unknown augmentation string. If we have 'z' we can ignore it, 110 otherwise we must bail out. */ 111 if (cie->sized_augmentation_data) 112 continue; 113 } 114 /* We only get here when we need to bail out. */ 115 break; 116 } 117 118 if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr) 119 { 120 /* Canonicalize encoding to a specific size. */ 121 assert (DW_EH_PE_absptr == 0); 122 123 /* XXX should get from dwarf_next_cfi with v4 header. */ 124 uint_fast8_t address_size 125 = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 126 switch (address_size) 127 { 128 case 8: 129 cie->fde_encoding |= DW_EH_PE_udata8; 130 break; 131 case 4: 132 cie->fde_encoding |= DW_EH_PE_udata4; 133 break; 134 default: 135 free (cie); 136 __libdw_seterrno (DWARF_E_INVALID_DWARF); 137 return NULL; 138 } 139 } 140 141 /* Save the initial instructions to be played out into initial state. */ 142 cie->initial_instructions = info->initial_instructions; 143 cie->initial_instructions_end = info->initial_instructions_end; 144 cie->initial_state = NULL; 145 146 /* Add the new entry to the search tree. */ 147 if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL) 148 { 149 free (cie); 150 __libdw_seterrno (DWARF_E_NOMEM); 151 return NULL; 152 } 153 154 return cie; 155 } 156 157 /* Look up a CIE_pointer for random access. */ 158 struct dwarf_cie * 159 internal_function 160 __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) 161 { 162 const struct dwarf_cie cie_key = { .offset = offset }; 163 struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 164 if (found != NULL) 165 return *found; 166 167 /* We have not read this CIE yet. Go find it. */ 168 Dwarf_Off next_offset = offset; 169 Dwarf_CFI_Entry entry; 170 int result = INTUSE(dwarf_next_cfi) (cache->e_ident, 171 &cache->data->d, CFI_IS_EH (cache), 172 offset, &next_offset, &entry); 173 if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64) 174 { 175 __libdw_seterrno (DWARF_E_INVALID_DWARF); 176 return NULL; 177 } 178 179 /* If this happened to be what we would have read next, notice it. */ 180 if (cache->next_offset == offset) 181 cache->next_offset = next_offset; 182 183 return intern_new_cie (cache, offset, &entry.cie); 184 } 185 186 /* Enter a CIE encountered while reading through for FDEs. */ 187 void 188 internal_function 189 __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 190 { 191 const struct dwarf_cie cie_key = { .offset = offset }; 192 struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 193 if (found == NULL) 194 /* We have not read this CIE yet. Enter it. */ 195 (void) intern_new_cie (cache, offset, info); 196 } 197