#ifndef libunwind_i_h
#define libunwind_i_h
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "compiler.h"
#if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD
#define UNWI_DEFAULT_CACHING_POLICY UNW_CACHE_PER_THREAD
#else
#define UNWI_DEFAULT_CACHING_POLICY UNW_CACHE_GLOBAL
#endif
#include <sys/types.h>
#include <assert.h>
#include <libunwind.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#if defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h>
#endif
#if defined(HAVE_ELF_H)
# include <elf.h>
#elif defined(HAVE_SYS_ELF_H)
# include <sys/elf.h>
#else
# error Could not locate <elf.h>
#endif
#if defined(ELFCLASS32)
# define UNW_ELFCLASS32 ELFCLASS32
#else
# define UNW_ELFCLASS32 1
#endif
#if defined(ELFCLASS64)
# define UNW_ELFCLASS64 ELFCLASS64
#else
# define UNW_ELFCLASS64 2
#endif
#if defined(HAVE_ENDIAN_H)
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
#elif defined(HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined(__LITTLE_ENDIAN)
# define UNW_LITTLE_ENDIAN __LITTLE_ENDIAN
#elif defined(_LITTLE_ENDIAN)
# define UNW_LITTLE_ENDIAN _LITTLE_ENDIAN
#elif defined(LITTLE_ENDIAN)
# define UNW_LITTLE_ENDIAN LITTLE_ENDIAN
#else
# define UNW_LITTLE_ENDIAN 1234
#endif
#if defined(__BIG_ENDIAN)
# define UNW_BIG_ENDIAN __BIG_ENDIAN
#elif defined(_BIG_ENDIAN)
# define UNW_BIG_ENDIAN _BIG_ENDIAN
#elif defined(BIG_ENDIAN)
# define UNW_BIG_ENDIAN BIG_ENDIAN
#else
# define UNW_BIG_ENDIAN 4321
#endif
#if defined(__BYTE_ORDER)
# define UNW_BYTE_ORDER __BYTE_ORDER
#elif defined(_BYTE_ORDER)
# define UNW_BYTE_ORDER _BYTE_ORDER
#elif defined(BIG_ENDIAN)
# define UNW_BYTE_ORDER BYTE_ORDER
#else
# if defined(__hpux)
# define UNW_BYTE_ORDER UNW_BIG_ENDIAN
# else
# error Target has unknown byte ordering.
# endif
#endif
static inline int
byte_order_is_valid(int byte_order)
{
return byte_order == UNW_BIG_ENDIAN
|| byte_order == UNW_LITTLE_ENDIAN;
}
static inline int
byte_order_is_big_endian(int byte_order)
{
return byte_order == UNW_BIG_ENDIAN;
}
static inline int
target_is_big_endian(void)
{
return byte_order_is_big_endian(UNW_BYTE_ORDER);
}
#if defined(HAVE__BUILTIN_UNREACHABLE)
# define unreachable() __builtin_unreachable()
#else
# define unreachable() do { } while (1)
#endif
#ifdef DEBUG
# define UNW_DEBUG 1
#else
# undef UNW_DEBUG
#endif
#pragma weak pthread_mutex_init
#pragma weak pthread_mutex_lock
#pragma weak pthread_mutex_unlock
#pragma weak pthread_sigmask
#define mutex_init(l) \
(pthread_mutex_init != NULL ? pthread_mutex_init ((l), NULL) : 0)
#define mutex_lock(l) \
(pthread_mutex_lock != NULL ? pthread_mutex_lock (l) : 0)
#define mutex_unlock(l) \
(pthread_mutex_unlock != NULL ? pthread_mutex_unlock (l) : 0)
#define UNWI_OBJ(fn) UNW_PASTE(UNW_PREFIX,UNW_PASTE(I,fn))
#define UNWI_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_UI,UNW_TARGET),_), fn)
#define unwi_full_mask UNWI_ARCH_OBJ(full_mask)
typedef sigset_t intrmask_t;
extern intrmask_t unwi_full_mask;
static inline void mark_as_used(void *v UNUSED) {
}
#if defined(CONFIG_BLOCK_SIGNALS)
# define SIGPROCMASK(how, new_mask, old_mask) \
(pthread_sigmask != NULL ? pthread_sigmask((how), (new_mask), (old_mask)) \
: sigprocmask((how), (new_mask), (old_mask)))
#else
# define SIGPROCMASK(how, new_mask, old_mask) mark_as_used(old_mask)
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
#define UNW_PTHREAD_MUTEX_INITIALIZER PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
#else
#define UNW_PTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif
#define define_lock(name) \
pthread_mutex_t name = UNW_PTHREAD_MUTEX_INITIALIZER
#define lock_init(l) mutex_init (l)
#define lock_acquire(l,m) \
do { \
SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m)); \
mutex_lock (l); \
} while (0)
#define lock_release(l,m) \
do { \
mutex_unlock (l); \
SIGPROCMASK (SIG_SETMASK, &(m), NULL); \
} while (0)
#define SOS_MEMORY_SIZE 16384
static ALWAYS_INLINE void *
mi_mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
#if defined(SYS_mmap) && !defined(__i386__)
# if defined(__FreeBSD__)
long int ret = __syscall (SYS_mmap, addr, len, prot, flags, fd, offset);
# else
long int ret = syscall (SYS_mmap, addr, len, prot, flags, fd, offset);
# endif
if ((unsigned long int)ret > -4096UL)
return MAP_FAILED;
else
return (void *)ret;
#else
return mmap (addr, len, prot, flags, fd, offset);
#endif
}
static ALWAYS_INLINE int
mi_munmap (void *addr, size_t len)
{
#ifdef SYS_munmap
return syscall (SYS_munmap, addr, len);
#else
return munmap (addr, len);
#endif
}
#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#endif
#define GET_MEMORY(mem, size) \
do { \
mem = mi_mmap (NULL, size, PROT_READ | PROT_WRITE, \
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \
if (mem == MAP_FAILED) \
mem = NULL; \
} while (0)
#define unwi_find_dynamic_proc_info UNWI_OBJ(find_dynamic_proc_info)
#define unwi_extract_dynamic_proc_info UNWI_OBJ(extract_dynamic_proc_info)
#define unwi_put_dynamic_unwind_info UNWI_OBJ(put_dynamic_unwind_info)
#define unwi_dyn_remote_find_proc_info UNWI_OBJ(dyn_remote_find_proc_info)
#define unwi_dyn_remote_put_unwind_info UNWI_OBJ(dyn_remote_put_unwind_info)
#define unwi_dyn_validate_cache UNWI_OBJ(dyn_validate_cache)
extern int unwi_find_dynamic_proc_info (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
extern int unwi_extract_dynamic_proc_info (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
unw_dyn_info_t *di,
int need_unwind_info,
void *arg);
extern void unwi_put_dynamic_unwind_info (unw_addr_space_t as,
unw_proc_info_t *pi, void *arg);
extern int unwi_dyn_remote_find_proc_info (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info,
void *arg);
extern void unwi_dyn_remote_put_unwind_info (unw_addr_space_t as,
unw_proc_info_t *pi,
void *arg);
extern int unwi_dyn_validate_cache (unw_addr_space_t as, void *arg);
extern unw_dyn_info_list_t _U_dyn_info_list;
extern pthread_mutex_t _U_dyn_info_list_lock;
#define unw_address_is_valid UNWI_ARCH_OBJ(address_is_valid)
HIDDEN bool unw_address_is_valid(unw_word_t, size_t);
#if defined(UNW_DEBUG)
# define unwi_debug_level UNWI_ARCH_OBJ(debug_level)
extern long unwi_debug_level;
# include <stdarg.h>
# include <stdio.h>
# include <unistd.h>
#define Debug(level, ...) _unw_debug(level, __FUNCTION__, __VA_ARGS__)
static inline void _unw_debug(int level, char const * const fname, char const * const fmt, ...)
{
if (unwi_debug_level >= level)
{
enum { buf_size = 512 };
char buf[buf_size];
if (level > 16) level = 16;
int bcount = snprintf (buf, buf_size, "%*c>%s: ", level, ' ', fname);
int res = write(STDERR_FILENO, buf, bcount);
va_list ap;
va_start(ap, fmt);
bcount = vsnprintf (buf, buf_size, fmt, ap);
va_end(ap);
res = write(STDERR_FILENO, buf, bcount);
(void)res;
}
}
# define Dprintf( ...) \
fprintf (stderr, __VA_ARGS__)
#else
# define Debug(level, ...)
# define Dprintf( ...)
#endif
static ALWAYS_INLINE int
print_error (const char *string)
{
return write (2, string, strlen (string));
}
HIDDEN extern long unw_page_size;
static inline unw_word_t unw_page_start(unw_word_t addr)
{
return addr & ~(unw_page_size - 1);
}
#define mi_init UNWI_ARCH_OBJ(mi_init)
extern void mi_init (void);
extern unw_word_t _U_dyn_info_list_addr (void);
struct elf_image
{
void *image;
size_t size;
};
struct elf_dyn_info
{
struct elf_image ei;
unw_dyn_info_t di_cache;
unw_dyn_info_t di_debug;
#if UNW_TARGET_IA64
unw_dyn_info_t ktab;
#endif
#if UNW_TARGET_ARM
unw_dyn_info_t di_arm;
#endif
};
static inline void invalidate_edi (struct elf_dyn_info *edi)
{
if (edi->ei.image)
mi_munmap (edi->ei.image, edi->ei.size);
memset (edi, 0, sizeof (*edi));
edi->di_cache.format = -1;
edi->di_debug.format = -1;
#if UNW_TARGET_ARM
edi->di_arm.format = -1;
#endif
}
#define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \
do { (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); } \
while (0)
#ifndef PT_GNU_EH_FRAME
# define PT_GNU_EH_FRAME 0x6474e550
#endif
#ifndef PT_ARM_EXIDX
# define PT_ARM_EXIDX 0x70000001
#endif
#include "tdep/libunwind_i.h"
#ifndef TDEP_DWARF_SP
#define TDEP_DWARF_SP UNW_TDEP_SP
#endif
#ifndef tdep_get_func_addr
# define tdep_get_func_addr(as,addr,v) (*(v) = addr, 0)
#endif
#ifndef DWARF_VAL_LOC
# define DWARF_IS_VAL_LOC(l) 0
# define DWARF_VAL_LOC(c,v) DWARF_NULL_LOC
#endif
#define UNW_ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
#endif