1da0c48c4Sopenharmony_ci/* CIE reading. 2da0c48c4Sopenharmony_ci Copyright (C) 2009-2010 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include "cfi.h" 34da0c48c4Sopenharmony_ci#include "encoded-value.h" 35da0c48c4Sopenharmony_ci#include <assert.h> 36da0c48c4Sopenharmony_ci#include <search.h> 37da0c48c4Sopenharmony_ci#include <stdlib.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_ci 40da0c48c4Sopenharmony_cistatic int 41da0c48c4Sopenharmony_cicompare_cie (const void *a, const void *b) 42da0c48c4Sopenharmony_ci{ 43da0c48c4Sopenharmony_ci const struct dwarf_cie *cie1 = a; 44da0c48c4Sopenharmony_ci const struct dwarf_cie *cie2 = b; 45da0c48c4Sopenharmony_ci if (cie1->offset < cie2->offset) 46da0c48c4Sopenharmony_ci return -1; 47da0c48c4Sopenharmony_ci if (cie1->offset > cie2->offset) 48da0c48c4Sopenharmony_ci return 1; 49da0c48c4Sopenharmony_ci return 0; 50da0c48c4Sopenharmony_ci} 51da0c48c4Sopenharmony_ci 52da0c48c4Sopenharmony_ci/* There is no CIE at OFFSET in the tree. Add it. */ 53da0c48c4Sopenharmony_cistatic struct dwarf_cie * 54da0c48c4Sopenharmony_ciintern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 55da0c48c4Sopenharmony_ci{ 56da0c48c4Sopenharmony_ci struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie)); 57da0c48c4Sopenharmony_ci if (cie == NULL) 58da0c48c4Sopenharmony_ci { 59da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NOMEM); 60da0c48c4Sopenharmony_ci return NULL; 61da0c48c4Sopenharmony_ci } 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_ci cie->offset = offset; 64da0c48c4Sopenharmony_ci cie->code_alignment_factor = info->code_alignment_factor; 65da0c48c4Sopenharmony_ci cie->data_alignment_factor = info->data_alignment_factor; 66da0c48c4Sopenharmony_ci cie->return_address_register = info->return_address_register; 67da0c48c4Sopenharmony_ci 68da0c48c4Sopenharmony_ci cie->fde_augmentation_data_size = 0; 69da0c48c4Sopenharmony_ci cie->sized_augmentation_data = false; 70da0c48c4Sopenharmony_ci cie->signal_frame = false; 71da0c48c4Sopenharmony_ci 72da0c48c4Sopenharmony_ci cie->fde_encoding = DW_EH_PE_absptr; 73da0c48c4Sopenharmony_ci cie->lsda_encoding = DW_EH_PE_omit; 74da0c48c4Sopenharmony_ci 75da0c48c4Sopenharmony_ci /* Grok the augmentation string and its data. */ 76da0c48c4Sopenharmony_ci const uint8_t *data = info->augmentation_data; 77da0c48c4Sopenharmony_ci for (const char *ap = info->augmentation; *ap != '\0'; ++ap) 78da0c48c4Sopenharmony_ci { 79da0c48c4Sopenharmony_ci uint8_t encoding; 80da0c48c4Sopenharmony_ci switch (*ap) 81da0c48c4Sopenharmony_ci { 82da0c48c4Sopenharmony_ci case 'z': 83da0c48c4Sopenharmony_ci cie->sized_augmentation_data = true; 84da0c48c4Sopenharmony_ci continue; 85da0c48c4Sopenharmony_ci 86da0c48c4Sopenharmony_ci case 'S': 87da0c48c4Sopenharmony_ci cie->signal_frame = true; 88da0c48c4Sopenharmony_ci continue; 89da0c48c4Sopenharmony_ci 90da0c48c4Sopenharmony_ci case 'L': /* LSDA pointer encoding byte. */ 91da0c48c4Sopenharmony_ci cie->lsda_encoding = *data++; 92da0c48c4Sopenharmony_ci if (!cie->sized_augmentation_data) 93da0c48c4Sopenharmony_ci cie->fde_augmentation_data_size 94da0c48c4Sopenharmony_ci += encoded_value_size (&cache->data->d, cache->e_ident, 95da0c48c4Sopenharmony_ci cie->lsda_encoding, NULL); 96da0c48c4Sopenharmony_ci continue; 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci case 'R': /* FDE address encoding byte. */ 99da0c48c4Sopenharmony_ci cie->fde_encoding = *data++; 100da0c48c4Sopenharmony_ci continue; 101da0c48c4Sopenharmony_ci 102da0c48c4Sopenharmony_ci case 'P': /* Skip personality routine. */ 103da0c48c4Sopenharmony_ci encoding = *data++; 104da0c48c4Sopenharmony_ci data += encoded_value_size (&cache->data->d, cache->e_ident, 105da0c48c4Sopenharmony_ci encoding, data); 106da0c48c4Sopenharmony_ci continue; 107da0c48c4Sopenharmony_ci 108da0c48c4Sopenharmony_ci default: 109da0c48c4Sopenharmony_ci /* Unknown augmentation string. If we have 'z' we can ignore it, 110da0c48c4Sopenharmony_ci otherwise we must bail out. */ 111da0c48c4Sopenharmony_ci if (cie->sized_augmentation_data) 112da0c48c4Sopenharmony_ci continue; 113da0c48c4Sopenharmony_ci } 114da0c48c4Sopenharmony_ci /* We only get here when we need to bail out. */ 115da0c48c4Sopenharmony_ci break; 116da0c48c4Sopenharmony_ci } 117da0c48c4Sopenharmony_ci 118da0c48c4Sopenharmony_ci if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr) 119da0c48c4Sopenharmony_ci { 120da0c48c4Sopenharmony_ci /* Canonicalize encoding to a specific size. */ 121da0c48c4Sopenharmony_ci assert (DW_EH_PE_absptr == 0); 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ci /* XXX should get from dwarf_next_cfi with v4 header. */ 124da0c48c4Sopenharmony_ci uint_fast8_t address_size 125da0c48c4Sopenharmony_ci = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; 126da0c48c4Sopenharmony_ci switch (address_size) 127da0c48c4Sopenharmony_ci { 128da0c48c4Sopenharmony_ci case 8: 129da0c48c4Sopenharmony_ci cie->fde_encoding |= DW_EH_PE_udata8; 130da0c48c4Sopenharmony_ci break; 131da0c48c4Sopenharmony_ci case 4: 132da0c48c4Sopenharmony_ci cie->fde_encoding |= DW_EH_PE_udata4; 133da0c48c4Sopenharmony_ci break; 134da0c48c4Sopenharmony_ci default: 135da0c48c4Sopenharmony_ci free (cie); 136da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 137da0c48c4Sopenharmony_ci return NULL; 138da0c48c4Sopenharmony_ci } 139da0c48c4Sopenharmony_ci } 140da0c48c4Sopenharmony_ci 141da0c48c4Sopenharmony_ci /* Save the initial instructions to be played out into initial state. */ 142da0c48c4Sopenharmony_ci cie->initial_instructions = info->initial_instructions; 143da0c48c4Sopenharmony_ci cie->initial_instructions_end = info->initial_instructions_end; 144da0c48c4Sopenharmony_ci cie->initial_state = NULL; 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_ci /* Add the new entry to the search tree. */ 147da0c48c4Sopenharmony_ci if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL) 148da0c48c4Sopenharmony_ci { 149da0c48c4Sopenharmony_ci free (cie); 150da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NOMEM); 151da0c48c4Sopenharmony_ci return NULL; 152da0c48c4Sopenharmony_ci } 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci return cie; 155da0c48c4Sopenharmony_ci} 156da0c48c4Sopenharmony_ci 157da0c48c4Sopenharmony_ci/* Look up a CIE_pointer for random access. */ 158da0c48c4Sopenharmony_cistruct dwarf_cie * 159da0c48c4Sopenharmony_ciinternal_function 160da0c48c4Sopenharmony_ci__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset) 161da0c48c4Sopenharmony_ci{ 162da0c48c4Sopenharmony_ci const struct dwarf_cie cie_key = { .offset = offset }; 163da0c48c4Sopenharmony_ci struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 164da0c48c4Sopenharmony_ci if (found != NULL) 165da0c48c4Sopenharmony_ci return *found; 166da0c48c4Sopenharmony_ci 167da0c48c4Sopenharmony_ci /* We have not read this CIE yet. Go find it. */ 168da0c48c4Sopenharmony_ci Dwarf_Off next_offset = offset; 169da0c48c4Sopenharmony_ci Dwarf_CFI_Entry entry; 170da0c48c4Sopenharmony_ci int result = INTUSE(dwarf_next_cfi) (cache->e_ident, 171da0c48c4Sopenharmony_ci &cache->data->d, CFI_IS_EH (cache), 172da0c48c4Sopenharmony_ci offset, &next_offset, &entry); 173da0c48c4Sopenharmony_ci if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64) 174da0c48c4Sopenharmony_ci { 175da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 176da0c48c4Sopenharmony_ci return NULL; 177da0c48c4Sopenharmony_ci } 178da0c48c4Sopenharmony_ci 179da0c48c4Sopenharmony_ci /* If this happened to be what we would have read next, notice it. */ 180da0c48c4Sopenharmony_ci if (cache->next_offset == offset) 181da0c48c4Sopenharmony_ci cache->next_offset = next_offset; 182da0c48c4Sopenharmony_ci 183da0c48c4Sopenharmony_ci return intern_new_cie (cache, offset, &entry.cie); 184da0c48c4Sopenharmony_ci} 185da0c48c4Sopenharmony_ci 186da0c48c4Sopenharmony_ci/* Enter a CIE encountered while reading through for FDEs. */ 187da0c48c4Sopenharmony_civoid 188da0c48c4Sopenharmony_ciinternal_function 189da0c48c4Sopenharmony_ci__libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info) 190da0c48c4Sopenharmony_ci{ 191da0c48c4Sopenharmony_ci const struct dwarf_cie cie_key = { .offset = offset }; 192da0c48c4Sopenharmony_ci struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie); 193da0c48c4Sopenharmony_ci if (found == NULL) 194da0c48c4Sopenharmony_ci /* We have not read this CIE yet. Enter it. */ 195da0c48c4Sopenharmony_ci (void) intern_new_cie (cache, offset, info); 196da0c48c4Sopenharmony_ci} 197