Home | History | Annotate | Download | only in include
      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
     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
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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