123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /* libunwind - a platform-independent unwind library
- Copyright (C) 2001-2005 Hewlett-Packard Co
- Copyright (C) 2007 David Mosberger-Tang
- Contributed by David Mosberger-Tang <dmosberger@gmail.com>
- This file is part of libunwind.
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /* This files contains libunwind-internal definitions which are
- subject to frequent change and are not to be exposed to
- libunwind-users. */
- #ifndef libunwind_i_h
- #define libunwind_i_h
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #ifdef HAVE___THREAD
- /* For now, turn off per-thread caching. It uses up too much TLS
- memory per thread even when the thread never uses libunwind at
- all. */
- # undef HAVE___THREAD
- #endif
- /* Platform-independent libunwind-internal declarations. */
- #include <sys/types.h> /* HP-UX needs this before include of pthread.h */
- #include <assert.h>
- #include <libunwind.h>
- #if HAVE_SGX
- #include "pthread_compat.h"
- #else
- #include <pthread.h>
- #include <signal.h>
- #endif
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <elf.h>
- #if defined(HAVE_ENDIAN_H)
- # include <endian.h>
- #elif defined(HAVE_SYS_ENDIAN_H)
- # include <sys/endian.h>
- #else
- # define __LITTLE_ENDIAN 1234
- # define __BIG_ENDIAN 4321
- # if defined(__hpux)
- # define __BYTE_ORDER __BIG_ENDIAN
- # else
- # error Host has unknown byte-order.
- # endif
- #endif
- #ifdef __GNUC__
- # define UNUSED __attribute__((unused))
- # define NORETURN __attribute__((noreturn))
- # define ALIAS(name) __attribute__((alias (#name)))
- # if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
- # define ALWAYS_INLINE inline __attribute__((always_inline))
- # define HIDDEN __attribute__((visibility ("hidden")))
- # define PROTECTED __attribute__((visibility ("protected")))
- # else
- # define ALWAYS_INLINE
- # define HIDDEN
- # define PROTECTED
- # endif
- # if (__GNUC__ >= 3)
- # define likely(x) __builtin_expect ((x), 1)
- # define unlikely(x) __builtin_expect ((x), 0)
- # else
- # define likely(x) (x)
- # define unlikely(x) (x)
- # endif
- #else
- # define ALWAYS_INLINE
- # define UNUSED
- # define NORETURN
- # define ALIAS(name)
- # define HIDDEN
- # define PROTECTED
- # define likely(x) (x)
- # define unlikely(x) (x)
- #endif
- #ifdef DEBUG
- # define UNW_DEBUG 1
- #else
- # define UNW_DEBUG 0
- #endif
- #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
- /* Make it easy to write thread-safe code which may or may not be
- linked against libpthread. The macros below can be used
- unconditionally and if -lpthread is around, they'll call the
- corresponding routines otherwise, they do nothing. */
- #if HAVE_SGX
- #define mutex_init(l) do { *l = PTHREAD_MUTEX_INITIALIZER; } while(0)
- #define mutex_lock(l) do { if (pthread_mutex_lock ((l)) != 0) abort(); } while(0)
- #define mutex_unlock(l) do { if (pthread_mutex_unlock ((l)) != 0) abort(); } while(0)
- #else
- #pragma weak pthread_mutex_init
- #pragma weak pthread_mutex_lock
- #pragma weak pthread_mutex_unlock
- #define mutex_init(l) \
- (pthread_mutex_init != 0 ? pthread_mutex_init ((l), 0) : 0)
- #define mutex_lock(l) \
- (pthread_mutex_lock != 0 ? pthread_mutex_lock (l) : 0)
- #define mutex_unlock(l) \
- (pthread_mutex_unlock != 0 ? pthread_mutex_unlock (l) : 0)
- #endif
- #ifdef HAVE_ATOMIC_OPS_H
- # include <atomic_ops.h>
- static inline int
- cmpxchg_ptr (void *addr, void *old, void *new)
- {
- union
- {
- void *vp;
- AO_t *aop;
- }
- u;
- u.vp = addr;
- return AO_compare_and_swap(u.aop, (AO_t) old, (AO_t) new);
- }
- # define fetch_and_add1(_ptr) AO_fetch_and_add1(_ptr)
- /* GCC 3.2.0 on HP-UX crashes on cmpxchg_ptr() */
- # if !(defined(__hpux) && __GNUC__ == 3 && __GNUC_MINOR__ == 2)
- # define HAVE_CMPXCHG
- # endif
- # define HAVE_FETCH_AND_ADD1
- #else
- # ifdef HAVE_IA64INTRIN_H
- # include <ia64intrin.h>
- static inline int
- cmpxchg_ptr (void *addr, void *old, void *new)
- {
- union
- {
- void *vp;
- long *vlp;
- }
- u;
- u.vp = addr;
- return __sync_bool_compare_and_swap(u.vlp, (long) old, (long) new);
- }
- # define fetch_and_add1(_ptr) __sync_fetch_and_add(_ptr, 1)
- # define HAVE_CMPXCHG
- # define HAVE_FETCH_AND_ADD1
- # endif
- #endif
- #define atomic_read(ptr) (*(ptr))
- #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)
- /* Type of a mask that can be used to inhibit preemption. At the
- userlevel, preemption is caused by signals and hence sigset_t is
- appropriate. In constrast, the Linux kernel uses "unsigned long"
- to hold the processor "flags" instead. */
- typedef sigset_t intrmask_t;
- extern intrmask_t unwi_full_mask;
- /* Silence compiler warnings about variables which are used only if libunwind
- is configured in a certain way */
- static inline void mark_as_used(void *v) {
- }
- #if defined(CONFIG_BLOCK_SIGNALS)
- # define SIGPROCMASK(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
- #define define_lock(name) \
- pthread_mutex_t name = 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 /* see src/mi/mempool.c */
- #if HAVE_SGX /* Running inside Enclave */
- #define GET_MEMORY(mem, size) do { mem = malloc(size); } while (0)
- #else /* Normal application */
- #ifndef MAP_ANONYMOUS
- # define MAP_ANONYMOUS MAP_ANON
- #endif
- #define GET_MEMORY(mem, size) \
- do { \
- /* Hopefully, mmap() goes straight through to a system call stub... */ \
- mem = mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, \
- -1, 0); \
- if (mem == MAP_FAILED) \
- mem = NULL; \
- } while (0)
- #endif
- #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);
- /* These handle the remote (cross-address-space) case of accessing
- dynamic unwind info. */
- 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;
- #if UNW_DEBUG && !HAVE_SGX
- #define unwi_debug_level UNWI_ARCH_OBJ(debug_level)
- extern long unwi_debug_level;
- # include <stdio.h>
- # define Debug(level,format...) \
- do { \
- if (unwi_debug_level >= level) \
- { \
- int _n = level; \
- if (_n > 16) \
- _n = 16; \
- fprintf (stderr, "%*c>%s: ", _n, ' ', __FUNCTION__); \
- fprintf (stderr, format); \
- } \
- } while (0)
- # define Dprintf(format...) fprintf (stderr, format)
- # ifdef __GNUC__
- # undef inline
- # define inline UNUSED
- # endif
- #else
- # define Debug(level,format...)
- # define Dprintf(format...)
- #endif
- static ALWAYS_INLINE void
- print_error (const char *string)
- {
- #if !HAVE_SGX
- write (2, string, strlen (string));
- #endif
- }
- #define mi_init UNWI_ARCH_OBJ(mi_init)
- extern void mi_init (void); /* machine-independent initializations */
- extern unw_word_t _U_dyn_info_list_addr (void);
- /* This is needed/used by ELF targets only. */
- struct elf_image
- {
- void *image; /* pointer to mmap'd image */
- size_t size; /* (file-) size of the image */
- };
- struct elf_dyn_info
- {
- struct elf_image ei;
- unw_dyn_info_t di_cache;
- unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
- #if UNW_TARGET_IA64
- unw_dyn_info_t ktab;
- #endif
- #if UNW_TARGET_ARM
- unw_dyn_info_t di_arm; /* additional table info for .ARM.exidx */
- #endif
- };
- static void inline invalidate_edi (struct elf_dyn_info *edi)
- {
- if (edi->ei.image)
- #if !HAVE_SGX
- munmap (edi->ei.image, edi->ei.size);
- #else /* to align with GET_MEMORY() */
- free(edi->ei.image);
- #endif
- 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
- }
- /* Provide a place holder for architecture to override for fast access
- to memory when known not to need to validate and know the access
- will be local to the process. A suitable override will improve
- unw_tdep_trace() performance in particular. */
- #define ACCESS_MEM_FAST(ret,validate,cur,addr,to) \
- do { (ret) = dwarf_get ((cur), DWARF_MEM_LOC ((cur), (addr)), &(to)); } \
- while (0)
- /* Define GNU and processor specific values for the Phdr p_type field in case
- they aren't defined by <elf.h>. */
- #ifndef PT_GNU_EH_FRAME
- # define PT_GNU_EH_FRAME 0x6474e550
- #endif /* !PT_GNU_EH_FRAME */
- #ifndef PT_ARM_EXIDX
- # define PT_ARM_EXIDX 0x70000001 /* ARM unwind segment */
- #endif /* !PT_ARM_EXIDX */
- #include "tdep/libunwind_i.h"
- #ifndef tdep_get_func_addr
- # define tdep_get_func_addr(as,addr,v) (*(v) = addr, 0)
- #endif
- #endif /* libunwind_i_h */
|