1 | #ifndef DWARF_I_H |
2 | #define DWARF_I_H |
3 | |
4 | /* This file contains definitions that cannot be used in code outside |
5 | of libunwind. In particular, most inline functions are here |
6 | because otherwise they'd generate unresolved references when the |
7 | files are compiled with inlining disabled. */ |
8 | |
9 | #include "dwarf.h" |
10 | #include "libunwind_i.h" |
11 | |
12 | /* Unless we are told otherwise, assume that a "machine address" is |
13 | the size of an unw_word_t. */ |
14 | #ifndef dwarf_addr_size |
15 | # define dwarf_addr_size(as) (sizeof (unw_word_t)) |
16 | #endif |
17 | |
18 | #ifndef dwarf_to_unw_regnum |
19 | # define dwarf_to_unw_regnum_map UNW_OBJ (dwarf_to_unw_regnum_map) |
20 | extern const uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH]; |
21 | /* REG is evaluated multiple times; it better be side-effects free! */ |
22 | # define dwarf_to_unw_regnum(reg) \ |
23 | (((reg) < DWARF_REGNUM_MAP_LENGTH) ? dwarf_to_unw_regnum_map[reg] : 0) |
24 | #endif |
25 | |
26 | #ifdef UNW_LOCAL_ONLY |
27 | |
28 | /* In the local-only case, we can let the compiler directly access |
29 | memory and don't need to worry about differing byte-order. */ |
30 | |
31 | typedef union __attribute__ ((packed)) |
32 | { |
33 | int8_t s8; |
34 | int16_t s16; |
35 | int32_t s32; |
36 | int64_t s64; |
37 | uint8_t u8; |
38 | uint16_t u16; |
39 | uint32_t u32; |
40 | uint64_t u64; |
41 | void *ptr; |
42 | } |
43 | dwarf_misaligned_value_t; |
44 | |
45 | static inline int |
46 | dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
47 | int8_t *val, void *arg) |
48 | { |
49 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
50 | |
51 | *val = mvp->s8; |
52 | *addr += sizeof (mvp->s8); |
53 | return 0; |
54 | } |
55 | |
56 | static inline int |
57 | dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
58 | int16_t *val, void *arg) |
59 | { |
60 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
61 | |
62 | *val = mvp->s16; |
63 | *addr += sizeof (mvp->s16); |
64 | return 0; |
65 | } |
66 | |
67 | static inline int |
68 | dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
69 | int32_t *val, void *arg) |
70 | { |
71 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
72 | |
73 | *val = mvp->s32; |
74 | *addr += sizeof (mvp->s32); |
75 | return 0; |
76 | } |
77 | |
78 | static inline int |
79 | dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
80 | int64_t *val, void *arg) |
81 | { |
82 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
83 | |
84 | *val = mvp->s64; |
85 | *addr += sizeof (mvp->s64); |
86 | return 0; |
87 | } |
88 | |
89 | static inline int |
90 | dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
91 | uint8_t *val, void *arg) |
92 | { |
93 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
94 | |
95 | *val = mvp->u8; |
96 | *addr += sizeof (mvp->u8); |
97 | return 0; |
98 | } |
99 | |
100 | static inline int |
101 | dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
102 | uint16_t *val, void *arg) |
103 | { |
104 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
105 | |
106 | *val = mvp->u16; |
107 | *addr += sizeof (mvp->u16); |
108 | return 0; |
109 | } |
110 | |
111 | static inline int |
112 | dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
113 | uint32_t *val, void *arg) |
114 | { |
115 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
116 | |
117 | *val = mvp->u32; |
118 | *addr += sizeof (mvp->u32); |
119 | return 0; |
120 | } |
121 | |
122 | static inline int |
123 | dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
124 | uint64_t *val, void *arg) |
125 | { |
126 | dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr; |
127 | |
128 | *val = mvp->u64; |
129 | *addr += sizeof (mvp->u64); |
130 | return 0; |
131 | } |
132 | |
133 | #else /* !UNW_LOCAL_ONLY */ |
134 | |
135 | static inline int |
136 | dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
137 | uint8_t *valp, void *arg) |
138 | { |
139 | unw_word_t val, aligned_addr = *addr & -sizeof (unw_word_t); |
140 | unw_word_t off = *addr - aligned_addr; |
141 | int ret; |
142 | |
143 | *addr += 1; |
144 | ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg); |
145 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
146 | val >>= 8*off; |
147 | #else |
148 | val >>= 8*(sizeof (unw_word_t) - 1 - off); |
149 | #endif |
150 | *valp = (uint8_t) val; |
151 | return ret; |
152 | } |
153 | |
154 | static inline int |
155 | dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
156 | uint16_t *val, void *arg) |
157 | { |
158 | uint8_t v0, v1; |
159 | int ret; |
160 | |
161 | if ((ret = dwarf_readu8 (as, a, addr, &v0, arg)) < 0 |
162 | || (ret = dwarf_readu8 (as, a, addr, &v1, arg)) < 0) |
163 | return ret; |
164 | |
165 | if (tdep_big_endian (as)) |
166 | *val = (uint16_t) v0 << 8 | v1; |
167 | else |
168 | *val = (uint16_t) v1 << 8 | v0; |
169 | return 0; |
170 | } |
171 | |
172 | static inline int |
173 | dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
174 | uint32_t *val, void *arg) |
175 | { |
176 | uint16_t v0, v1; |
177 | int ret; |
178 | |
179 | if ((ret = dwarf_readu16 (as, a, addr, &v0, arg)) < 0 |
180 | || (ret = dwarf_readu16 (as, a, addr, &v1, arg)) < 0) |
181 | return ret; |
182 | |
183 | if (tdep_big_endian (as)) |
184 | *val = (uint32_t) v0 << 16 | v1; |
185 | else |
186 | *val = (uint32_t) v1 << 16 | v0; |
187 | return 0; |
188 | } |
189 | |
190 | static inline int |
191 | dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
192 | uint64_t *val, void *arg) |
193 | { |
194 | uint32_t v0, v1; |
195 | int ret; |
196 | |
197 | if ((ret = dwarf_readu32 (as, a, addr, &v0, arg)) < 0 |
198 | || (ret = dwarf_readu32 (as, a, addr, &v1, arg)) < 0) |
199 | return ret; |
200 | |
201 | if (tdep_big_endian (as)) |
202 | *val = (uint64_t) v0 << 32 | v1; |
203 | else |
204 | *val = (uint64_t) v1 << 32 | v0; |
205 | return 0; |
206 | } |
207 | |
208 | static inline int |
209 | dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
210 | int8_t *val, void *arg) |
211 | { |
212 | uint8_t uval; |
213 | int ret; |
214 | |
215 | if ((ret = dwarf_readu8 (as, a, addr, &uval, arg)) < 0) |
216 | return ret; |
217 | *val = (int8_t) uval; |
218 | return 0; |
219 | } |
220 | |
221 | static inline int |
222 | dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
223 | int16_t *val, void *arg) |
224 | { |
225 | uint16_t uval; |
226 | int ret; |
227 | |
228 | if ((ret = dwarf_readu16 (as, a, addr, &uval, arg)) < 0) |
229 | return ret; |
230 | *val = (int16_t) uval; |
231 | return 0; |
232 | } |
233 | |
234 | static inline int |
235 | dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
236 | int32_t *val, void *arg) |
237 | { |
238 | uint32_t uval; |
239 | int ret; |
240 | |
241 | if ((ret = dwarf_readu32 (as, a, addr, &uval, arg)) < 0) |
242 | return ret; |
243 | *val = (int32_t) uval; |
244 | return 0; |
245 | } |
246 | |
247 | static inline int |
248 | dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
249 | int64_t *val, void *arg) |
250 | { |
251 | uint64_t uval; |
252 | int ret; |
253 | |
254 | if ((ret = dwarf_readu64 (as, a, addr, &uval, arg)) < 0) |
255 | return ret; |
256 | *val = (int64_t) uval; |
257 | return 0; |
258 | } |
259 | |
260 | #endif /* !UNW_LOCAL_ONLY */ |
261 | |
262 | static inline int |
263 | dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
264 | unw_word_t *val, void *arg) |
265 | { |
266 | uint32_t u32; |
267 | uint64_t u64; |
268 | int ret; |
269 | |
270 | switch (dwarf_addr_size (as)) |
271 | { |
272 | case 4: |
273 | ret = dwarf_readu32 (as, a, addr, &u32, arg); |
274 | if (ret < 0) |
275 | return ret; |
276 | *val = u32; |
277 | return ret; |
278 | |
279 | case 8: |
280 | ret = dwarf_readu64 (as, a, addr, &u64, arg); |
281 | if (ret < 0) |
282 | return ret; |
283 | *val = u64; |
284 | return ret; |
285 | |
286 | default: |
287 | abort (); |
288 | } |
289 | } |
290 | |
291 | /* Read an unsigned "little-endian base 128" value. See Chapter 7.6 |
292 | of DWARF spec v3. */ |
293 | |
294 | static inline int |
295 | dwarf_read_uleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
296 | unw_word_t *valp, void *arg) |
297 | { |
298 | unw_word_t val = 0, shift = 0; |
299 | unsigned char byte; |
300 | int ret; |
301 | |
302 | do |
303 | { |
304 | if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) |
305 | return ret; |
306 | |
307 | val |= ((unw_word_t) byte & 0x7f) << shift; |
308 | shift += 7; |
309 | } |
310 | while (byte & 0x80); |
311 | |
312 | *valp = val; |
313 | return 0; |
314 | } |
315 | |
316 | /* Read a signed "little-endian base 128" value. See Chapter 7.6 of |
317 | DWARF spec v3. */ |
318 | |
319 | static inline int |
320 | dwarf_read_sleb128 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, |
321 | unw_word_t *valp, void *arg) |
322 | { |
323 | unw_word_t val = 0, shift = 0; |
324 | unsigned char byte; |
325 | int ret; |
326 | |
327 | do |
328 | { |
329 | if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0) |
330 | return ret; |
331 | |
332 | val |= ((unw_word_t) byte & 0x7f) << shift; |
333 | shift += 7; |
334 | } |
335 | while (byte & 0x80); |
336 | |
337 | if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0) |
338 | /* sign-extend negative value */ |
339 | val |= ((unw_word_t) -1) << shift; |
340 | |
341 | *valp = val; |
342 | return 0; |
343 | } |
344 | |
345 | static ALWAYS_INLINE int |
346 | dwarf_read_encoded_pointer_inlined (unw_addr_space_t as, unw_accessors_t *a, |
347 | unw_word_t *addr, unsigned char encoding, |
348 | const unw_proc_info_t *pi, |
349 | unw_word_t *valp, void *arg) |
350 | { |
351 | unw_word_t val, initial_addr = *addr; |
352 | uint16_t uval16; |
353 | uint32_t uval32; |
354 | uint64_t uval64; |
355 | int16_t sval16 = 0; |
356 | int32_t sval32 = 0; |
357 | int64_t sval64 = 0; |
358 | int ret; |
359 | |
360 | /* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal |
361 | format/application encoding. Handle them first. */ |
362 | if (encoding == DW_EH_PE_omit) |
363 | { |
364 | *valp = 0; |
365 | return 0; |
366 | } |
367 | else if (encoding == DW_EH_PE_aligned) |
368 | { |
369 | int size = dwarf_addr_size (as); |
370 | *addr = (initial_addr + size - 1) & -size; |
371 | return dwarf_readw (as, a, addr, valp, arg); |
372 | } |
373 | |
374 | switch (encoding & DW_EH_PE_FORMAT_MASK) |
375 | { |
376 | case DW_EH_PE_ptr: |
377 | if ((ret = dwarf_readw (as, a, addr, &val, arg)) < 0) |
378 | return ret; |
379 | break; |
380 | |
381 | case DW_EH_PE_uleb128: |
382 | if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) |
383 | return ret; |
384 | break; |
385 | |
386 | case DW_EH_PE_udata2: |
387 | if ((ret = dwarf_readu16 (as, a, addr, &uval16, arg)) < 0) |
388 | return ret; |
389 | val = uval16; |
390 | break; |
391 | |
392 | case DW_EH_PE_udata4: |
393 | if ((ret = dwarf_readu32 (as, a, addr, &uval32, arg)) < 0) |
394 | return ret; |
395 | val = uval32; |
396 | break; |
397 | |
398 | case DW_EH_PE_udata8: |
399 | if ((ret = dwarf_readu64 (as, a, addr, &uval64, arg)) < 0) |
400 | return ret; |
401 | val = uval64; |
402 | break; |
403 | |
404 | case DW_EH_PE_sleb128: |
405 | if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0) |
406 | return ret; |
407 | break; |
408 | |
409 | case DW_EH_PE_sdata2: |
410 | if ((ret = dwarf_reads16 (as, a, addr, &sval16, arg)) < 0) |
411 | return ret; |
412 | val = sval16; |
413 | break; |
414 | |
415 | case DW_EH_PE_sdata4: |
416 | if ((ret = dwarf_reads32 (as, a, addr, &sval32, arg)) < 0) |
417 | return ret; |
418 | val = sval32; |
419 | break; |
420 | |
421 | case DW_EH_PE_sdata8: |
422 | if ((ret = dwarf_reads64 (as, a, addr, &sval64, arg)) < 0) |
423 | return ret; |
424 | val = sval64; |
425 | break; |
426 | |
427 | default: |
428 | Debug (1, "unexpected encoding format 0x%x\n" , |
429 | encoding & DW_EH_PE_FORMAT_MASK); |
430 | return -UNW_EINVAL; |
431 | } |
432 | |
433 | if (val == 0) |
434 | { |
435 | /* 0 is a special value and always absolute. */ |
436 | *valp = 0; |
437 | return 0; |
438 | } |
439 | |
440 | switch (encoding & DW_EH_PE_APPL_MASK) |
441 | { |
442 | case DW_EH_PE_absptr: |
443 | break; |
444 | |
445 | case DW_EH_PE_pcrel: |
446 | val += initial_addr; |
447 | break; |
448 | |
449 | case DW_EH_PE_datarel: |
450 | /* XXX For now, assume that data-relative addresses are relative |
451 | to the global pointer. */ |
452 | val += pi->gp; |
453 | break; |
454 | |
455 | case DW_EH_PE_funcrel: |
456 | val += pi->start_ip; |
457 | break; |
458 | |
459 | case DW_EH_PE_textrel: |
460 | /* XXX For now we don't support text-rel values. If there is a |
461 | platform which needs this, we probably would have to add a |
462 | "segbase" member to unw_proc_info_t. */ |
463 | default: |
464 | Debug (1, "unexpected application type 0x%x\n" , |
465 | encoding & DW_EH_PE_APPL_MASK); |
466 | return -UNW_EINVAL; |
467 | } |
468 | |
469 | /* Trim off any extra bits. Assume that sign extension isn't |
470 | required; the only place it is needed is MIPS kernel space |
471 | addresses. */ |
472 | if (sizeof (val) > dwarf_addr_size (as)) |
473 | { |
474 | assert (dwarf_addr_size (as) == 4); |
475 | val = (uint32_t) val; |
476 | } |
477 | |
478 | if (encoding & DW_EH_PE_indirect) |
479 | { |
480 | unw_word_t indirect_addr = val; |
481 | |
482 | if ((ret = dwarf_readw (as, a, &indirect_addr, &val, arg)) < 0) |
483 | return ret; |
484 | } |
485 | |
486 | *valp = val; |
487 | return 0; |
488 | } |
489 | |
490 | #endif /* DWARF_I_H */ |
491 | |