/src/libunwind/src/dwarf/Gfde.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* libunwind - a platform-independent unwind library |
2 | | Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. |
3 | | Contributed by David Mosberger-Tang <davidm@hpl.hp.com> |
4 | | |
5 | | This file is part of libunwind. |
6 | | |
7 | | Permission is hereby granted, free of charge, to any person obtaining |
8 | | a copy of this software and associated documentation files (the |
9 | | "Software"), to deal in the Software without restriction, including |
10 | | without limitation the rights to use, copy, modify, merge, publish, |
11 | | distribute, sublicense, and/or sell copies of the Software, and to |
12 | | permit persons to whom the Software is furnished to do so, subject to |
13 | | the following conditions: |
14 | | |
15 | | The above copyright notice and this permission notice shall be |
16 | | included in all copies or substantial portions of the Software. |
17 | | |
18 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
19 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
20 | | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
21 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
22 | | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
23 | | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
24 | | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
25 | | |
26 | | #include "dwarf_i.h" |
27 | | |
28 | | static inline int |
29 | | is_cie_id (unw_word_t val, int is_debug_frame) |
30 | 15 | { |
31 | | /* The CIE ID is normally 0xffffffff (for 32-bit ELF) or |
32 | | 0xffffffffffffffff (for 64-bit ELF). However, .eh_frame |
33 | | uses 0. */ |
34 | 15 | if (is_debug_frame) |
35 | 0 | return (val == (uint32_t)(-1) || val == (uint64_t)(-1)); |
36 | 15 | else |
37 | 15 | return (val == 0); |
38 | 15 | } |
39 | | |
40 | | /* Note: we don't need to keep track of more than the first four |
41 | | characters of the augmentation string, because we (a) ignore any |
42 | | augmentation string contents once we find an unrecognized character |
43 | | and (b) those characters that we do recognize, can't be |
44 | | repeated. */ |
45 | | static inline int |
46 | | parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, |
47 | | const unw_proc_info_t *pi, struct dwarf_cie_info *dci, |
48 | | int is_debug_frame, void *arg) |
49 | 15 | { |
50 | 15 | uint8_t version, ch, augstr[5], fde_encoding, handler_encoding; |
51 | 15 | uint8_t address_size, segment_size; |
52 | 15 | unw_word_t len, cie_end_addr, aug_size; |
53 | 15 | uint32_t u32val; |
54 | 15 | uint64_t u64val; |
55 | 15 | size_t i; |
56 | 15 | int ret; |
57 | 15 | # define STR2(x) #x |
58 | 15 | # define STR(x) STR2(x) |
59 | | |
60 | | /* Pick appropriate default for FDE-encoding. DWARF spec says |
61 | | start-IP (initial_location) and the code-size (address_range) are |
62 | | "address-unit sized constants". The `R' augmentation can be used |
63 | | to override this, but by default, we pick an address-sized unit |
64 | | for fde_encoding. */ |
65 | 15 | switch (dwarf_addr_size (as)) |
66 | 15 | { |
67 | 0 | case 4: fde_encoding = DW_EH_PE_udata4; break; |
68 | 15 | case 8: fde_encoding = DW_EH_PE_udata8; break; |
69 | 0 | default: fde_encoding = DW_EH_PE_omit; break; |
70 | 15 | } |
71 | | |
72 | 15 | dci->lsda_encoding = DW_EH_PE_omit; |
73 | 15 | dci->handler = 0; |
74 | | |
75 | 15 | if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) |
76 | 0 | return ret; |
77 | | |
78 | 15 | if (u32val != 0xffffffff) |
79 | 15 | { |
80 | | /* the CIE is in the 32-bit DWARF format */ |
81 | 15 | uint32_t cie_id; |
82 | | /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */ |
83 | 15 | const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0; |
84 | | |
85 | 15 | len = u32val; |
86 | 15 | cie_end_addr = addr + len; |
87 | 15 | if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0) |
88 | 0 | return ret; |
89 | 15 | if (cie_id != expected_id) |
90 | 0 | { |
91 | 0 | Debug (1, "Unexpected CIE id %x\n", cie_id); |
92 | 0 | return -UNW_EINVAL; |
93 | 0 | } |
94 | 15 | } |
95 | 0 | else |
96 | 0 | { |
97 | | /* the CIE is in the 64-bit DWARF format */ |
98 | 0 | uint64_t cie_id; |
99 | | /* DWARF says CIE id should be 0xffffffffffffffff, but in |
100 | | .eh_frame, it's 0 */ |
101 | 0 | const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull : 0; |
102 | |
|
103 | 0 | if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) |
104 | 0 | return ret; |
105 | 0 | len = (unw_word_t) u64val; |
106 | 0 | cie_end_addr = addr + len; |
107 | 0 | if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0) |
108 | 0 | return ret; |
109 | 0 | if (cie_id != expected_id) |
110 | 0 | { |
111 | 0 | Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id); |
112 | 0 | return -UNW_EINVAL; |
113 | 0 | } |
114 | 0 | } |
115 | 15 | dci->cie_instr_end = cie_end_addr; |
116 | | |
117 | 15 | if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0) |
118 | 0 | return ret; |
119 | | |
120 | | /* GCC emits version 1??? */ |
121 | 15 | if (version != 1 && (version < DWARF_CIE_VERSION || version > DWARF_CIE_VERSION_MAX)) |
122 | 0 | { |
123 | 0 | Debug (1, "Got CIE version %u, expected version 1 or between " |
124 | 0 | STR (DWARF_CIE_VERSION) " and " STR (DWARF_CIE_VERSION_MAX) "\n", version); |
125 | 0 | return -UNW_EBADVERSION; |
126 | 0 | } |
127 | | |
128 | | /* read and parse the augmentation string: */ |
129 | 15 | memset (augstr, 0, sizeof (augstr)); |
130 | 15 | for (i = 0;;) |
131 | 45 | { |
132 | 45 | if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) |
133 | 0 | return ret; |
134 | | |
135 | 45 | if (!ch) |
136 | 15 | break; /* end of augmentation string */ |
137 | | |
138 | 30 | if (i < sizeof (augstr) - 1) |
139 | 30 | augstr[i++] = ch; |
140 | 30 | } |
141 | | |
142 | 15 | if (version > 3) |
143 | 0 | { |
144 | 0 | if((ret = dwarf_readu8(as, a, &addr, &address_size, arg)) < 0) |
145 | 0 | return ret; |
146 | | |
147 | 0 | if((ret = dwarf_readu8(as, a, &addr, &segment_size, arg)) < 0) |
148 | 0 | return ret; |
149 | 0 | } |
150 | | |
151 | 15 | if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0 |
152 | 15 | || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0) |
153 | 0 | return ret; |
154 | | |
155 | | /* Read the return-address column either as a u8 or as a uleb128. */ |
156 | 15 | if (version == 1) |
157 | 15 | { |
158 | 15 | if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) |
159 | 0 | return ret; |
160 | 15 | dci->ret_addr_column = ch; |
161 | 15 | } |
162 | 0 | else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column, |
163 | 0 | arg)) < 0) |
164 | 0 | return ret; |
165 | | |
166 | 15 | i = 0; |
167 | 15 | if (augstr[0] == 'z') |
168 | 15 | { |
169 | 15 | dci->sized_augmentation = 1; |
170 | 15 | if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) |
171 | 0 | return ret; |
172 | 15 | i++; |
173 | 15 | } |
174 | | |
175 | 30 | for (; i < sizeof (augstr) && augstr[i]; ++i) |
176 | 15 | switch (augstr[i]) |
177 | 15 | { |
178 | 0 | case 'L': |
179 | | /* read the LSDA pointer-encoding format. */ |
180 | 0 | if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0) |
181 | 0 | return ret; |
182 | 0 | dci->lsda_encoding = ch; |
183 | 0 | break; |
184 | | |
185 | 15 | case 'R': |
186 | | /* read the FDE pointer-encoding format. */ |
187 | 15 | if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0) |
188 | 0 | return ret; |
189 | 15 | break; |
190 | | |
191 | 15 | case 'P': |
192 | | /* read the personality-routine pointer-encoding format. */ |
193 | 0 | if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0) |
194 | 0 | return ret; |
195 | 0 | if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding, |
196 | 0 | pi, &dci->handler, arg)) < 0) |
197 | 0 | return ret; |
198 | 0 | break; |
199 | | |
200 | 0 | case 'S': |
201 | | /* This is a signal frame. */ |
202 | 0 | dci->signal_frame = 1; |
203 | | |
204 | | /* Temporarily set it to one so dwarf_parse_fde() knows that |
205 | | it should fetch the actual ABI/TAG pair from the FDE. */ |
206 | 0 | dci->have_abi_marker = 1; |
207 | 0 | break; |
208 | | |
209 | 0 | default: |
210 | 0 | Debug (1, "Unexpected augmentation string `%s'\n", augstr); |
211 | 0 | if (dci->sized_augmentation) |
212 | | /* If we have the size of the augmentation body, we can skip |
213 | | over the parts that we don't understand, so we're OK. */ |
214 | 0 | goto done; |
215 | 0 | else |
216 | 0 | return -UNW_EINVAL; |
217 | 15 | } |
218 | 15 | done: |
219 | 15 | dci->fde_encoding = fde_encoding; |
220 | 15 | dci->cie_instr_start = addr; |
221 | 15 | Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n", |
222 | 15 | augstr, (long) dci->handler); |
223 | 15 | return 0; |
224 | 15 | } |
225 | | |
226 | | /* Extract proc-info from the FDE starting at address ADDR. |
227 | | |
228 | | Pass BASE as zero for eh_frame behaviour, or a pointer to |
229 | | debug_frame base for debug_frame behaviour. */ |
230 | | |
231 | | HIDDEN int |
232 | | dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, |
233 | | unw_word_t *addrp, unw_proc_info_t *pi, |
234 | | unw_word_t base, |
235 | | int need_unwind_info, int is_debug_frame, |
236 | | void *arg) |
237 | 15 | { |
238 | 15 | unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0; |
239 | 15 | unw_word_t start_ip, ip_range, aug_size, addr = *addrp; |
240 | 15 | int ret; |
241 | 15 | uint8_t ip_range_encoding; |
242 | 15 | struct dwarf_cie_info dci; |
243 | 15 | uint64_t u64val; |
244 | 15 | uint32_t u32val; |
245 | | |
246 | 15 | Debug (12, "FDE @ 0x%lx\n", (long) addr); |
247 | | |
248 | 15 | memset (&dci, 0, sizeof (dci)); |
249 | | |
250 | 15 | if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0) |
251 | 0 | return ret; |
252 | | |
253 | 15 | if (u32val != 0xffffffff) |
254 | 15 | { |
255 | 15 | int32_t cie_offset = 0; |
256 | | |
257 | | /* In some configurations, an FDE with a 0 length indicates the |
258 | | end of the FDE-table. */ |
259 | 15 | if (u32val == 0) |
260 | 0 | return -UNW_ENOINFO; |
261 | | |
262 | | /* the FDE is in the 32-bit DWARF format */ |
263 | | |
264 | 15 | *addrp = fde_end_addr = addr + u32val; |
265 | 15 | cie_offset_addr = addr; |
266 | | |
267 | 15 | if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0) |
268 | 0 | return ret; |
269 | | |
270 | 15 | if (is_cie_id (cie_offset, is_debug_frame)) |
271 | | /* ignore CIEs (happens during linear searches) */ |
272 | 0 | return 0; |
273 | | |
274 | 15 | if (is_debug_frame) |
275 | 0 | cie_addr = base + cie_offset; |
276 | 15 | else |
277 | | /* DWARF says that the CIE_pointer in the FDE is a |
278 | | .debug_frame-relative offset, but the GCC-generated .eh_frame |
279 | | sections instead store a "pcrelative" offset, which is just |
280 | | as fine as it's self-contained. */ |
281 | 15 | cie_addr = cie_offset_addr - cie_offset; |
282 | 15 | } |
283 | 0 | else |
284 | 0 | { |
285 | 0 | int64_t cie_offset = 0; |
286 | | |
287 | | /* the FDE is in the 64-bit DWARF format */ |
288 | |
|
289 | 0 | if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0) |
290 | 0 | return ret; |
291 | | |
292 | 0 | *addrp = fde_end_addr = (unw_word_t) (addr + u64val); |
293 | 0 | cie_offset_addr = addr; |
294 | |
|
295 | 0 | if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0) |
296 | 0 | return ret; |
297 | | |
298 | 0 | if (is_cie_id ((unw_word_t) cie_offset, is_debug_frame)) |
299 | | /* ignore CIEs (happens during linear searches) */ |
300 | 0 | return 0; |
301 | | |
302 | 0 | if (is_debug_frame) |
303 | 0 | cie_addr = (unw_word_t) (base + cie_offset); |
304 | 0 | else |
305 | | /* DWARF says that the CIE_pointer in the FDE is a |
306 | | .debug_frame-relative offset, but the GCC-generated .eh_frame |
307 | | sections instead store a "pcrelative" offset, which is just |
308 | | as fine as it's self-contained. */ |
309 | 0 | cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); |
310 | 0 | } |
311 | | |
312 | 15 | Debug (15, "looking for CIE at address %lx\n", (long) cie_addr); |
313 | | |
314 | 15 | if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0) |
315 | 0 | return ret; |
316 | | |
317 | | /* IP-range has same encoding as FDE pointers, except that it's |
318 | | always an absolute value: */ |
319 | 15 | ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK; |
320 | | |
321 | 15 | if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding, |
322 | 15 | pi, &start_ip, arg)) < 0 |
323 | 15 | || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding, |
324 | 15 | pi, &ip_range, arg)) < 0) |
325 | 0 | return ret; |
326 | 15 | pi->start_ip = start_ip; |
327 | 15 | pi->end_ip = start_ip + ip_range; |
328 | 15 | pi->handler = dci.handler; |
329 | | |
330 | 15 | if (dci.sized_augmentation) |
331 | 15 | { |
332 | 15 | if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0) |
333 | 0 | return ret; |
334 | 15 | aug_end_addr = addr + aug_size; |
335 | 15 | } |
336 | | |
337 | 15 | if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding, |
338 | 15 | pi, &pi->lsda, arg)) < 0) |
339 | 0 | return ret; |
340 | | |
341 | 15 | Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n", |
342 | 15 | (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda); |
343 | | |
344 | 15 | if (need_unwind_info) |
345 | 15 | { |
346 | 15 | pi->format = UNW_INFO_FORMAT_TABLE; |
347 | 15 | pi->unwind_info_size = sizeof (dci); |
348 | 15 | pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool); |
349 | 15 | if (!pi->unwind_info) |
350 | 0 | return -UNW_ENOMEM; |
351 | | |
352 | 15 | if (dci.have_abi_marker) |
353 | 0 | { |
354 | 0 | if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0 |
355 | 0 | || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0) |
356 | 0 | return ret; |
357 | 0 | Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n", |
358 | 0 | dci.abi, dci.tag); |
359 | 0 | } |
360 | | |
361 | 15 | if (dci.sized_augmentation) |
362 | 15 | dci.fde_instr_start = aug_end_addr; |
363 | 0 | else |
364 | 0 | dci.fde_instr_start = addr; |
365 | 15 | dci.fde_instr_end = fde_end_addr; |
366 | | |
367 | 15 | memcpy (pi->unwind_info, &dci, sizeof (dci)); |
368 | 15 | } |
369 | 15 | return 0; |
370 | 15 | } |