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