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
dwarf_reads8(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int8_t * val,void * arg)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
dwarf_reads16(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int16_t * val,void * arg)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
dwarf_reads32(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int32_t * val,void * arg)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
dwarf_reads64(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int64_t * val,void * arg)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
dwarf_readu8(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint8_t * val,void * arg)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
dwarf_readu16(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint16_t * val,void * arg)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
dwarf_readu32(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint32_t * val,void * arg)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
dwarf_readu64(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint64_t * val,void * arg)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
dwarf_readu8(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint8_t * valp,void * arg)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 UNW_BYTE_ORDER == UNW_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
dwarf_readu16(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint16_t * val,void * arg)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
dwarf_readu32(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint32_t * val,void * arg)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
dwarf_readu64(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,uint64_t * val,void * arg)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
dwarf_reads8(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int8_t * val,void * arg)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
dwarf_reads16(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int16_t * val,void * arg)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
dwarf_reads32(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int32_t * val,void * arg)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
dwarf_reads64(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,int64_t * val,void * arg)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
dwarf_readw(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,unw_word_t * val,void * arg)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
dwarf_read_uleb128(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,unw_word_t * valp,void * arg)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
dwarf_read_sleb128(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,unw_word_t * valp,void * arg)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
dwarf_read_encoded_pointer_inlined(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,unsigned char encoding,const unw_proc_info_t * pi,unw_word_t * valp,void * arg)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