Branch data Line data Source code
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 : 55900 : compare_cie (const void *a, const void *b) 42 : : { 43 : 55900 : const struct dwarf_cie *cie1 = a; 44 : 55900 : const struct dwarf_cie *cie2 = b; 45 [ + + ]: 55900 : if (cie1->offset < cie2->offset) 46 : : return -1; 47 [ + + ]: 43196 : if (cie1->offset > cie2->offset) 48 : 4708 : 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 : 310 : intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 55 : : { 56 : 310 : struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie)); 57 [ - + ]: 310 : if (cie == NULL) 58 : : { 59 : 0 : __libdw_seterrno (DWARF_E_NOMEM); 60 : 0 : return NULL; 61 : : } 62 : : 63 : 310 : cie->offset = offset; 64 : 310 : cie->code_alignment_factor = info->code_alignment_factor; 65 : 310 : cie->data_alignment_factor = info->data_alignment_factor; 66 : 310 : cie->return_address_register = info->return_address_register; 67 : : 68 : 310 : cie->fde_augmentation_data_size = 0; 69 : 310 : cie->sized_augmentation_data = false; 70 : 310 : cie->signal_frame = false; 71 : : 72 : 310 : cie->fde_encoding = DW_EH_PE_absptr; 73 : 310 : cie->lsda_encoding = DW_EH_PE_omit; 74 : : 75 : : /* Grok the augmentation string and its data. */ 76 : 310 : const uint8_t *data = info->augmentation_data; 77 [ + + ]: 834 : for (const char *ap = info->augmentation; *ap != '\0'; ++ap) 78 : : { 79 : 524 : uint8_t encoding; 80 [ + + + + : 524 : switch (*ap) + - ] 81 : : { 82 : 224 : case 'z': 83 : 224 : cie->sized_augmentation_data = true; 84 : 224 : continue; 85 : : 86 : 6 : case 'S': 87 : 6 : cie->signal_frame = true; 88 : 6 : continue; 89 : : 90 : 34 : case 'L': /* LSDA pointer encoding byte. */ 91 : 34 : cie->lsda_encoding = *data++; 92 [ - + ]: 34 : if (!cie->sized_augmentation_data) 93 : 0 : cie->fde_augmentation_data_size 94 : 0 : += encoded_value_size (&cache->data->d, cache->e_ident, 95 : : cie->lsda_encoding, NULL); 96 : 34 : continue; 97 : : 98 : 218 : case 'R': /* FDE address encoding byte. */ 99 : 218 : cie->fde_encoding = *data++; 100 : 218 : continue; 101 : : 102 : 42 : case 'P': /* Skip personality routine. */ 103 : 42 : encoding = *data++; 104 : 42 : data += encoded_value_size (&cache->data->d, cache->e_ident, 105 : : encoding, data); 106 : 42 : continue; 107 : : 108 : 0 : default: 109 : : /* Unknown augmentation string. If we have 'z' we can ignore it, 110 : : otherwise we must bail out. */ 111 [ # # ]: 0 : if (cie->sized_augmentation_data) 112 : 0 : continue; 113 : : } 114 : : /* We only get here when we need to bail out. */ 115 : : break; 116 : : } 117 : : 118 [ + + ]: 310 : if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr) 119 : : { 120 : : /* Canonicalize encoding to a specific size. */ 121 : 92 : assert (DW_EH_PE_absptr == 0); 122 : : 123 : : /* XXX should get from dwarf_next_cfi with v4 header. */ 124 : 184 : uint_fast8_t address_size 125 [ + + ]: 92 : = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 126 : 92 : switch (address_size) 127 : : { 128 : : case 8: 129 : 56 : cie->fde_encoding |= DW_EH_PE_udata8; 130 : 56 : break; 131 : : case 4: 132 : 36 : cie->fde_encoding |= DW_EH_PE_udata4; 133 : 36 : 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 : 310 : cie->initial_instructions = info->initial_instructions; 143 : 310 : cie->initial_instructions_end = info->initial_instructions_end; 144 : 310 : cie->initial_state = NULL; 145 : : 146 : : /* Add the new entry to the search tree. */ 147 [ - + ]: 310 : if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL) 148 : : { 149 : 0 : free (cie); 150 : 0 : __libdw_seterrno (DWARF_E_NOMEM); 151 : 0 : 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 : 38602 : __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) 161 : : { 162 : 38602 : const struct dwarf_cie cie_key = { .offset = offset }; 163 : 38602 : struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 164 [ + + ]: 38602 : if (found != NULL) 165 : 38488 : return *found; 166 : : 167 : : /* We have not read this CIE yet. Go find it. */ 168 : 114 : Dwarf_Off next_offset = offset; 169 : 114 : Dwarf_CFI_Entry entry; 170 : 228 : int result = INTUSE(dwarf_next_cfi) (cache->e_ident, 171 : 114 : &cache->data->d, CFI_IS_EH (cache), 172 : : offset, &next_offset, &entry); 173 [ + - - + ]: 114 : if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64) 174 : : { 175 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 176 : 0 : return NULL; 177 : : } 178 : : 179 : : /* If this happened to be what we would have read next, notice it. */ 180 [ + + ]: 114 : if (cache->next_offset == offset) 181 : 44 : cache->next_offset = next_offset; 182 : : 183 : 114 : 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 : 196 : __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 190 : : { 191 : 196 : const struct dwarf_cie cie_key = { .offset = offset }; 192 : 196 : struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 193 [ + - ]: 196 : if (found == NULL) 194 : : /* We have not read this CIE yet. Enter it. */ 195 : 196 : (void) intern_new_cie (cache, offset, info); 196 : 196 : }