• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 __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
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;
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