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 #define UPDATE_VERSION 3
28 static inline int
is_cie_id(unw_word_t val,int is_debug_frame)29 is_cie_id (unw_word_t val, int is_debug_frame)
30 {
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 if (is_debug_frame)
35 return (val == (uint32_t)(-1) || val == (uint64_t)(-1));
36 else
37 return (val == 0);
38 }
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
parse_cie(unw_addr_space_t as,unw_accessors_t * a,unw_word_t addr,const unw_proc_info_t * pi,struct dwarf_cie_info * dci,int is_debug_frame,void * arg)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 {
50 uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
51 uint8_t address_size, segment_size;
52 unw_word_t len, cie_end_addr, aug_size;
53 uint32_t u32val;
54 uint64_t u64val;
55 size_t i;
56 int ret;
57 # define STR2(x) #x
58 # 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 switch (dwarf_addr_size (as))
66 {
67 case 4: fde_encoding = DW_EH_PE_udata4; break;
68 case 8: fde_encoding = DW_EH_PE_udata8; break;
69 default: fde_encoding = DW_EH_PE_omit; break;
70 }
71
72 dci->lsda_encoding = DW_EH_PE_omit;
73 dci->handler = 0;
74
75 if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
76 return ret;
77
78 if (u32val != 0xffffffff)
79 {
80 /* the CIE is in the 32-bit DWARF format */
81 uint32_t cie_id;
82 /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
83 const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0;
84
85 len = u32val;
86 cie_end_addr = addr + len;
87 if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0)
88 return ret;
89 if (cie_id != expected_id)
90 {
91 Debug (1, "Unexpected CIE id %x\n", cie_id);
92 return -UNW_EINVAL;
93 }
94 }
95 else
96 {
97 /* the CIE is in the 64-bit DWARF format */
98 uint64_t cie_id;
99 /* DWARF says CIE id should be 0xffffffffffffffff, but in
100 .eh_frame, it's 0 */
101 const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull : 0;
102
103 if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
104 return ret;
105 len = u64val;
106 cie_end_addr = addr + len;
107 if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0)
108 return ret;
109 if (cie_id != expected_id)
110 {
111 Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
112 return -UNW_EINVAL;
113 }
114 }
115 dci->cie_instr_end = cie_end_addr;
116
117 if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0)
118 return ret;
119
120 /* GCC emits version 1??? */
121 if (version != 1 && (version < DWARF_CIE_VERSION || version > DWARF_CIE_VERSION_MAX))
122 {
123 Debug (1, "Got CIE version %u, expected version 1 or between "
124 STR (DWARF_CIE_VERSION) " and " STR (DWARF_CIE_VERSION_MAX) "\n", version);
125 return -UNW_EBADVERSION;
126 }
127
128 /* read and parse the augmentation string: */
129 memset (augstr, 0, sizeof (augstr));
130 for (i = 0;;)
131 {
132 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
133 return ret;
134
135 if (!ch)
136 break; /* end of augmentation string */
137
138 if (i < sizeof (augstr) - 1)
139 augstr[i++] = ch;
140 }
141
142 if (version > UPDATE_VERSION)
143 {
144 if ((ret = dwarf_readu8(as, a, &addr, &address_size, arg)) < 0)
145 return ret;
146
147 if ((ret = dwarf_readu8(as, a, &addr, &segment_size, arg)) < 0)
148 return ret;
149 }
150
151 if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0
152 || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0)
153 return ret;
154
155 /* Read the return-address column either as a u8 or as a uleb128. */
156 if (version == 1)
157 {
158 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
159 return ret;
160 dci->ret_addr_column = ch;
161 }
162 else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column,
163 arg)) < 0)
164 return ret;
165
166 i = 0;
167 if (augstr[0] == 'z')
168 {
169 dci->sized_augmentation = 1;
170 if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
171 return ret;
172 i++;
173 }
174
175 for (; i < sizeof (augstr) && augstr[i]; ++i)
176 switch (augstr[i])
177 {
178 case 'L':
179 /* read the LSDA pointer-encoding format. */
180 if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
181 return ret;
182 dci->lsda_encoding = ch;
183 break;
184
185 case 'R':
186 /* read the FDE pointer-encoding format. */
187 if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0)
188 return ret;
189 break;
190
191 case 'P':
192 /* read the personality-routine pointer-encoding format. */
193 if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0)
194 return ret;
195 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding,
196 pi, &dci->handler, arg)) < 0)
197 return ret;
198 break;
199
200 case 'S':
201 /* This is a signal frame. */
202 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 dci->have_abi_marker = 1;
207 break;
208
209 default:
210 Debug (1, "Unexpected augmentation string `%s'\n", augstr);
211 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 goto done;
215 else
216 return -UNW_EINVAL;
217 }
218 done:
219 dci->fde_encoding = fde_encoding;
220 dci->cie_instr_start = addr;
221 Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
222 augstr, (long) dci->handler);
223 return 0;
224 }
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
dwarf_extract_proc_info_from_fde(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addrp,unw_proc_info_t * pi,unw_word_t base,int need_unwind_info,int is_debug_frame,void * arg)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 {
238 unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
239 unw_word_t start_ip, ip_range, aug_size, addr = *addrp;
240 int ret, ip_range_encoding;
241 struct dwarf_cie_info dci;
242 uint64_t u64val;
243 uint32_t u32val;
244
245 Debug (12, "FDE @ 0x%lx\n", (long) addr);
246
247 memset (&dci, 0, sizeof (dci));
248
249 if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
250 return ret;
251
252 if (u32val != 0xffffffff)
253 {
254 int32_t cie_offset = 0;
255
256 /* In some configurations, an FDE with a 0 length indicates the
257 end of the FDE-table. */
258 if (u32val == 0)
259 return -UNW_ENOINFO;
260
261 /* the FDE is in the 32-bit DWARF format */
262
263 *addrp = fde_end_addr = addr + u32val;
264 cie_offset_addr = addr;
265
266 if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0)
267 return ret;
268
269 if (is_cie_id (cie_offset, is_debug_frame))
270 /* ignore CIEs (happens during linear searches) */
271 return 0;
272
273 if (is_debug_frame)
274 cie_addr = base + cie_offset;
275 else
276 /* DWARF says that the CIE_pointer in the FDE is a
277 .debug_frame-relative offset, but the GCC-generated .eh_frame
278 sections instead store a "pcrelative" offset, which is just
279 as fine as it's self-contained. */
280 cie_addr = cie_offset_addr - cie_offset;
281 }
282 else
283 {
284 int64_t cie_offset = 0;
285
286 /* the FDE is in the 64-bit DWARF format */
287
288 if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
289 return ret;
290
291 *addrp = fde_end_addr = addr + u64val;
292 cie_offset_addr = addr;
293
294 if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0)
295 return ret;
296
297 if (is_cie_id (cie_offset, is_debug_frame))
298 /* ignore CIEs (happens during linear searches) */
299 return 0;
300
301 if (is_debug_frame)
302 cie_addr = base + cie_offset;
303 else
304 /* DWARF says that the CIE_pointer in the FDE is a
305 .debug_frame-relative offset, but the GCC-generated .eh_frame
306 sections instead store a "pcrelative" offset, which is just
307 as fine as it's self-contained. */
308 cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
309 }
310
311 Debug (15, "looking for CIE at address %lx\n", (long) cie_addr);
312
313 if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0)
314 return ret;
315
316 /* IP-range has same encoding as FDE pointers, except that it's
317 always an absolute value: */
318 ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
319
320 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding,
321 pi, &start_ip, arg)) < 0
322 || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding,
323 pi, &ip_range, arg)) < 0)
324 return ret;
325 pi->start_ip = start_ip;
326 pi->end_ip = start_ip + ip_range;
327 pi->handler = dci.handler;
328
329 if (dci.sized_augmentation)
330 {
331 if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
332 return ret;
333 aug_end_addr = addr + aug_size;
334 }
335
336 if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding,
337 pi, &pi->lsda, arg)) < 0)
338 return ret;
339
340 Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n",
341 (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda);
342
343 if (need_unwind_info)
344 {
345 pi->format = UNW_INFO_FORMAT_TABLE;
346 pi->unwind_info_size = sizeof (dci);
347 pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool);
348 if (!pi->unwind_info)
349 return -UNW_ENOMEM;
350
351 if (dci.have_abi_marker)
352 {
353 if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0
354 || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0)
355 return ret;
356 Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n",
357 dci.abi, dci.tag);
358 }
359
360 if (dci.sized_augmentation)
361 dci.fde_instr_start = aug_end_addr;
362 else
363 dci.fde_instr_start = addr;
364 dci.fde_instr_end = fde_end_addr;
365
366 memcpy (pi->unwind_info, &dci, sizeof (dci));
367 }
368 return 0;
369 }
370