mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-18 05:47:39 +01:00
343 lines
7.4 KiB
C
343 lines
7.4 KiB
C
#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 "tdep.h"
|
|
|
|
#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];
|
|
|
|
static inline unw_regnum_t
|
|
dwarf_to_unw_regnum (unw_word_t regnum)
|
|
{
|
|
if (regnum <= DWARF_REGNUM_MAP_LENGTH)
|
|
return dwarf_to_unw_regnum_map[regnum];
|
|
return 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. */
|
|
|
|
typedef union
|
|
{
|
|
int8_t s8;
|
|
int16_t s16;
|
|
int32_t s32;
|
|
int64_t s64;
|
|
uint8_t u8;
|
|
uint16_t u16;
|
|
uint32_t u32;
|
|
uint64_t u64;
|
|
unw_word_t w;
|
|
void *ptr;
|
|
}
|
|
dwarf_misaligned_value_t __attribute__ ((packed));
|
|
|
|
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 *) *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 *) *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 *) *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 *) *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 *) *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 *) *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 *) *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 *) *addr;
|
|
|
|
*val = mvp->u64;
|
|
*addr += sizeof (mvp->u64);
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
|
|
unw_word_t *val, void *arg)
|
|
{
|
|
dwarf_misaligned_value_t *mvp = (void *) *addr;
|
|
|
|
*val = mvp->w;
|
|
*addr += sizeof (mvp->w);
|
|
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;
|
|
}
|
|
|
|
static inline int
|
|
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
|
|
unw_word_t *val, void *arg)
|
|
{
|
|
switch (sizeof (unw_word_t))
|
|
{
|
|
case 4:
|
|
return dwarf_readu32 (as, a, addr, (uint32_t *) val, arg);
|
|
|
|
case 8:
|
|
return dwarf_readu64 (as, a, addr, (uint64_t *) val, arg);
|
|
|
|
default:
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
#endif /* !UNW_LOCAL_ONLY */
|
|
|
|
/* 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;
|
|
}
|
|
|
|
#endif /* DWARF_I_H */
|