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 <stdlib.h>
37 : : #include "eu-search.h"
38 : :
39 : :
40 : : static int
41 : 56004 : compare_cie (const void *a, const void *b)
42 : : {
43 : 56004 : const struct dwarf_cie *cie1 = a;
44 : 56004 : const struct dwarf_cie *cie2 = b;
45 [ + + ]: 56004 : if (cie1->offset < cie2->offset)
46 : : return -1;
47 [ + + ]: 43300 : 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 : 318 : intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
55 : : {
56 : 318 : struct dwarf_cie *cie = malloc (sizeof (struct dwarf_cie));
57 [ - + ]: 318 : if (cie == NULL)
58 : : {
59 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
60 : 0 : return NULL;
61 : : }
62 : :
63 : 318 : cie->offset = offset;
64 : 318 : cie->code_alignment_factor = info->code_alignment_factor;
65 : 318 : cie->data_alignment_factor = info->data_alignment_factor;
66 : 318 : cie->return_address_register = info->return_address_register;
67 : :
68 : 318 : cie->fde_augmentation_data_size = 0;
69 : 318 : cie->sized_augmentation_data = false;
70 : 318 : cie->signal_frame = false;
71 : :
72 : 318 : cie->fde_encoding = DW_EH_PE_absptr;
73 : 318 : cie->lsda_encoding = DW_EH_PE_omit;
74 : :
75 : : /* Grok the augmentation string and its data. */
76 : 318 : const uint8_t *data = info->augmentation_data;
77 [ + + ]: 858 : for (const char *ap = info->augmentation; *ap != '\0'; ++ap)
78 : : {
79 : 540 : uint8_t encoding;
80 [ + + + + : 540 : switch (*ap)
+ - ]
81 : : {
82 : 232 : case 'z':
83 : 232 : cie->sized_augmentation_data = true;
84 : 232 : 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 : 226 : case 'R': /* FDE address encoding byte. */
99 : 226 : cie->fde_encoding = *data++;
100 : 226 : 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 [ + + ]: 318 : 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 : 318 : cie->initial_instructions = info->initial_instructions;
143 : 318 : cie->initial_instructions_end = info->initial_instructions_end;
144 : 318 : cie->initial_state = NULL;
145 : :
146 : : /* Add the new entry to the search tree. */
147 [ - + ]: 318 : if (eu_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 : 38714 : __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
161 : : {
162 : 38714 : const struct dwarf_cie cie_key = { .offset = offset };
163 : 38714 : struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree,
164 : : &compare_cie);
165 [ + + ]: 38714 : if (found != NULL)
166 : 38592 : return *found;
167 : :
168 : : /* We have not read this CIE yet. Go find it. */
169 : 122 : Dwarf_Off next_offset = offset;
170 : 122 : Dwarf_CFI_Entry entry;
171 : 244 : int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
172 : 122 : &cache->data->d, CFI_IS_EH (cache),
173 : : offset, &next_offset, &entry);
174 [ + - - + ]: 122 : if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64)
175 : : {
176 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
177 : 0 : return NULL;
178 : : }
179 : :
180 : : /* If this happened to be what we would have read next, notice it. */
181 [ + + ]: 122 : if (cache->next_offset == offset)
182 : 52 : cache->next_offset = next_offset;
183 : :
184 : 122 : return intern_new_cie (cache, offset, &entry.cie);
185 : : }
186 : :
187 : : /* Enter a CIE encountered while reading through for FDEs. */
188 : : void
189 : : internal_function
190 : 196 : __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
191 : : {
192 : 196 : const struct dwarf_cie cie_key = { .offset = offset };
193 : 196 : struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree,
194 : : &compare_cie);
195 [ + - ]: 196 : if (found == NULL)
196 : : /* We have not read this CIE yet. Enter it. */
197 : 196 : (void) intern_new_cie (cache, offset, info);
198 : 196 : }
|