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)
20extern 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
31typedef 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  }
43dwarf_misaligned_value_t;
44
45static inline int
46dwarf_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
56static inline int
57dwarf_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
67static inline int
68dwarf_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
78static inline int
79dwarf_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
89static inline int
90dwarf_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
100static inline int
101dwarf_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
111static inline int
112dwarf_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
122static inline int
123dwarf_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
135static inline int
136dwarf_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
154static inline int
155dwarf_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
172static inline int
173dwarf_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
190static inline int
191dwarf_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
208static inline int
209dwarf_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
221static inline int
222dwarf_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
234static inline int
235dwarf_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
247static inline int
248dwarf_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
262static inline int
263dwarf_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
294static inline int
295dwarf_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
319static inline int
320dwarf_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
345static ALWAYS_INLINE int
346dwarf_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;
356  int32_t sval32;
357  int64_t sval64;
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