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 : 58922 : compare_cie (const void *a, const void *b)
42 : : {
43 : 58922 : const struct dwarf_cie *cie1 = a;
44 : 58922 : const struct dwarf_cie *cie2 = b;
45 [ + + ]: 58922 : if (cie1->offset < cie2->offset)
46 : : return -1;
47 [ + + ]: 46218 : 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 : 318 : const char *ap = info->augmentation;
78 : : /* If present, 'z' must be the first char. */
79 [ + + ]: 318 : if (*ap == 'z')
80 : : {
81 : 232 : cie->sized_augmentation_data = true;
82 : 232 : ap++;
83 : : }
84 [ + + ]: 626 : for (; *ap != '\0'; ++ap)
85 : : {
86 : 308 : uint8_t encoding;
87 [ + + + + : 308 : switch (*ap)
- ]
88 : : {
89 : 6 : case 'S':
90 : 6 : cie->signal_frame = true;
91 : 6 : continue;
92 : :
93 : 34 : case 'L': /* LSDA pointer encoding byte. */
94 [ + - ]: 34 : if (cie->sized_augmentation_data)
95 : 34 : cie->lsda_encoding = *data++;
96 [ - + ]: 34 : if (!cie->sized_augmentation_data)
97 : 0 : cie->fde_augmentation_data_size
98 : 0 : += encoded_value_size (&cache->data->d, cache->e_ident,
99 : 0 : cie->lsda_encoding, NULL);
100 : 34 : continue;
101 : :
102 : 226 : case 'R': /* FDE address encoding byte. */
103 [ + - ]: 226 : if (cie->sized_augmentation_data)
104 : 226 : cie->fde_encoding = *data++;
105 : 226 : continue;
106 : :
107 : 42 : case 'P': /* Skip personality routine. */
108 [ + - ]: 42 : if (cie->sized_augmentation_data)
109 : : {
110 : 42 : encoding = *data++;
111 : 42 : data += encoded_value_size (&cache->data->d, cache->e_ident,
112 : : encoding, data);
113 : : }
114 : 42 : continue;
115 : :
116 : 0 : default:
117 : : /* Unknown augmentation string. If we have 'z' we can ignore it,
118 : : otherwise we must bail out. */
119 [ # # ]: 0 : if (cie->sized_augmentation_data)
120 : 0 : continue;
121 : : }
122 : : /* We only get here when we need to bail out. */
123 : : break;
124 : : }
125 : :
126 [ + + ]: 318 : if ((cie->fde_encoding & 0x0f) == DW_EH_PE_absptr)
127 : : {
128 : : /* Canonicalize encoding to a specific size. */
129 : 92 : assert (DW_EH_PE_absptr == 0);
130 : :
131 : : /* XXX should get from dwarf_next_cfi with v4 header. */
132 : 184 : uint_fast8_t address_size
133 [ + + ]: 92 : = cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
134 : 92 : switch (address_size)
135 : : {
136 : : case 8:
137 : 56 : cie->fde_encoding |= DW_EH_PE_udata8;
138 : 56 : break;
139 : : case 4:
140 : 36 : cie->fde_encoding |= DW_EH_PE_udata4;
141 : 36 : break;
142 : : default:
143 : : free (cie);
144 : : __libdw_seterrno (DWARF_E_INVALID_DWARF);
145 : : return NULL;
146 : : }
147 : : }
148 : :
149 : : /* Save the initial instructions to be played out into initial state. */
150 : 318 : cie->initial_instructions = info->initial_instructions;
151 : 318 : cie->initial_instructions_end = info->initial_instructions_end;
152 : 318 : cie->initial_state = NULL;
153 : :
154 : : /* Add the new entry to the search tree. */
155 [ - + ]: 318 : if (eu_tsearch (cie, &cache->cie_tree, &compare_cie) == NULL)
156 : : {
157 : 0 : free (cie);
158 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
159 : 0 : return NULL;
160 : : }
161 : :
162 : : return cie;
163 : : }
164 : :
165 : : /* Look up a CIE_pointer for random access. */
166 : : struct dwarf_cie *
167 : : internal_function
168 : 41632 : __libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
169 : : {
170 : 41632 : const struct dwarf_cie cie_key = { .offset = offset };
171 : 41632 : struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree,
172 : : &compare_cie);
173 [ + + ]: 41632 : if (found != NULL)
174 : 41510 : return *found;
175 : :
176 : : /* We have not read this CIE yet. Go find it. */
177 : 122 : Dwarf_Off next_offset = offset;
178 : 122 : Dwarf_CFI_Entry entry;
179 : 244 : int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
180 : 122 : &cache->data->d, CFI_IS_EH (cache),
181 : : offset, &next_offset, &entry);
182 [ + - - + ]: 122 : if (result != 0 || entry.cie.CIE_id != DW_CIE_ID_64)
183 : : {
184 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
185 : 0 : return NULL;
186 : : }
187 : :
188 : : /* If this happened to be what we would have read next, notice it. */
189 [ + + ]: 122 : if (cache->next_offset == offset)
190 : 52 : cache->next_offset = next_offset;
191 : :
192 : 122 : return intern_new_cie (cache, offset, &entry.cie);
193 : : }
194 : :
195 : : /* Enter a CIE encountered while reading through for FDEs. */
196 : : void
197 : : internal_function
198 : 196 : __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
199 : : {
200 : 196 : const struct dwarf_cie cie_key = { .offset = offset };
201 : 196 : struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree,
202 : : &compare_cie);
203 [ + - ]: 196 : if (found == NULL)
204 : : /* We have not read this CIE yet. Enter it. */
205 : 196 : (void) intern_new_cie (cache, offset, info);
206 : 196 : }
|