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