123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- #ifndef DWARF_I_H
- #define DWARF_I_H
- /* This file contains definitions that cannot be used in code outside
- of libunwind. In particular, most inline functions are here
- because otherwise they'd generate unresolved references when the
- files are compiled with inlining disabled. */
- #include "dwarf.h"
- #include "libunwind_i.h"
- /* Unless we are told otherwise, assume that a "machine address" is
- the size of an unw_word_t. */
- #ifndef dwarf_addr_size
- # define dwarf_addr_size(as) (sizeof (unw_word_t))
- #endif
- #define dwarf_to_unw_regnum_map UNW_OBJ (dwarf_to_unw_regnum_map)
- extern uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH];
- /* REG is evaluated multiple times; it better be side-effects free! */
- #define dwarf_to_unw_regnum(reg) \
- (((reg) <= DWARF_REGNUM_MAP_LENGTH) ? dwarf_to_unw_regnum_map[reg] : 0)
- #ifdef UNW_LOCAL_ONLY
- /* In the local-only case, we can let the compiler directly access
- memory and don't need to worry about differing byte-order. */
- union __attribute__ ((packed)) _dwarf_misaligned_value_t
- {
- int8_t s8;
- int16_t s16;
- int32_t s32;
- int64_t s64;
- uint8_t u8;
- uint16_t u16;
- uint32_t u32;
- uint64_t u64;
- void *ptr;
- };
- typedef union _dwarf_misaligned_value_t dwarf_misaligned_value_t;
- static inline int
- dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int8_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->s8;
- *addr += sizeof (mvp->s8);
- return 0;
- }
- static inline int
- dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int16_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->s16;
- *addr += sizeof (mvp->s16);
- return 0;
- }
- static inline int
- dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int32_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->s32;
- *addr += sizeof (mvp->s32);
- return 0;
- }
- static inline int
- dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int64_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->s64;
- *addr += sizeof (mvp->s64);
- return 0;
- }
- static inline int
- dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint8_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->u8;
- *addr += sizeof (mvp->u8);
- return 0;
- }
- static inline int
- dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint16_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->u16;
- *addr += sizeof (mvp->u16);
- return 0;
- }
- static inline int
- dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint32_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->u32;
- *addr += sizeof (mvp->u32);
- return 0;
- }
- static inline int
- dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint64_t *val, void *arg)
- {
- dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
- *val = mvp->u64;
- *addr += sizeof (mvp->u64);
- return 0;
- }
- #else /* !UNW_LOCAL_ONLY */
- static inline int
- dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint8_t *valp, void *arg)
- {
- unw_word_t val, aligned_addr = *addr & -sizeof (unw_word_t);
- unw_word_t off = *addr - aligned_addr;
- int ret;
- *addr += 1;
- ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg);
- #if __BYTE_ORDER == __LITTLE_ENDIAN
- val >>= 8*off;
- #else
- val >>= 8*(sizeof (unw_word_t) - 1 - off);
- #endif
- *valp = (uint8_t) val;
- return ret;
- }
- static inline int
- dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint16_t *val, void *arg)
- {
- uint8_t v0, v1;
- int ret;
- if ((ret = dwarf_readu8 (as, a, addr, &v0, arg)) < 0
- || (ret = dwarf_readu8 (as, a, addr, &v1, arg)) < 0)
- return ret;
- if (tdep_big_endian (as))
- *val = (uint16_t) v0 << 8 | v1;
- else
- *val = (uint16_t) v1 << 8 | v0;
- return 0;
- }
- static inline int
- dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint32_t *val, void *arg)
- {
- uint16_t v0, v1;
- int ret;
- if ((ret = dwarf_readu16 (as, a, addr, &v0, arg)) < 0
- || (ret = dwarf_readu16 (as, a, addr, &v1, arg)) < 0)
- return ret;
- if (tdep_big_endian (as))
- *val = (uint32_t) v0 << 16 | v1;
- else
- *val = (uint32_t) v1 << 16 | v0;
- return 0;
- }
- static inline int
- dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- uint64_t *val, void *arg)
- {
- uint32_t v0, v1;
- int ret;
- if ((ret = dwarf_readu32 (as, a, addr, &v0, arg)) < 0
- || (ret = dwarf_readu32 (as, a, addr, &v1, arg)) < 0)
- return ret;
- if (tdep_big_endian (as))
- *val = (uint64_t) v0 << 32 | v1;
- else
- *val = (uint64_t) v1 << 32 | v0;
- return 0;
- }
- static inline int
- dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int8_t *val, void *arg)
- {
- uint8_t uval;
- int ret;
- if ((ret = dwarf_readu8 (as, a, addr, &uval, arg)) < 0)
- return ret;
- *val = (int8_t) uval;
- return 0;
- }
- static inline int
- dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int16_t *val, void *arg)
- {
- uint16_t uval;
- int ret;
- if ((ret = dwarf_readu16 (as, a, addr, &uval, arg)) < 0)
- return ret;
- *val = (int16_t) uval;
- return 0;
- }
- static inline int
- dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int32_t *val, void *arg)
- {
- uint32_t uval;
- int ret;
- if ((ret = dwarf_readu32 (as, a, addr, &uval, arg)) < 0)
- return ret;
- *val = (int32_t) uval;
- return 0;
- }
- static inline int
- dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- int64_t *val, void *arg)
- {
- uint64_t uval;
- int ret;
- if ((ret = dwarf_readu64 (as, a, addr, &uval, arg)) < 0)
- return ret;
- *val = (int64_t) uval;
- return 0;
- }
- #endif /* !UNW_LOCAL_ONLY */
- static inline int
- dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
- unw_word_t *val, void *arg)
- {
- uint32_t u32;
- uint64_t u64;
- int ret;
- switch (dwarf_addr_size (as))
- {
- case 4:
- ret = dwarf_readu32 (as, a, addr, &u32, arg);
- if (ret < 0)
- return ret;
- *val = u32;
- return ret;
- case 8:
- ret = dwarf_readu64 (as, a, addr, &u64, arg);
- if (ret < 0)
- return ret;
- *val = u64;
- return ret;
- default:
- abort ();
- }
- }
- /* Read an unsigned "little-endian base 128" value. See Chapter 7.6
- of DWARF spec v3. */
- 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)
- {
- unw_word_t val = 0, shift = 0;
- unsigned char byte;
- int ret;
- do
- {
- if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0)
- return ret;
- val |= ((unw_word_t) byte & 0x7f) << shift;
- shift += 7;
- }
- while (byte & 0x80);
- *valp = val;
- return 0;
- }
- /* Read a signed "little-endian base 128" value. See Chapter 7.6 of
- DWARF spec v3. */
- 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)
- {
- unw_word_t val = 0, shift = 0;
- unsigned char byte;
- int ret;
- do
- {
- if ((ret = dwarf_readu8 (as, a, addr, &byte, arg)) < 0)
- return ret;
- val |= ((unw_word_t) byte & 0x7f) << shift;
- shift += 7;
- }
- while (byte & 0x80);
- if (shift < 8 * sizeof (unw_word_t) && (byte & 0x40) != 0)
- /* sign-extend negative value */
- val |= ((unw_word_t) -1) << shift;
- *valp = val;
- return 0;
- }
- 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)
- {
- unw_word_t val, initial_addr = *addr;
- uint16_t uval16;
- uint32_t uval32;
- uint64_t uval64;
- int16_t sval16;
- int32_t sval32;
- int64_t sval64;
- int ret;
- /* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal
- format/application encoding. Handle them first. */
- if (encoding == DW_EH_PE_omit)
- {
- *valp = 0;
- return 0;
- }
- else if (encoding == DW_EH_PE_aligned)
- {
- int size = dwarf_addr_size (as);
- *addr = (initial_addr + size - 1) & -size;
- return dwarf_readw (as, a, addr, valp, arg);
- }
- switch (encoding & DW_EH_PE_FORMAT_MASK)
- {
- case DW_EH_PE_ptr:
- if ((ret = dwarf_readw (as, a, addr, &val, arg)) < 0)
- return ret;
- break;
- case DW_EH_PE_uleb128:
- if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
- return ret;
- break;
- case DW_EH_PE_udata2:
- if ((ret = dwarf_readu16 (as, a, addr, &uval16, arg)) < 0)
- return ret;
- val = uval16;
- break;
- case DW_EH_PE_udata4:
- if ((ret = dwarf_readu32 (as, a, addr, &uval32, arg)) < 0)
- return ret;
- val = uval32;
- break;
- case DW_EH_PE_udata8:
- if ((ret = dwarf_readu64 (as, a, addr, &uval64, arg)) < 0)
- return ret;
- val = uval64;
- break;
- case DW_EH_PE_sleb128:
- if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
- return ret;
- break;
- case DW_EH_PE_sdata2:
- if ((ret = dwarf_reads16 (as, a, addr, &sval16, arg)) < 0)
- return ret;
- val = sval16;
- break;
- case DW_EH_PE_sdata4:
- if ((ret = dwarf_reads32 (as, a, addr, &sval32, arg)) < 0)
- return ret;
- val = sval32;
- break;
- case DW_EH_PE_sdata8:
- if ((ret = dwarf_reads64 (as, a, addr, &sval64, arg)) < 0)
- return ret;
- val = sval64;
- break;
- default:
- Debug (1, "unexpected encoding format 0x%x\n",
- encoding & DW_EH_PE_FORMAT_MASK);
- return -UNW_EINVAL;
- }
- if (val == 0)
- {
- /* 0 is a special value and always absolute. */
- *valp = 0;
- return 0;
- }
- switch (encoding & DW_EH_PE_APPL_MASK)
- {
- case DW_EH_PE_absptr:
- break;
- case DW_EH_PE_pcrel:
- val += initial_addr;
- break;
- case DW_EH_PE_datarel:
- /* XXX For now, assume that data-relative addresses are relative
- to the global pointer. */
- val += pi->gp;
- break;
- case DW_EH_PE_funcrel:
- val += pi->start_ip;
- break;
- case DW_EH_PE_textrel:
- /* XXX For now we don't support text-rel values. If there is a
- platform which needs this, we probably would have to add a
- "segbase" member to unw_proc_info_t. */
- default:
- Debug (1, "unexpected application type 0x%x\n",
- encoding & DW_EH_PE_APPL_MASK);
- return -UNW_EINVAL;
- }
- /* Trim off any extra bits. Assume that sign extension isn't
- required; the only place it is needed is MIPS kernel space
- addresses. */
- if (sizeof (val) > dwarf_addr_size (as))
- {
- assert (dwarf_addr_size (as) == 4);
- val = (uint32_t) val;
- }
- if (encoding & DW_EH_PE_indirect)
- {
- unw_word_t indirect_addr = val;
- if ((ret = dwarf_readw (as, a, &indirect_addr, &val, arg)) < 0)
- return ret;
- }
- *valp = val;
- return 0;
- }
- #endif /* DWARF_I_H */
|