1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-12-11 23:17:39 +01:00

Merge branch 'upstream'

Conflicts:
	src/dwarf/Gfind_proc_info-lsb.c
	src/x86_64/Gis_signal_frame.c
	src/x86_64/Gresume.c
	src/x86_64/ucontext_i.h
This commit is contained in:
Alexander Esilevich 2010-09-28 20:37:34 +07:00
commit 70d23830fa
122 changed files with 4342 additions and 1016 deletions

View file

@ -48,6 +48,9 @@ EXTRA_DIST = include/dwarf.h include/dwarf_i.h include/dwarf-eh.h \
include/libunwind_i.h include/mempool.h \ include/libunwind_i.h include/mempool.h \
include/remote.h \ include/remote.h \
include/libunwind-common.h.in \ include/libunwind-common.h.in \
include/tdep-arm/dwarf-config.h \
include/tdep-arm/jmpbuf.h include/tdep-arm/libunwind_i.h \
include/tdep-ia64/jmpbuf.h include/tdep-ia64/rse.h \
include/libunwind-ia64.h include/tdep-ia64/libunwind_i.h \ include/libunwind-ia64.h include/tdep-ia64/libunwind_i.h \
include/tdep-ia64/jmpbuf.h include/tdep-ia64/rse.h \ include/tdep-ia64/jmpbuf.h include/tdep-ia64/rse.h \
include/tdep-ia64/script.h \ include/tdep-ia64/script.h \

11
README
View file

@ -9,6 +9,8 @@ several architecture/operating-system combinations:
Linux/PARISC: Works well, but C library missing unwind-info. Linux/PARISC: Works well, but C library missing unwind-info.
HP-UX/IA-64: Mostly works but known to have some serious limitations. HP-UX/IA-64: Mostly works but known to have some serious limitations.
Linux/PPC64: Newly added. Linux/PPC64: Newly added.
FreeBSD/i386: Newly added.
FreeBSD/x86-64: Newly added (FreeBSD architecture is known as amd64).
* General Build Instructions * General Build Instructions
@ -16,6 +18,7 @@ several architecture/operating-system combinations:
In general, this library can be built and installed with the following In general, this library can be built and installed with the following
commands: commands:
$ autoreconf -i # Needed only for building from git. Depends on libtool.
$ ./configure $ ./configure
$ make $ make
$ make install prefix=PREFIX $ make install prefix=PREFIX
@ -79,6 +82,14 @@ If libunwind seems to not work (backtracing failing), try to compile
it with -O0, without optimizations. There are some compiler problems it with -O0, without optimizations. There are some compiler problems
depending on the version of your gcc. depending on the version of your gcc.
* Building on FreeBSD
General building instructions apply. To build and execute several tests,
you need libexecinfo library available in ports as devel/libexecinfo.
Development of the port was done of FreeBSD 8.0-STABLE. The library
was build with the system compiler that is modified version of gcc 4.2.1,
as well as the gcc 4.4.3.
* Regression Testing * Regression Testing

View file

@ -23,12 +23,21 @@ AM_PROG_CC_C_O
dnl Checks for libraries. dnl Checks for libraries.
AC_CHECK_LIB(uca, __uc_get_grs) AC_CHECK_LIB(uca, __uc_get_grs)
OLD_LIBS=${LIBS}
AC_SEARCH_LIBS(dlopen, dl)
LIBS=${OLD_LIBS}
case "$ac_cv_search_dlopen" in
-l*) DLLIB=$ac_cv_search_dlopen;;
*) DLLIB="";;
esac
CHECK_ATOMIC_OPS CHECK_ATOMIC_OPS
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h execinfo.h ia64intrin.h \ AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h sys/endian.h execinfo.h \
sys/uc_access.h unistd.h signal.h) ia64intrin.h sys/uc_access.h unistd.h signal.h sys/types.h \
sys/procfs.h)
dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST AC_C_CONST
@ -51,11 +60,23 @@ AC_CHECK_TYPES([sighandler_t], [], [],
#endif #endif
]) ])
AC_CHECK_DECLS([PTRACE_POKEUSER, PTRACE_POKEDATA, PTRACE_CONT,
PTRACE_TRACEME, PTRACE_CONT, PTRACE_SIGNLESTEP,
PTRACE_SYSCALL, PT_IO, PT_GETREGS,
PT_GETFPREGS, PT_CONTINUE, PT_TRACE_ME,
PT_STEP, PT_SYSCALL], [], [],
[$ac_includes_default
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/ptrace.h>
])
dnl Checks for library functions. dnl Checks for library functions.
AC_FUNC_MEMCMP AC_FUNC_MEMCMP
AC_TYPE_SIGNAL AC_TYPE_SIGNAL
AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo getunwind \ AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo getunwind \
ttrace) ttrace mincore)
is_gcc_m64() { is_gcc_m64() {
if test `echo $CFLAGS | grep "\-m64" -c` -eq 1 ; then echo ppc64; if test `echo $CFLAGS | grep "\-m64" -c` -eq 1 ; then echo ppc64;
else else
@ -80,6 +101,7 @@ get_arch() {
hppa*) echo hppa;; hppa*) echo hppa;;
mips*) echo mips;; mips*) echo mips;;
powerpc*) is_gcc_m64;; powerpc*) is_gcc_m64;;
amd64) echo x86_64;;
*) echo $1;; *) echo $1;;
esac esac
} }
@ -99,6 +121,7 @@ AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32)
AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64) AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64)
AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null) AM_CONDITIONAL(OS_LINUX, expr x$target_os : xlinux >/dev/null)
AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null) AM_CONDITIONAL(OS_HPUX, expr x$target_os : xhpux >/dev/null)
AM_CONDITIONAL(OS_FREEBSD, expr x$target_os : xfreebsd >/dev/null)
if test x$target_arch = xppc64; then if test x$target_arch = xppc64; then
libdir='${exec_prefix}/lib64' libdir='${exec_prefix}/lib64'
@ -139,6 +162,20 @@ if test x$enable_debug_frame = xyes; then
AC_DEFINE([CONFIG_DEBUG_FRAME], [], [Enable Debug Frame]) AC_DEFINE([CONFIG_DEBUG_FRAME], [], [Enable Debug Frame])
fi fi
AC_ARG_ENABLE(block_signals,
[ --enable-block-signals Block signals before performing mutex operations],
[enable_block_signals=$enableval], [enable_block_signals=yes])
if test x$enable_block_signals = xyes; then
AC_DEFINE([CONFIG_BLOCK_SIGNALS], [], [Block signals before mutex operations])
fi
AC_ARG_ENABLE(conservative_checks,
[ --enable-conservative-checks Validate all memory addresses before use],
[enable_conservative_checks=$enableval], [enable_conservative_checks=yes])
if test x$enable_conservative_checks = xyes; then
CPPFLAGS="${CPPFLAGS} -DCONSERVATIVE_CHECKS"
fi
LIBUNWIND___THREAD LIBUNWIND___THREAD
save_LDFLAGS="$LDFLAGS" save_LDFLAGS="$LDFLAGS"
@ -180,6 +217,8 @@ AC_SUBST(PKG_MINOR)
AC_SUBST(PKG_EXTRA) AC_SUBST(PKG_EXTRA)
AC_SUBST(PKG_MAINTAINER) AC_SUBST(PKG_MAINTAINER)
AC_SUBST(enable_cxx_exceptions) AC_SUBST(enable_cxx_exceptions)
AC_SUBST(enable_debug_frame)
AC_SUBST(DLLIB)
AC_CONFIG_FILES(Makefile src/Makefile tests/Makefile tests/check-namespace.sh AC_CONFIG_FILES(Makefile src/Makefile tests/Makefile tests/check-namespace.sh
doc/Makefile doc/common.tex include/libunwind-common.h) doc/Makefile doc/common.tex include/libunwind-common.h)

View file

@ -39,6 +39,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
struct dwarf_cursor; /* forward-declaration */ struct dwarf_cursor; /* forward-declaration */
#include "dwarf-config.h" #include "dwarf-config.h"
#include <link.h>
/* DWARF expression opcodes. */ /* DWARF expression opcodes. */
@ -247,6 +248,7 @@ typedef struct dwarf_reg_state
unsigned short lru_chain; /* used for least-recently-used chain */ unsigned short lru_chain; /* used for least-recently-used chain */
unsigned short coll_chain; /* used for hash collisions */ unsigned short coll_chain; /* used for hash collisions */
unsigned short hint; /* hint for next rs to try (or -1) */ unsigned short hint; /* hint for next rs to try (or -1) */
unsigned short signal_frame; /* optional machine-dependent signal info */
} }
dwarf_reg_state_t; dwarf_reg_state_t;
@ -266,6 +268,7 @@ typedef struct dwarf_cie_info
uint8_t lsda_encoding; uint8_t lsda_encoding;
unsigned int sized_augmentation : 1; unsigned int sized_augmentation : 1;
unsigned int have_abi_marker : 1; unsigned int have_abi_marker : 1;
unsigned int signal_frame : 1;
} }
dwarf_cie_info_t; dwarf_cie_info_t;
@ -293,6 +296,7 @@ typedef struct dwarf_cursor
dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS]; dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS];
unsigned int use_prev_instr :1; /* use previous (= call) or current (= signal) instruction? */
unsigned int pi_valid :1; /* is proc_info valid? */ unsigned int pi_valid :1; /* is proc_info valid? */
unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */ unsigned int pi_is_dynamic :1; /* proc_info found via dynamic proc info? */
unw_proc_info_t pi; /* info about current procedure */ unw_proc_info_t pi; /* info about current procedure */
@ -312,11 +316,7 @@ typedef unsigned char unw_hash_index_t;
struct dwarf_rs_cache struct dwarf_rs_cache
{ {
#ifdef HAVE_ATOMIC_OPS_H
AO_TS_t busy; /* is the rs-cache busy? */
#else
pthread_mutex_t lock; pthread_mutex_t lock;
#endif
unsigned short lru_head; /* index of lead-recently used rs */ unsigned short lru_head; /* index of lead-recently used rs */
unsigned short lru_tail; /* index of most-recently used rs */ unsigned short lru_tail; /* index of most-recently used rs */
@ -349,6 +349,7 @@ struct unw_debug_frame_list
/* Convenience macros: */ /* Convenience macros: */
#define dwarf_init UNW_ARCH_OBJ (dwarf_init) #define dwarf_init UNW_ARCH_OBJ (dwarf_init)
#define dwarf_find_proc_info UNW_OBJ (dwarf_find_proc_info) #define dwarf_find_proc_info UNW_OBJ (dwarf_find_proc_info)
#define dwarf_find_debug_frame UNW_OBJ (dwarf_find_debug_frame)
#define dwarf_search_unwind_table UNW_OBJ (dwarf_search_unwind_table) #define dwarf_search_unwind_table UNW_OBJ (dwarf_search_unwind_table)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info) #define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info) #define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
@ -365,6 +366,8 @@ extern int dwarf_init (void);
extern int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip, extern int dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, unw_proc_info_t *pi,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern int dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
struct dl_phdr_info *info, unw_word_t ip);
extern int dwarf_search_unwind_table (unw_addr_space_t as, extern int dwarf_search_unwind_table (unw_addr_space_t as,
unw_word_t ip, unw_word_t ip,
unw_dyn_info_t *di, unw_dyn_info_t *di,

View file

@ -119,6 +119,8 @@ typedef struct unw_addr_space *unw_addr_space_t;
/* Each target may define it's own set of flags, but bits 0-15 are /* Each target may define it's own set of flags, but bits 0-15 are
reserved for general libunwind-use. */ reserved for general libunwind-use. */
#define UNW_PI_FLAG_FIRST_TDEP_BIT 16 #define UNW_PI_FLAG_FIRST_TDEP_BIT 16
/* The information comes from a .debug_frame section. */
#define UNW_PI_FLAG_DEBUG_FRAME 32
typedef struct unw_proc_info typedef struct unw_proc_info
{ {
@ -220,6 +222,7 @@ unw_save_loc_t;
#define unw_set_fpreg UNW_OBJ(set_fpreg) #define unw_set_fpreg UNW_OBJ(set_fpreg)
#define unw_get_save_loc UNW_OBJ(get_save_loc) #define unw_get_save_loc UNW_OBJ(get_save_loc)
#define unw_is_signal_frame UNW_OBJ(is_signal_frame) #define unw_is_signal_frame UNW_OBJ(is_signal_frame)
#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame)
#define unw_get_proc_name UNW_OBJ(get_proc_name) #define unw_get_proc_name UNW_OBJ(get_proc_name)
#define unw_set_caching_policy UNW_OBJ(set_caching_policy) #define unw_set_caching_policy UNW_OBJ(set_caching_policy)
#define unw_regname UNW_ARCH_OBJ(regname) #define unw_regname UNW_ARCH_OBJ(regname)
@ -246,6 +249,7 @@ extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *);
extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t); extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t);
extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *); extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *);
extern int unw_is_signal_frame (unw_cursor_t *); extern int unw_is_signal_frame (unw_cursor_t *);
extern int unw_handle_signal_frame (unw_cursor_t *);
extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *); extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *);
extern const char *unw_strerror (int); extern const char *unw_strerror (int);

View file

@ -75,7 +75,7 @@ typedef enum
{ {
UNW_INFO_FORMAT_DYNAMIC, /* unw_dyn_proc_info_t */ UNW_INFO_FORMAT_DYNAMIC, /* unw_dyn_proc_info_t */
UNW_INFO_FORMAT_TABLE, /* unw_dyn_table_t */ UNW_INFO_FORMAT_TABLE, /* unw_dyn_table_t */
UNW_INFO_FORMAT_REMOTE_TABLE, /* unw_dyn_remote_table_t */ UNW_INFO_FORMAT_REMOTE_TABLE /* unw_dyn_remote_table_t */
} }
unw_dyn_info_format_t; unw_dyn_info_format_t;

View file

@ -30,6 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
extern "C" { extern "C" {
#endif #endif
#include <sys/types.h>
#include <inttypes.h> #include <inttypes.h>
#include <ucontext.h> #include <ucontext.h>
@ -147,7 +148,7 @@ typedef enum
UNW_TDEP_LAST_REG = UNW_X86_XMM7, UNW_TDEP_LAST_REG = UNW_X86_XMM7,
UNW_TDEP_IP = UNW_X86_EIP, UNW_TDEP_IP = UNW_X86_EIP,
UNW_TDEP_SP = UNW_X86_CFA, UNW_TDEP_SP = UNW_X86_ESP,
UNW_TDEP_EH = UNW_X86_EAX UNW_TDEP_EH = UNW_X86_EAX
} }
x86_regnum_t; x86_regnum_t;
@ -163,12 +164,6 @@ unw_tdep_save_loc_t;
/* On x86, we can directly use ucontext_t as the unwind context. */ /* On x86, we can directly use ucontext_t as the unwind context. */
typedef ucontext_t unw_tdep_context_t; typedef ucontext_t unw_tdep_context_t;
/* XXX this is not ideal: an application should not be prevented from
using the "getcontext" name just because it's using libunwind. We
can't just use __getcontext() either, because that isn't exported
by glibc... */
#define unw_tdep_getcontext(uc) (getcontext (uc), 0)
#include "libunwind-dynamic.h" #include "libunwind-dynamic.h"
typedef struct typedef struct
@ -179,6 +174,9 @@ unw_tdep_proc_info_t;
#include "libunwind-common.h" #include "libunwind-common.h"
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
extern int unw_tdep_getcontext (unw_tdep_context_t *);
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int); extern int unw_tdep_is_fpreg (int);

View file

@ -32,6 +32,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
extern "C" { extern "C" {
#endif #endif
#include <sys/types.h>
#include <inttypes.h> #include <inttypes.h>
#include <ucontext.h> #include <ucontext.h>

View file

@ -54,8 +54,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_ENDIAN_H #if defined(HAVE_ENDIAN_H)
# include <endian.h> # include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
#else #else
# define __LITTLE_ENDIAN 1234 # define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321 # define __BIG_ENDIAN 4321
@ -180,22 +182,37 @@ typedef sigset_t intrmask_t;
extern intrmask_t unwi_full_mask; 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) \ #define define_lock(name) \
pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER
#define lock_init(l) mutex_init (l) #define lock_init(l) mutex_init (l)
#define lock_acquire(l,m) \ #define lock_acquire(l,m) \
do { \ do { \
sigprocmask (SIG_SETMASK, &unwi_full_mask, &(m)); \ SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m)); \
mutex_lock (l); \ mutex_lock (l); \
} while (0) } while (0)
#define lock_release(l,m) \ #define lock_release(l,m) \
do { \ do { \
mutex_unlock (l); \ mutex_unlock (l); \
sigprocmask (SIG_SETMASK, &(m), NULL); \ SIGPROCMASK (SIG_SETMASK, &(m), NULL); \
} while (0) } while (0)
#define SOS_MEMORY_SIZE 16384 /* see src/mi/mempool.c */ #define SOS_MEMORY_SIZE 16384 /* see src/mi/mempool.c */
#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#endif
#define GET_MEMORY(mem, size_in_bytes) \ #define GET_MEMORY(mem, size_in_bytes) \
do { \ do { \
/* Hopefully, mmap() goes straight through to a system call stub... */ \ /* Hopefully, mmap() goes straight through to a system call stub... */ \
@ -267,10 +284,10 @@ do { \
# define Dprintf(format...) # define Dprintf(format...)
#endif #endif
static ALWAYS_INLINE void static ALWAYS_INLINE int
print_error (const char *string) print_error (const char *string)
{ {
write (2, string, strlen (string)); return write (2, string, strlen (string));
} }
#define mi_init UNWI_ARCH_OBJ(mi_init) #define mi_init UNWI_ARCH_OBJ(mi_init)

View file

@ -217,6 +217,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \ # define tdep_find_proc_info(c,ip,n) \
@ -245,10 +248,21 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t *uc, int reg); extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
unw_fpreg_t *valp, int write); unw_fpreg_t *valp, int write);
/* unwinding method selection support */
#define UNW_ARM_METHOD_ALL 0xFF
#define UNW_ARM_METHOD_DWARF 0x01
#define UNW_ARM_METHOD_FRAME 0x02
#define unwi_unwind_method UNWI_ARCH_OBJ(unwind_method)
extern int unwi_unwind_method;
#define UNW_TRY_METHOD(x) (unwi_unwind_method & x)
#endif /* ARM_LIBUNWIND_I_H */ #endif /* ARM_LIBUNWIND_I_H */

View file

@ -224,6 +224,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \ # define tdep_find_proc_info(c,ip,n) \
@ -252,7 +255,8 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t *uc, int reg); extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -220,6 +220,9 @@ struct ia64_global_unwind_state
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#define tdep_get_as(c) ((c)->as) #define tdep_get_as(c) ((c)->as)
#define tdep_get_as_arg(c) ((c)->as_arg) #define tdep_get_as_arg(c) ((c)->as_arg)
#define tdep_get_ip(c) ((c)->ip) #define tdep_get_ip(c) ((c)->ip)
@ -244,7 +247,8 @@ extern void tdep_put_unwind_info (unw_addr_space_t as,
extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum, extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum,
uint8_t *nat_bitnr); uint8_t *nat_bitnr);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -279,6 +279,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \ # define tdep_find_proc_info(c,ip,n) \
@ -306,7 +309,8 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t *uc, int reg); extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -256,6 +256,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#define tdep_get_func_addr UNW_OBJ(get_func_addr) #define tdep_get_func_addr UNW_OBJ(get_func_addr)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
@ -289,7 +292,8 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t * uc, int reg); extern void *tdep_uc_addr (ucontext_t * uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t * valp, int write); unw_word_t * valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -256,6 +256,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#define tdep_get_func_addr UNW_OBJ(get_func_addr) #define tdep_get_func_addr UNW_OBJ(get_func_addr)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
@ -289,7 +292,8 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t * uc, int reg); extern void *tdep_uc_addr (ucontext_t * uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t * valp, int write); unw_word_t * valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -25,7 +25,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ /* Use glibc's jump-buffer indices; NPTL peeks at SP: */
#if defined __linux__
#define JB_SP 4 #define JB_SP 4
#define JB_RP 5 #define JB_RP 5
#define JB_MASK_SAVED 6 #define JB_MASK_SAVED 6
#define JB_MASK 7 #define JB_MASK 7
#elif defined __FreeBSD__
#define JB_SP 1
#define JB_RP 0
/* Pretend the ip cannot be 0 and mask is always saved */
#define JB_MASK_SAVED 0
#define JB_MASK 7
#endif

View file

@ -60,8 +60,12 @@ struct cursor
enum enum
{ {
X86_SCF_NONE, /* no signal frame encountered */ X86_SCF_NONE, /* no signal frame encountered */
X86_SCF_LINUX_SIGFRAME, /* classic x86 sigcontext */ X86_SCF_LINUX_SIGFRAME, /* Linux x86 sigcontext */
X86_SCF_LINUX_RT_SIGFRAME /* POSIX ucontext_t */ X86_SCF_LINUX_RT_SIGFRAME, /* POSIX ucontext_t */
X86_SCF_FREEBSD_SIGFRAME, /* FreeBSD x86 sigcontext */
X86_SCF_FREEBSD_SIGFRAME4, /* FreeBSD 4.x x86 sigcontext */
X86_SCF_FREEBSD_OSIGFRAME, /* FreeBSD pre-4.x x86 sigcontext */
X86_SCF_FREEBSD_SYSCALL, /* FreeBSD x86 syscall */
} }
sigcontext_format; sigcontext_format;
unw_word_t sigcontext_addr; unw_word_t sigcontext_addr;
@ -236,6 +240,9 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#define tdep_fetch_frame(c,ip,n) do {} while(0)
#define tdep_cache_frame(c,rs) do {} while(0)
#define tdep_reuse_frame(c,rs) do {} while(0)
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \ # define tdep_find_proc_info(c,ip,n) \
@ -264,7 +271,8 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t *uc, int reg); extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,

View file

@ -23,9 +23,21 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#if defined __linux__
/* Use glibc's jump-buffer indices; NPTL peeks at SP: */ /* Use glibc's jump-buffer indices; NPTL peeks at SP: */
#define JB_SP 6 #define JB_SP 6
#define JB_RP 7 #define JB_RP 7
#define JB_MASK_SAVED 8 #define JB_MASK_SAVED 8
#define JB_MASK 9 #define JB_MASK 9
#elif defined __FreeBSD__
#define JB_SP 2
#define JB_RP 0
/* Pretend the ip cannot be 0 and mask is always saved */
#define JB_MASK_SAVED 0
#define JB_MASK 9
#endif

View file

@ -62,7 +62,9 @@ struct cursor
enum enum
{ {
X86_64_SCF_NONE, /* no signal frame encountered */ X86_64_SCF_NONE, /* no signal frame encountered */
X86_64_SCF_LINUX_RT_SIGFRAME /* POSIX ucontext_t */ X86_64_SCF_LINUX_RT_SIGFRAME, /* Linux ucontext_t */
X86_64_SCF_FREEBSD_SIGFRAME, /* FreeBSD signal frame */
X86_64_SCF_FREEBSD_SYSCALL, /* FreeBSD syscall */
} }
sigcontext_format; sigcontext_format;
unw_word_t sigcontext_addr; unw_word_t sigcontext_addr;
@ -161,6 +163,15 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image) #define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg) #define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg) #define tdep_access_fpreg UNW_OBJ(access_fpreg)
#if __linux__
# define tdep_fetch_frame UNW_OBJ(fetch_frame)
# define tdep_cache_frame UNW_OBJ(cache_frame)
# define tdep_reuse_frame UNW_OBJ(reuse_frame)
#else
# define tdep_fetch_frame(c,ip,n) do {} while(0)
# define tdep_cache_frame(c,rs) do {} while(0)
# define tdep_reuse_frame(c,rs) do {} while(0)
#endif
#ifdef UNW_LOCAL_ONLY #ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \ # define tdep_find_proc_info(c,ip,n) \
@ -189,10 +200,20 @@ extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
int need_unwind_info, void *arg); int need_unwind_info, void *arg);
extern void *tdep_uc_addr (ucontext_t *uc, int reg); extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff); unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write); unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
unw_fpreg_t *valp, int write); unw_fpreg_t *valp, int write);
#if __linux__
extern void tdep_fetch_frame (struct dwarf_cursor *c, unw_word_t ip,
int need_unwind_info);
extern void tdep_cache_frame (struct dwarf_cursor *c,
struct dwarf_reg_state *rs);
extern void tdep_reuse_frame (struct dwarf_cursor *c,
struct dwarf_reg_state *rs);
#endif
#endif /* X86_64_LIBUNWIND_I_H */ #endif /* X86_64_LIBUNWIND_I_H */

View file

@ -15,7 +15,7 @@
# include "tdep-ppc64/dwarf-config.h" # include "tdep-ppc64/dwarf-config.h"
#elif defined __i386__ #elif defined __i386__
# include "tdep-x86/dwarf-config.h" # include "tdep-x86/dwarf-config.h"
#elif defined __x86_64__ #elif defined __x86_64__ || defined __amd64__
# include "tdep-x86_64/dwarf-config.h" # include "tdep-x86_64/dwarf-config.h"
#else #else
# error "Unsupported arch" # error "Unsupported arch"

View file

@ -26,6 +26,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef _UNWIND_H #ifndef _UNWIND_H
#define _UNWIND_H #define _UNWIND_H
/* For uint64_t */
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -62,23 +65,22 @@ typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
struct _Unwind_Exception *); struct _Unwind_Exception *);
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action, typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action,
unsigned long, uint64_t,
struct _Unwind_Exception *, struct _Unwind_Exception *,
struct _Unwind_Context *, struct _Unwind_Context *,
void *); void *);
/* The C++ ABI requires exception_class, private_1, and private_2 to /* The C++ ABI requires exception_class, private_1, and private_2 to
be of type uint64 and the entire structure to be be of type uint64 and the entire structure to be
double-word-aligned, but that seems a bit overly IA-64-specific. double-word-aligned. Please note that exception_class stays 64-bit
Using "unsigned long" instead should give us the desired effect on even on 32-bit machines for gcc compatibility. */
IA-64, while being more general. */
struct _Unwind_Exception struct _Unwind_Exception
{ {
unsigned long exception_class; uint64_t exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup; _Unwind_Exception_Cleanup_Fn exception_cleanup;
unsigned long private_1; unsigned long private_1;
unsigned long private_2; unsigned long private_2;
}; } __attribute__((__aligned__));
extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *); extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *, extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,

View file

@ -97,6 +97,8 @@ libunwind_la_SOURCES_os_linux = os-linux.h os-linux.c
libunwind_la_SOURCES_os_hpux = os-hpux.c libunwind_la_SOURCES_os_hpux = os-hpux.c
libunwind_la_SOURCES_os_freebsd = os-freebsd.c
dwarf_SOURCES_common = \ dwarf_SOURCES_common = \
dwarf/global.c dwarf/global.c
@ -106,11 +108,11 @@ dwarf_SOURCES_local = \
dwarf_SOURCES_generic = \ dwarf_SOURCES_generic = \
dwarf/Gexpr.c dwarf/Gfde.c dwarf/Gparser.c dwarf/Gpe.c dwarf/Gstep.c dwarf/Gexpr.c dwarf/Gfde.c dwarf/Gparser.c dwarf/Gpe.c dwarf/Gstep.c
# The list of files that go info libunwind and libunwind-arm: # The list of files that go into libunwind and libunwind-arm:
libunwind_la_SOURCES_arm_common = $(libunwind_la_SOURCES_common) \ libunwind_la_SOURCES_arm_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \ $(dwarf_SOURCES_common) \
elf32.c elf32.h \ elf32.c elf32.h \
arm/init.h arm/offsets.h arm/regs.h \ arm/init.h arm/offsets.h arm/unwind_i.h \
arm/is_fpreg.c arm/regname.c arm/is_fpreg.c arm/regname.c
# The list of files that go into libunwind: # The list of files that go into libunwind:
@ -191,7 +193,7 @@ libunwind_hppa_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \
libunwind_la_SOURCES_mips_common = $(libunwind_la_SOURCES_common) \ libunwind_la_SOURCES_mips_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \ $(dwarf_SOURCES_common) \
elfxx.c \ elfxx.c \
mips/init.h mips/offsets.h mips/regs.h \ mips/init.h mips/offsets.h \
mips/is_fpreg.c mips/regname.c mips/is_fpreg.c mips/regname.c
# The list of files that go into libunwind: # The list of files that go into libunwind:
@ -221,50 +223,54 @@ libunwind_la_SOURCES_x86_common = $(libunwind_la_SOURCES_common) \
# The list of files that go into libunwind: # The list of files that go into libunwind:
libunwind_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \ libunwind_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os_local) \
$(libunwind_la_SOURCES_local) \ $(libunwind_la_SOURCES_local) \
$(dwarf_SOURCES_local) \ $(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.c \ dwarf/Lfind_proc_info-lsb.c \
x86/Lcreate_addr_space.c x86/Lget_save_loc.c x86/Lglobal.c \ x86/Lcreate_addr_space.c x86/Lget_save_loc.c x86/Lglobal.c \
x86/Linit.c x86/Linit_local.c x86/Linit_remote.c \ x86/Linit.c x86/Linit_local.c x86/Linit_remote.c \
x86/Lis_signal_frame.c x86/Lget_proc_info.c x86/Lregs.c \ x86/Lget_proc_info.c x86/Lregs.c \
x86/Lresume.c x86/Lstep.c x86/Lresume.c x86/Lstep.c
# The list of files that go into libunwind-x86: # The list of files that go into libunwind-x86:
libunwind_x86_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \ libunwind_x86_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os) \
$(libunwind_la_SOURCES_generic) \ $(libunwind_la_SOURCES_generic) \
$(dwarf_SOURCES_generic) \ $(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.c \ dwarf/Gfind_proc_info-lsb.c \
x86/Gcreate_addr_space.c x86/Gget_save_loc.c x86/Gglobal.c \ x86/Gcreate_addr_space.c x86/Gget_save_loc.c x86/Gglobal.c \
x86/Ginit.c x86/Ginit_local.c x86/Ginit_remote.c \ x86/Ginit.c x86/Ginit_local.c x86/Ginit_remote.c \
x86/Gis_signal_frame.c x86/Gget_proc_info.c x86/Gregs.c \ x86/Gget_proc_info.c x86/Gregs.c \
x86/Gresume.c x86/Gstep.c x86/Gresume.c x86/Gstep.c
# The list of files that go both into libunwind and libunwind-x86_64: # The list of files that go both into libunwind and libunwind-x86_64:
libunwind_la_SOURCES_x86_64_common = $(libunwind_la_SOURCES_common) \ libunwind_la_SOURCES_x86_64_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \ $(dwarf_SOURCES_common) \
elf64.c elf64.h \ elf64.c elf64.h x86_64/offsets.h \
x86_64/init.h x86_64/unwind_i.h x86_64/ucontext_i.h \ x86_64/init.h x86_64/unwind_i.h x86_64/ucontext_i.h \
x86_64/is_fpreg.c x86_64/regname.c x86_64/is_fpreg.c x86_64/regname.c
# The list of files that go into libunwind: # The list of files that go into libunwind:
libunwind_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \ libunwind_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
$(libunwind_la_SOURCES_x86_64_os_local) \
$(libunwind_la_SOURCES_local) \ $(libunwind_la_SOURCES_local) \
$(dwarf_SOURCES_local) \ $(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.c \ dwarf/Lfind_proc_info-lsb.c \
x86_64/setcontext.S \ x86_64/setcontext.S \
x86_64/Lcreate_addr_space.c x86_64/Lget_save_loc.c x86_64/Lglobal.c \ x86_64/Lcreate_addr_space.c x86_64/Lget_save_loc.c x86_64/Lglobal.c \
x86_64/Linit.c x86_64/Linit_local.c x86_64/Linit_remote.c \ x86_64/Linit.c x86_64/Linit_local.c x86_64/Linit_remote.c \
x86_64/Lis_signal_frame.c x86_64/Lget_proc_info.c x86_64/Lregs.c \ x86_64/Lget_proc_info.c x86_64/Lregs.c \
x86_64/Lresume.c x86_64/Lstep.c x86_64/getcontext.S x86_64/Lresume.c x86_64/Lstep.c x86_64/getcontext.S
# The list of files that go into libunwind-x86_64: # The list of files that go into libunwind-x86_64:
libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \ libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
$(libunwind_la_SOURCES_x86_64_os) \
$(libunwind_la_SOURCES_generic) \ $(libunwind_la_SOURCES_generic) \
$(dwarf_SOURCES_generic) \ $(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.c \ dwarf/Gfind_proc_info-lsb.c \
x86_64/Gcreate_addr_space.c x86_64/Gget_save_loc.c x86_64/Gglobal.c \ x86_64/Gcreate_addr_space.c x86_64/Gget_save_loc.c x86_64/Gglobal.c \
x86_64/Ginit.c x86_64/Ginit_local.c x86_64/Ginit_remote.c \ x86_64/Ginit.c x86_64/Ginit_local.c x86_64/Ginit_remote.c \
x86_64/Gis_signal_frame.c x86_64/Gget_proc_info.c x86_64/Gregs.c \ x86_64/Gget_proc_info.c x86_64/Gregs.c \
x86_64/Gresume.c x86_64/Gstep.c x86_64/Gresume.c x86_64/Gstep.c
# The list of local files that go to Power 64 and 32: # The list of local files that go to Power 64 and 32:
@ -342,8 +348,13 @@ install-exec-hook:
endif endif
if OS_LINUX if OS_LINUX
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_linux) libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_linux)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_linux_local) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_linux_local)
libunwind_la_SOURCES_x86_os = x86/Gos-linux.c
libunwind_x86_la_SOURCES_os = x86/getcontext-linux.S
libunwind_la_SOURCES_x86_os_local = x86/Los-linux.c
libunwind_la_SOURCES_x86_64_os = x86_64/Gos-linux.c
libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-linux.c
endif endif
if OS_HPUX if OS_HPUX
@ -351,6 +362,16 @@ if OS_HPUX
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_hpux_local) libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_hpux_local)
endif endif
if OS_FREEBSD
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_freebsd)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_freebsd_local)
libunwind_la_SOURCES_x86_os = x86/Gos-freebsd.c
libunwind_x86_la_SOURCES_os = x86/getcontext-freebsd.S
libunwind_la_SOURCES_x86_os_local = x86/Los-freebsd.c
libunwind_la_SOURCES_x86_64_os = x86_64/Gos-freebsd.c
libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-freebsd.c
endif
if ARCH_ARM if ARCH_ARM
lib_LTLIBRARIES_arch = libunwind-arm.la lib_LTLIBRARIES_arch = libunwind-arm.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_arm) libunwind_la_SOURCES = $(libunwind_la_SOURCES_arm)
@ -405,7 +426,7 @@ endif
else else
if ARCH_X86 if ARCH_X86
lib_LTLIBRARIES_arch = libunwind-x86.la lib_LTLIBRARIES_arch = libunwind-x86.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86) libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86) $(libunwind_x86_la_SOURCES_os)
libunwind_x86_la_SOURCES = $(libunwind_x86_la_SOURCES_x86) libunwind_x86_la_SOURCES = $(libunwind_x86_la_SOURCES_x86)
libunwind_x86_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION) libunwind_x86_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION)
if !REMOTE_ONLY if !REMOTE_ONLY

View file

@ -29,6 +29,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
HIDDEN pthread_mutex_t arm_lock = PTHREAD_MUTEX_INITIALIZER; HIDDEN pthread_mutex_t arm_lock = PTHREAD_MUTEX_INITIALIZER;
HIDDEN int tdep_needs_initialization = 1; HIDDEN int tdep_needs_initialization = 1;
/* Unwinding methods to use. See UNW_METHOD_ enums */
HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL;
/* FIXME: I'm pretty sure we don't need this at all for ARM, but "generic" /* FIXME: I'm pretty sure we don't need this at all for ARM, but "generic"
code (include/dwarf_i.h) seems to expect it to be here at present. */ code (include/dwarf_i.h) seems to expect it to be here at present. */
@ -44,13 +47,19 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&arm_lock, saved_mask);
mutex_lock (&arm_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
goto out; goto out;
/* read ARM unwind method setting */
const char* str = getenv ("UNW_ARM_UNWIND_METHOD");
if (str)
{
unwi_unwind_method = atoi (str);
}
mi_init (); mi_init ();
dwarf_init (); dwarf_init ();
@ -61,6 +70,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&arm_lock); lock_release (&arm_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space; c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc; c->dwarf.as_arg = uc;
return common_init (c); return common_init (c, 1);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */

View file

@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as = as; c->dwarf.as = as;
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
return common_init (c); return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */ #endif /* !UNW_LOCAL_ONLY */
} }

View file

@ -29,20 +29,83 @@ PROTECTED int
unw_step (unw_cursor_t *cursor) unw_step (unw_cursor_t *cursor)
{ {
struct cursor *c = (struct cursor *) cursor; struct cursor *c = (struct cursor *) cursor;
int ret; int ret = -UNW_EUNSPEC;
Debug (1, "(cursor=%p)\n", c); Debug (1, "(cursor=%p)\n", c);
/* Try DWARF-based unwinding... this is the only method likely to work for /* Try DWARF-based unwinding... this is the only method likely to work for
ARM. */ ARM. */
ret = dwarf_step (&c->dwarf); if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
{
ret = dwarf_step (&c->dwarf);
Debug(1, "dwarf_step()=%d\n", ret);
if (unlikely (ret == -UNW_ESTOPUNWIND)) if (unlikely (ret == -UNW_ESTOPUNWIND))
return ret; return ret;
if (ret < 0 && ret != -UNW_ENOINFO)
{
Debug (2, "returning %d\n", ret);
return ret;
}
}
/* Dwarf unwinding didn't work, stop. */
if (unlikely (ret < 0)) if (unlikely (ret < 0))
return 0; {
if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
return (c->dwarf.ip == 0) ? 0 : 1; {
ret = UNW_ESUCCESS;
/* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
unw_word_t instr, i;
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
dwarf_loc_t ip_loc, fp_loc;
unw_word_t frame;
/* Mark all registers unsaved, since we don't know where
they are saved (if at all), except for the EBP and
EIP. */
if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0)
{
return 0;
}
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) {
c->dwarf.loc[i] = DWARF_NULL_LOC;
}
if (frame)
{
if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0)
{
return 0;
}
instr -= 8;
if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0)
{
return 0;
}
if ((instr & 0xFFFFD800) == 0xE92DD800)
{
/* Standard APCS frame. */
ip_loc = DWARF_LOC(frame - 4, 0);
fp_loc = DWARF_LOC(frame - 12, 0);
}
else
{
/* Codesourcery optimized normal frame. */
ip_loc = DWARF_LOC(frame, 0);
fp_loc = DWARF_LOC(frame - 4, 0);
}
if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0)
{
return 0;
}
c->dwarf.loc[UNW_ARM_R12] = ip_loc;
c->dwarf.loc[UNW_ARM_R11] = fp_loc;
Debug(15, "ip=%lx\n", c->dwarf.ip);
}
else
{
ret = -UNW_ENOINFO;
}
}
}
return ret == -UNW_ENOINFO ? 0 : 1;
} }

View file

@ -50,3 +50,7 @@ _Uarm_getcontext:
str r1, [r0, #15 * 4] str r1, [r0, #15 * 4]
ldmfd sp!, {r0, r1} ldmfd sp!, {r0, r1}
bx lr bx lr
#ifdef __linux__
/* We do not need executable stack. */
.section .note.GNU-stack,"",%progbits
#endif

View file

@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
static inline int static inline int
common_init (struct cursor *c) common_init (struct cursor *c, unsigned use_prev_instr)
{ {
int ret, i; int ret, i;
@ -62,6 +62,7 @@ common_init (struct cursor *c)
c->dwarf.args_size = 0; c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0; c->dwarf.ret_addr_column = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0; c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0; c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0; c->dwarf.hint = 0;

View file

@ -6,3 +6,7 @@
_UI_siglongjmp_cont: _UI_siglongjmp_cont:
_UI_longjmp_cont: _UI_longjmp_cont:
bx lr bx lr
#ifdef __linux__
/* We do not need executable stack. */
.section .note.GNU-stack,"",%progbits
#endif

View file

@ -187,6 +187,9 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
break; break;
case 'S': case 'S':
/* This is a signal frame. */
dci->signal_frame = 1;
/* Temporarily set it to one so dwarf_parse_fde() knows that /* Temporarily set it to one so dwarf_parse_fde() knows that
it should fetch the actual ABI/TAG pair from the FDE. */ it should fetch the actual ABI/TAG pair from the FDE. */
dci->have_abi_marker = 1; dci->have_abi_marker = 1;
@ -293,7 +296,7 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
} }
Debug (15, "looking for CIE at address %x\n", (int) cie_addr); Debug (15, "looking for CIE at address %lx\n", (long) cie_addr);
if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0) if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0)
return ret; return ret;

View file

@ -186,8 +186,8 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
FILE *f; FILE *f;
Elf_W (Ehdr) ehdr; Elf_W (Ehdr) ehdr;
Elf_W (Half) shstrndx; Elf_W (Half) shstrndx;
Elf_W (Shdr) *sec_hdrs; Elf_W (Shdr) *sec_hdrs = NULL;
char *stringtab; char *stringtab = NULL;
unsigned int i; unsigned int i;
size_t linksize = 0; size_t linksize = 0;
char *linkbuf = NULL; char *linkbuf = NULL;
@ -200,7 +200,8 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
if (!f) if (!f)
return 1; return 1;
fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f); if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
goto file_error;
shstrndx = ehdr.e_shstrndx; shstrndx = ehdr.e_shstrndx;
@ -209,13 +210,15 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
fseek (f, ehdr.e_shoff, SEEK_SET); fseek (f, ehdr.e_shoff, SEEK_SET);
sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr))); sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f); if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum)
goto file_error;
Debug (4, "loading string table of size %zd\n", Debug (4, "loading string table of size %zd\n",
sec_hdrs[shstrndx].sh_size); sec_hdrs[shstrndx].sh_size);
stringtab = malloc (sec_hdrs[shstrndx].sh_size); stringtab = malloc (sec_hdrs[shstrndx].sh_size);
fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET); fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f); if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size)
goto file_error;
for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++) for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
{ {
@ -227,21 +230,23 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
*buf = malloc (*bufsize); *buf = malloc (*bufsize);
fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
fread (*buf, 1, *bufsize, f); if (fread (*buf, 1, *bufsize, f) != *bufsize)
goto file_error;
Debug (4, "read %zd bytes of .debug_frame from offset %zd\n", Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
*bufsize, sec_hdrs[i].sh_offset); *bufsize, sec_hdrs[i].sh_offset);
} }
else if (is_local >= 0 && strcmp (secname, ".gnu_debuglink") == 0) else if (strcmp (secname, ".gnu_debuglink") == 0)
{ {
linksize = sec_hdrs[i].sh_size; linksize = sec_hdrs[i].sh_size;
linkbuf = malloc (linksize); linkbuf = malloc (linksize);
fseek (f, sec_hdrs[i].sh_offset, SEEK_SET); fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
fread (linkbuf, 1, linksize, f); if (fread (linkbuf, 1, linksize, f) != linksize)
goto file_error;
Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n", Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n",
*bufsize, sec_hdrs[i].sh_offset); linksize, sec_hdrs[i].sh_offset);
} }
} }
@ -250,6 +255,13 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
fclose (f); fclose (f);
/* Ignore separate debug files which contain a .gnu_debuglink section. */
if (linkbuf && is_local == -1)
{
free (linkbuf);
return 1;
}
if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL) if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
{ {
char *newname, *basedir, *p; char *newname, *basedir, *p;
@ -298,15 +310,16 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
free (linkbuf); free (linkbuf);
return 0; return 0;
}
#else /* An error reading image file. Release resources and return error code */
static int file_error:
load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local) if (stringtab) free(stringtab);
{ if (sec_hdrs) free(sec_hdrs);
if (linkbuf) free(linkbuf);
fclose(f);
return 1; return 1;
} }
#endif /* CONFIG_DEBUG_FRAME */
/* Locate the binary which originated the contents of address ADDR. Return /* Locate the binary which originated the contents of address ADDR. Return
the name of the binary in *name (space is allocated by the caller) the name of the binary in *name (space is allocated by the caller)
@ -322,10 +335,16 @@ find_binary_for_address (unw_word_t ip, char *name, size_t name_size)
unsigned long segbase, mapoff, hi; unsigned long segbase, mapoff, hi;
maps_init (&mi, pid); maps_init (&mi, pid);
while (maps_next (&mi, &segbase, &hi, &mapoff, name, name_size)) while (maps_next (&mi, &segbase, &hi, &mapoff))
if (ip >= segbase && ip < hi) if (ip >= segbase && ip < hi)
{ {
found = 1; size_t len = strlen (mi.path);
if (len + 1 <= name_size)
{
memcpy (name, mi.path, len + 1);
found = 1;
}
break; break;
} }
maps_close (&mi); maps_close (&mi);
@ -355,7 +374,7 @@ locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
for (w = as->debug_frames; w; w = w->next) for (w = as->debug_frames; w; w = w->next)
{ {
Debug (4, "checking %p: %x-%x\n", w, (int)w->start, (int)w->end); Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
if (addr >= w->start && addr < w->end) if (addr >= w->start && addr < w->end)
return w; return w;
} }
@ -396,7 +415,7 @@ locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
end = hdrlimit; end = hdrlimit;
} }
Debug (4, "calculated bounds of %x-%x for '%s'\n", (int)start, (int)end, Debug (4, "calculated bounds of %lx-%lx for '%s'\n", (long)start, (long)end,
name); name);
err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
@ -478,6 +497,154 @@ debug_frame_tab_compare (const void *a, const void *b)
return 0; return 0;
} }
PROTECTED int
dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug,
struct dl_phdr_info *info, unw_word_t ip)
{
unw_dyn_info_t *di;
struct unw_debug_frame_list *fdesc = 0;
unw_accessors_t *a;
unw_word_t addr;
Debug (15, "Trying to find .debug_frame info->dlpi_name=%s\n",
info->dlpi_name);
di = di_debug;
fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name);
if (!fdesc)
{
Debug (15, "couldn't load .debug_frame\n");
return found;
}
else
{
char *buf;
size_t bufsize;
unw_word_t item_start, item_end = 0;
uint32_t u32val = 0;
uint64_t cie_id = 0;
struct debug_frame_tab *tab;
Debug (15, "loaded .debug_frame\n");
buf = fdesc->debug_frame;
bufsize = fdesc->debug_frame_size;
if (bufsize == 0)
{
Debug (15, "zero-length .debug_frame\n");
return found;
}
/* Now create a binary-search table, if it does not already exist. */
if (!fdesc->index)
{
addr = (unw_word_t) (uintptr_t) buf;
a = unw_get_accessors (unw_local_addr_space);
/* Find all FDE entries in debug_frame, and make into a sorted
index. */
tab = debug_frame_tab_new (16);
while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
{
uint64_t id_for_cie;
item_start = addr;
dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
if (u32val == 0)
break;
else if (u32val != 0xffffffff)
{
uint32_t cie_id32 = 0;
item_end = addr + u32val;
dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
NULL);
cie_id = cie_id32;
id_for_cie = 0xffffffff;
}
else
{
uint64_t u64val = 0;
/* Extended length. */
dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
item_end = addr + u64val;
dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
id_for_cie = 0xffffffffffffffffull;
}
/*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
if (cie_id == id_for_cie)
;
/*Debug (1, "Found CIE at %.8x.\n", item_start);*/
else
{
unw_word_t fde_addr = item_start;
unw_proc_info_t this_pi;
int err;
/*Debug (1, "Found FDE at %.8x\n", item_start);*/
err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
a, &fde_addr,
&this_pi, 0,
(uintptr_t) buf,
NULL);
if (err == 0)
{
Debug (15, "start_ip = %lx, end_ip = %lx\n",
(long) this_pi.start_ip, (long) this_pi.end_ip);
debug_frame_tab_append (tab,
item_start - (unw_word_t) (uintptr_t) buf,
this_pi.start_ip);
}
/*else
Debug (1, "FDE parse failed\n");*/
}
addr = item_end;
}
debug_frame_tab_shrink (tab);
qsort (tab->tab, tab->length, sizeof (struct table_entry),
debug_frame_tab_compare);
/* for (i = 0; i < tab->length; i++)
{
fprintf (stderr, "ip %x, fde offset %x\n",
(int) tab->tab[i].start_ip_offset,
(int) tab->tab[i].fde_offset);
}*/
fdesc->index = tab->tab;
fdesc->index_size = tab->length;
free (tab);
}
di->format = UNW_INFO_FORMAT_TABLE;
di->start_ip = fdesc->start;
di->end_ip = fdesc->end;
di->u.ti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
di->u.ti.table_data = (unw_word_t *) fdesc;
di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
di->u.ti.segbase = (unw_word_t) (uintptr_t) info->dlpi_addr;
found = 1;
Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
"gp=0x%lx, table_data=0x%lx\n",
(char *) (uintptr_t) di->u.ti.name_ptr,
(long) di->u.ti.segbase, (long) di->u.ti.table_len,
(long) di->gp, (long) di->u.ti.table_data);
}
return found;
}
#endif /* CONFIG_DEBUG_FRAME */
/* ptr is a pointer to a callback_data structure and, on entry, /* ptr is a pointer to a callback_data structure and, on entry,
member ip contains the instruction-pointer we're looking member ip contains the instruction-pointer we're looking
for. */ for. */
@ -492,7 +659,6 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
struct dwarf_eh_frame_hdr *hdr; struct dwarf_eh_frame_hdr *hdr;
unw_accessors_t *a; unw_accessors_t *a;
long n; long n;
struct unw_debug_frame_list *fdesc = 0;
int found = 0; int found = 0;
ip = cb_data->ip; ip = cb_data->ip;
@ -595,144 +761,13 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
return 1; return 1;
} }
Debug (15, "Trying to find .debug_frame\n"); #ifdef CONFIG_DEBUG_FRAME
fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name);
if (!fdesc)
{
Debug (15, "couldn't load .debug_frame\n");
return 0;
}
{ {
char *buf; found = dwarf_find_debug_frame (found, &cb_data->di_debug, info, ip);
size_t bufsize;
unw_word_t item_start, item_end = 0;
uint32_t u32val = 0;
uint64_t cie_id = 0;
struct debug_frame_tab *tab;
int err;
unw_word_t fde_addr;
Debug (15, "loaded .debug_frame\n");
buf = fdesc->debug_frame;
bufsize = fdesc->debug_frame_size;
if (bufsize == 0)
{
Debug (15, "zero-length .debug_frame\n");
return found;
}
/* Now create a binary-search table, if it does not already exist. */
if (!fdesc->index)
{
addr = (unw_word_t) (uintptr_t) buf;
a = unw_get_accessors (unw_local_addr_space);
/* Find all FDE entries in debug_frame, and make into a sorted
index. */
tab = debug_frame_tab_new (16);
while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
{
uint64_t id_for_cie;
item_start = addr;
dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
if (u32val == 0)
break;
else if (u32val != 0xffffffff)
{
uint32_t cie_id32 = 0;
item_end = addr + u32val;
dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
NULL);
cie_id = cie_id32;
id_for_cie = 0xffffffff;
}
else
{
uint64_t u64val = 0;
/* Extended length. */
dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
item_end = addr + u64val;
dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
id_for_cie = 0xffffffffffffffffull;
}
/*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
if (cie_id == id_for_cie)
;
/*Debug (1, "Found CIE at %.8x.\n", item_start);*/
else
{
unw_word_t fde_addr = item_start;
unw_proc_info_t this_pi;
int err;
/*Debug (1, "Found FDE at %.8x\n", item_start);*/
err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
a, &fde_addr,
&this_pi, 0,
(uintptr_t) buf,
NULL);
if (err == 0)
{
Debug (15, "start_ip = %x, end_ip = %x\n",
(int) this_pi.start_ip, (int) this_pi.end_ip);
debug_frame_tab_append (tab,
item_start - (unw_word_t) (uintptr_t) buf,
this_pi.start_ip);
}
/*else
Debug (1, "FDE parse failed\n");*/
}
addr = item_end;
}
debug_frame_tab_shrink (tab);
qsort (tab->tab, tab->length, sizeof (struct table_entry),
debug_frame_tab_compare);
/* for (i = 0; i < tab->length; i++)
{
fprintf (stderr, "ip %x, fde offset %x\n",
(int) tab->tab[i].start_ip_offset,
(int) tab->tab[i].fde_offset);
}*/
fdesc->index = tab->tab;
fdesc->index_size = tab->length;
free (tab);
}
Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
"gp=0x%lx, table_data=0x%lx\n",
(char *) (uintptr_t) info->dlpi_name,
(unw_word_t) (uintptr_t) info->dlpi_addr,
(long) sizeof (*fdesc) / sizeof (unw_word_t),
(long) cb_data->gp, (long) fdesc);
err = dwarf_search_unwind_table_local (unw_local_addr_space, cb_data->ip, fdesc,
(unw_word_t) (uintptr_t) info->dlpi_addr,
&cb_data->fde_addr,
cb_data->arg);
if(err < 0)
return err;
/* .debug_frame uses an absolute encoding that does not know about any
shared library relocation. */
cb_data->ip_offset = segbase;
cb_data->fde_base = (uintptr_t) fdesc->debug_frame;
return 1;
} }
#endif /* CONFIG_DEBUG_FRAME */
return found;
} }
static int static int
@ -747,9 +782,9 @@ find_proc_fde (unw_word_t ip, unw_word_t *fde_addr,
cb_data.ip = ip; cb_data.ip = ip;
cb_data.arg = arg; cb_data.arg = arg;
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
ret = dl_iterate_phdr (callback, &cb_data); ret = dl_iterate_phdr (callback, &cb_data);
sigprocmask (SIG_SETMASK, &saved_mask, NULL); SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -865,7 +900,7 @@ lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
{ {
mid = (lo + hi) / 2; mid = (lo + hi) / 2;
e = table + mid; e = table + mid;
Debug (1, "e->start_ip_offset = %x\n", (int) e->start_ip_offset); Debug (1, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset);
if (rel_ip < e->start_ip_offset) if (rel_ip < e->start_ip_offset)
hi = mid; hi = mid;
else else
@ -1043,13 +1078,11 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
#ifndef UNW_REMOTE_ONLY #ifndef UNW_REMOTE_ONLY
struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
/* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is currently only /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
supported for the local address space. Both the index and space. Both the index and the unwind tables live in local memory, but
the unwind tables live in local memory, but the address space the address space to check for properties like the address size and
to check for properties like the address size and endianness endianness is the target one. */
is the target one. When the ptrace code adds support for as = unw_local_addr_space;
.debug_frame something will have to change. */
assert (as == unw_local_addr_space);
table = fdesc->index; table = fdesc->index;
table_len = fdesc->index_size * sizeof (struct table_entry); table_len = fdesc->index_size * sizeof (struct table_entry);
debug_frame_base = (uintptr_t) fdesc->debug_frame; debug_frame_base = (uintptr_t) fdesc->debug_frame;
@ -1080,8 +1113,8 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
} }
if (!e) if (!e)
{ {
Debug (1, "IP %x inside range %x-%x, but no explicit unwind info found\n", Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
(int) ip, (int) di->start_ip, (int) di->end_ip); (long) ip, (long) di->start_ip, (long) di->end_ip);
/* IP is inside this table's range, but there is no explicit /* IP is inside this table's range, but there is no explicit
unwind info. */ unwind info. */
return -UNW_ENOINFO; return -UNW_ENOINFO;
@ -1092,9 +1125,9 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
fde_addr = e->fde_offset + debug_frame_base; fde_addr = e->fde_offset + debug_frame_base;
else else
fde_addr = e->fde_offset + segbase; fde_addr = e->fde_offset + segbase;
Debug (1, "e->fde_offset = %x, segbase = %x, debug_frame_base = %x, " Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
"fde_addr = %x\n", (int) e->fde_offset, (int) segbase, "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
(int) debug_frame_base, (int) fde_addr); (long) debug_frame_base, (long) fde_addr);
if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
need_unwind_info, need_unwind_info,
debug_frame_base, arg)) < 0) debug_frame_base, arg)) < 0)
@ -1106,6 +1139,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
{ {
pi->start_ip += segbase; pi->start_ip += segbase;
pi->end_ip += segbase; pi->end_ip += segbase;
pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
} }
if (ip < pi->start_ip || ip >= pi->end_ip) if (ip < pi->start_ip || ip >= pi->end_ip)

View file

@ -73,10 +73,19 @@ run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
as = c->as; as = c->as;
arg = c->as_arg; arg = c->as_arg;
if (c->pi.flags & UNW_PI_FLAG_DEBUG_FRAME)
{
/* .debug_frame CFI is stored in local address space. */
as = unw_local_addr_space;
arg = NULL;
}
a = unw_get_accessors (as); a = unw_get_accessors (as);
curr_ip = c->pi.start_ip; curr_ip = c->pi.start_ip;
while (curr_ip < ip && *addr < end_addr) /* Process everything up to and including the current 'ip',
including all the DW_CFA_advance_loc instructions. See
'c->use_prev_instr' use in 'fetch_proc_info' for details. */
while (curr_ip <= ip && *addr < end_addr)
{ {
if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0) if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
return ret; return ret;
@ -381,7 +390,23 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
{ {
int ret, dynamic = 1; int ret, dynamic = 1;
--ip; /* The 'ip' can point either to the previous or next instruction
depending on what type of frame we have: normal call or a place
to resume execution (e.g. after signal frame).
For a normal call frame we need to back up so we point within the
call itself; this is important because a) the call might be the
very last instruction of the function and the edge of the FDE,
and b) so that run_cfi_program() runs locations up to the call
but not more.
For execution resume, we need to do the exact opposite and look
up using the current 'ip' value. That is where execution will
continue, and it's important we get this right, as 'ip' could be
right at the function entry and hence FDE edge, or at instruction
that manipulates CFA (push/pop). */
if (c->use_prev_instr)
--ip;
if (c->pi_valid && !need_unwind_info) if (c->pi_valid && !need_unwind_info)
return 0; return 0;
@ -400,6 +425,19 @@ fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
c->pi_valid = 1; c->pi_valid = 1;
c->pi_is_dynamic = dynamic; c->pi_is_dynamic = dynamic;
/* Let system/machine-dependent code determine frame-specific attributes. */
if (ret >= 0)
tdep_fetch_frame (c, ip, need_unwind_info);
/* Update use_prev_instr for the next frame. */
if (need_unwind_info)
{
assert(c->pi.unwind_info);
struct dwarf_cie_info *dci = c->pi.unwind_info;
c->use_prev_instr = ! dci->signal_frame;
}
return ret; return ret;
} }
@ -422,7 +460,7 @@ put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
if (c->pi_is_dynamic) if (c->pi_is_dynamic)
unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg); unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
else if (pi->unwind_info); else if (pi->unwind_info)
{ {
mempool_free (&dwarf_cie_info_pool, pi->unwind_info); mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
pi->unwind_info = NULL; pi->unwind_info = NULL;
@ -481,22 +519,11 @@ get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
if (caching == UNW_CACHE_NONE) if (caching == UNW_CACHE_NONE)
return NULL; return NULL;
#ifdef HAVE_ATOMIC_H
if (!spin_trylock_irqsave (&cache->busy, *saved_maskp))
return NULL;
#else
# ifdef HAVE_ATOMIC_OPS_H
if (AO_test_and_set (&cache->busy) == AO_TS_SET)
return NULL;
# else
sigprocmask (SIG_SETMASK, &unwi_full_mask, saved_maskp);
if (likely (caching == UNW_CACHE_GLOBAL)) if (likely (caching == UNW_CACHE_GLOBAL))
{ {
Debug (16, "%s: acquiring lock\n", __FUNCTION__); Debug (16, "%s: acquiring lock\n", __FUNCTION__);
mutex_lock (&cache->lock); lock_acquire (&cache->lock, *saved_maskp);
} }
# endif
#endif
if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation)) if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
{ {
@ -514,17 +541,8 @@ put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache,
assert (as->caching_policy != UNW_CACHE_NONE); assert (as->caching_policy != UNW_CACHE_NONE);
Debug (16, "unmasking signals/interrupts and releasing lock\n"); Debug (16, "unmasking signals/interrupts and releasing lock\n");
#ifdef HAVE_ATOMIC_H
spin_unlock_irqrestore (&cache->busy, *saved_maskp);
#else
# ifdef HAVE_ATOMIC_OPS_H
AO_CLEAR (&cache->busy);
# else
if (likely (as->caching_policy == UNW_CACHE_GLOBAL)) if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
mutex_unlock (&cache->lock); lock_release (&cache->lock, *saved_maskp);
sigprocmask (SIG_SETMASK, saved_maskp, NULL);
# endif
#endif
} }
static inline unw_hash_index_t static inline unw_hash_index_t
@ -624,6 +642,8 @@ rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
rs->hint = 0; rs->hint = 0;
rs->ip = c->ip; rs->ip = c->ip;
rs->ret_addr_column = c->ret_addr_column; rs->ret_addr_column = c->ret_addr_column;
rs->signal_frame = 0;
tdep_cache_frame (c, rs);
return rs; return rs;
} }
@ -711,6 +731,7 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
stack-pointer wasn't saved, popping the CFA implicitly pops stack-pointer wasn't saved, popping the CFA implicitly pops
the stack-pointer as well. */ the stack-pointer as well. */
if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP) if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP)
&& (UNW_TDEP_SP < ARRAY_SIZE(rs->reg))
&& (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME)) && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME))
cfa = c->cfa; cfa = c->cfa;
else else
@ -762,13 +783,20 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
break; break;
} }
} }
c->cfa = cfa;
ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
if (ret < 0)
return ret;
c->ip = ip;
/* XXX: check for ip to be code_aligned */
c->cfa = cfa;
/* DWARF spec says undefined return address location means end of stack. */
if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column]))
c->ip = 0;
else
{
ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
if (ret < 0)
return ret;
c->ip = ip;
}
/* XXX: check for ip to be code_aligned */
if (c->ip == prev_ip && c->cfa == prev_cfa) if (c->ip == prev_ip && c->cfa == prev_cfa)
{ {
Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
@ -803,7 +831,7 @@ HIDDEN int
dwarf_find_save_locs (struct dwarf_cursor *c) dwarf_find_save_locs (struct dwarf_cursor *c)
{ {
dwarf_state_record_t sr; dwarf_state_record_t sr;
dwarf_reg_state_t *rs, *rs1; dwarf_reg_state_t *rs, rs_copy;
struct dwarf_rs_cache *cache; struct dwarf_rs_cache *cache;
int ret = 0; int ret = 0;
intrmask_t saved_mask; intrmask_t saved_mask;
@ -812,49 +840,37 @@ dwarf_find_save_locs (struct dwarf_cursor *c)
return uncached_dwarf_find_save_locs (c); return uncached_dwarf_find_save_locs (c);
cache = get_rs_cache(c->as, &saved_mask); cache = get_rs_cache(c->as, &saved_mask);
if (!cache)
return -UNW_ENOINFO; /* cache is busy */
rs = rs_lookup(cache, c); rs = rs_lookup(cache, c);
if (rs) if (rs)
{ {
c->ret_addr_column = rs->ret_addr_column; c->ret_addr_column = rs->ret_addr_column;
goto apply; c->use_prev_instr = ! rs->signal_frame;
} }
else
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
goto out;
if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
goto out;
rs1 = &sr.rs_current;
if (rs1)
{ {
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 ||
(ret = create_state_record_for (c, &sr, c->ip)) < 0)
{
put_rs_cache (c->as, cache, &saved_mask);
return ret;
}
rs = rs_new (cache, c); rs = rs_new (cache, c);
memcpy(rs, rs1, offsetof(struct dwarf_reg_state, ip)); memcpy(rs, &sr.rs_current, offsetof(struct dwarf_reg_state, ip));
if (!rs) cache->buckets[c->prev_rs].hint = rs - cache->buckets;
{
Dprintf ("%s: failed to create unwind rs\n", __FUNCTION__); c->hint = rs->hint;
ret = -UNW_EUNSPEC; c->prev_rs = rs - cache->buckets;
goto out;
} put_unwind_info (c, &c->pi);
} }
cache->buckets[c->prev_rs].hint = rs - cache->buckets;
c->hint = rs->hint; memcpy (&rs_copy, rs, sizeof (rs_copy));
c->prev_rs = rs - cache->buckets;
put_unwind_info (c, &c->pi);
ret = apply_reg_state (c, rs);
out:
put_rs_cache (c->as, cache, &saved_mask); put_rs_cache (c->as, cache, &saved_mask);
return ret;
apply: tdep_reuse_frame (c, &rs_copy);
put_rs_cache (c->as, cache, &saved_mask); if ((ret = apply_reg_state (c, &rs_copy)) < 0)
if ((ret = apply_reg_state (c, rs)) < 0)
return ret; return ret;
return 0; return 0;

View file

@ -29,7 +29,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
HIDDEN int HIDDEN int
dwarf_step (struct dwarf_cursor *c) dwarf_step (struct dwarf_cursor *c)
{ {
unw_word_t prev_cfa = c->cfa;
int ret; int ret;
if ((ret = dwarf_find_save_locs (c)) >= 0) { if ((ret = dwarf_find_save_locs (c)) >= 0) {

View file

@ -1,7 +1,9 @@
#ifndef elf32_h #ifndef elf32_h
#define elf32_h #define elf32_h
#ifndef ELF_CLASS
#define ELF_CLASS ELFCLASS32 #define ELF_CLASS ELFCLASS32
#endif
#include "elfxx.h" #include "elfxx.h"
#endif /* elf32_h */ #endif /* elf32_h */

View file

@ -1,7 +1,9 @@
#ifndef elf64_h #ifndef elf64_h
#define elf64_h #define elf64_h
#ifndef ELF_CLASS
#define ELF_CLASS ELFCLASS64 #define ELF_CLASS ELFCLASS64
#endif
#include "elfxx.h" #include "elfxx.h"
#endif /* elf64_h */ #endif /* elf64_h */

View file

@ -25,6 +25,7 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h> #include <stdio.h>
#include <sys/param.h>
#include "libunwind_i.h" #include "libunwind_i.h"
@ -147,7 +148,7 @@ elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
Elf_W (Phdr) *phdr; Elf_W (Phdr) *phdr;
int i, ret; int i, ret;
ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff); ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff, NULL, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;

View file

@ -35,8 +35,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&hppa_lock, saved_mask);
mutex_lock (&hppa_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -52,6 +51,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&hppa_lock); lock_release (&hppa_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -48,7 +48,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space; c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc; c->dwarf.as_arg = uc;
return common_init (c); return common_init (c, 1);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */

View file

@ -41,6 +41,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as = as; c->dwarf.as = as;
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
return common_init (c); return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */ #endif /* !UNW_LOCAL_ONLY */
} }

View file

@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
static inline int static inline int
common_init (struct cursor *c) common_init (struct cursor *c, unsigned use_prev_instr)
{ {
int ret; int ret;
@ -40,5 +40,7 @@ common_init (struct cursor *c)
ret = hppa_get (c, HPPA_REG_LOC (c, UNW_HPPA_SP), &c->sp); ret = hppa_get (c, HPPA_REG_LOC (c, UNW_HPPA_SP), &c->sp);
if (ret < 0) if (ret < 0)
return ret; return ret;
c->dwarf.use_prev_instr = use_prev_instr;
return 0; return 0;
} }

View file

@ -71,8 +71,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&unw.lock, saved_mask);
mutex_lock (&unw.lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -120,6 +119,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&unw.lock); lock_release (&unw.lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -113,11 +113,10 @@ get_script_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
if (AO_test_and_set (&cache->busy) == AO_TS_SET) if (AO_test_and_set (&cache->busy) == AO_TS_SET)
return NULL; return NULL;
# else # else
sigprocmask (SIG_SETMASK, &unwi_full_mask, saved_maskp);
if (likely (caching == UNW_CACHE_GLOBAL)) if (likely (caching == UNW_CACHE_GLOBAL))
{ {
Debug (16, "%s: acquiring lock\n", __FUNCTION__); Debug (16, "%s: acquiring lock\n", __FUNCTION__);
mutex_lock (&cache->lock); lock_acquire (&cache->lock, *saved_maskp);
} }
# endif # endif
#endif #endif
@ -144,8 +143,7 @@ put_script_cache (unw_addr_space_t as, struct ia64_script_cache *cache,
AO_CLEAR (&cache->busy); AO_CLEAR (&cache->busy);
# else # else
if (likely (as->caching_policy == UNW_CACHE_GLOBAL)) if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
mutex_unlock (&cache->lock); lock_release (&cache->lock, *saved_maskp);
sigprocmask (SIG_SETMASK, saved_maskp, NULL);
# endif # endif
#endif #endif
} }

View file

@ -622,9 +622,9 @@ validate_cache (unw_addr_space_t as)
intrmask_t saved_mask; intrmask_t saved_mask;
int ret; int ret;
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
ret = dl_iterate_phdr (check_callback, as); ret = dl_iterate_phdr (check_callback, as);
sigprocmask (SIG_SETMASK, &saved_mask, NULL); SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
return ret; return ret;
} }
@ -653,9 +653,9 @@ tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip,
di.u.ti.segbase = ip; /* this is cheap... */ di.u.ti.segbase = ip; /* this is cheap... */
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
ret = dl_iterate_phdr (callback, &di); ret = dl_iterate_phdr (callback, &di);
sigprocmask (SIG_SETMASK, &saved_mask, NULL); SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
if (ret <= 0) if (ret <= 0)
{ {

View file

@ -119,6 +119,8 @@ typedef struct unw_addr_space *unw_addr_space_t;
/* Each target may define it's own set of flags, but bits 0-15 are /* Each target may define it's own set of flags, but bits 0-15 are
reserved for general libunwind-use. */ reserved for general libunwind-use. */
#define UNW_PI_FLAG_FIRST_TDEP_BIT 16 #define UNW_PI_FLAG_FIRST_TDEP_BIT 16
/* The information comes from a .debug_frame section. */
#define UNW_PI_FLAG_DEBUG_FRAME 32
typedef struct unw_proc_info typedef struct unw_proc_info
{ {
@ -220,6 +222,7 @@ unw_save_loc_t;
#define unw_set_fpreg UNW_OBJ(set_fpreg) #define unw_set_fpreg UNW_OBJ(set_fpreg)
#define unw_get_save_loc UNW_OBJ(get_save_loc) #define unw_get_save_loc UNW_OBJ(get_save_loc)
#define unw_is_signal_frame UNW_OBJ(is_signal_frame) #define unw_is_signal_frame UNW_OBJ(is_signal_frame)
#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame)
#define unw_get_proc_name UNW_OBJ(get_proc_name) #define unw_get_proc_name UNW_OBJ(get_proc_name)
#define unw_set_caching_policy UNW_OBJ(set_caching_policy) #define unw_set_caching_policy UNW_OBJ(set_caching_policy)
#define unw_regname UNW_ARCH_OBJ(regname) #define unw_regname UNW_ARCH_OBJ(regname)
@ -246,6 +249,7 @@ extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *);
extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t); extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t);
extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *); extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *);
extern int unw_is_signal_frame (unw_cursor_t *); extern int unw_is_signal_frame (unw_cursor_t *);
extern int unw_handle_signal_frame (unw_cursor_t *);
extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *); extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *);
extern const char *unw_strerror (int); extern const char *unw_strerror (int);

View file

@ -44,8 +44,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&mips_lock, saved_mask);
mutex_lock (&mips_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -61,6 +60,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&mips_lock); lock_release (&mips_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -47,7 +47,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space; c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc; c->dwarf.as_arg = uc;
return common_init (c); return common_init (c, 1);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */

View file

@ -40,6 +40,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as = as; c->dwarf.as = as;
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
return common_init (c); return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */ #endif /* !UNW_LOCAL_ONLY */
} }

View file

@ -25,7 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
static inline int static inline int
common_init (struct cursor *c) common_init (struct cursor *c, unsigned use_prev_instr)
{ {
int ret, i; int ret, i;
@ -47,6 +47,7 @@ common_init (struct cursor *c)
c->dwarf.args_size = 0; c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0; c->dwarf.ret_addr_column = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0; c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0; c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0; c->dwarf.hint = 0;

101
src/os-freebsd.c Normal file
View file

@ -0,0 +1,101 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
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. */
#ifndef UNW_REMOTE_ONLY
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <stdio.h>
#include "libunwind_i.h"
static void *
get_mem(size_t sz)
{
void *res;
res = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (res == MAP_FAILED)
return (NULL);
return (res);
}
static void
free_mem(void *ptr, size_t sz)
{
munmap(ptr, sz);
}
PROTECTED int
tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff, char *path, size_t pathlen)
{
int mib[4], error, ret;
size_t len, len1;
char *buf, *bp, *eb;
struct kinfo_vmentry *kv;
len = 0;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_VMMAP;
mib[3] = pid;
error = sysctl(mib, 4, NULL, &len, NULL, 0);
if (error)
return (-1);
len1 = len * 4 / 3;
buf = get_mem(len1);
if (buf == NULL)
return (-1);
len = len1;
error = sysctl(mib, 4, buf, &len, NULL, 0);
if (error) {
free_mem(buf, len1);
return (-1);
}
ret = -1;
for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize) {
kv = (struct kinfo_vmentry *)(uintptr_t)bp;
if (ip < kv->kve_start || ip >= kv->kve_end)
continue;
if (kv->kve_type != KVME_TYPE_VNODE)
break;
*segbase = kv->kve_start;
*mapoff = kv->kve_offset;
if (path)
{
strncpy(path, kv->kve_path, pathlen);
}
ret = elf_map_image(ei, kv->kve_path);
break;
}
free_mem(buf, len1);
return (ret);
}
#endif /* UNW_REMOTE_ONLY */

View file

@ -26,6 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef UNW_REMOTE_ONLY #ifndef UNW_REMOTE_ONLY
#include <dlfcn.h> #include <dlfcn.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "libunwind_i.h" #include "libunwind_i.h"
@ -34,10 +35,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
HIDDEN int HIDDEN int
tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff) unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen);
{ {
struct load_module_desc lmd; struct load_module_desc lmd;
const char *path; const char *path2;
if (pid != getpid ()) if (pid != getpid ())
{ {
@ -51,10 +53,16 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
*segbase = lmd.text_base; *segbase = lmd.text_base;
*mapoff = 0; /* XXX fix me? */ *mapoff = 0; /* XXX fix me? */
path = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0); path2 = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0);
if (!path) if (!path2)
return -UNW_ENOINFO; return -UNW_ENOINFO;
if (path)
{
strncpy(path, path2, pathlen);
path[pathlen - 1] = '\0';
if (strcmp(path, path2) != 0)
Debug(1, "buffer size (%d) not big enough to hold path\n", pathlen);
}
Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", *segbase, *mapoff, path); Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", *segbase, *mapoff, path);
return elf_map_image (ei, path); return elf_map_image (ei, path);

View file

@ -33,26 +33,35 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
PROTECTED int PROTECTED int
tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip, tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff) unsigned long *segbase, unsigned long *mapoff,
char *path, size_t pathlen)
{ {
struct map_iterator mi; struct map_iterator mi;
char path[PATH_MAX]; int found = 0, rc;
int found = 0;
unsigned long hi; unsigned long hi;
maps_init (&mi, pid); if (maps_init (&mi, pid) < 0)
while (maps_next (&mi, segbase, &hi, mapoff, path, sizeof (path))) return -1;
while (maps_next (&mi, segbase, &hi, mapoff))
if (ip >= *segbase && ip < hi) if (ip >= *segbase && ip < hi)
{ {
found = 1; found = 1;
break; break;
} }
maps_close (&mi);
if (!found) if (!found)
return -1; {
maps_close (&mi);
return elf_map_image (ei, path); return -1;
}
if (path)
{
strncpy(path, mi.path, pathlen);
}
rc = elf_map_image (ei, mi.path);
maps_close (&mi);
return rc;
} }
#endif /* UNW_REMOTE_ONLY */ #endif /* UNW_REMOTE_ONLY */

View file

@ -34,6 +34,7 @@ struct map_iterator
size_t buf_size; size_t buf_size;
char *buf; char *buf;
char *buf_end; char *buf_end;
char *path;
}; };
static inline char * static inline char *
@ -61,33 +62,33 @@ ltoa (char *buf, long val)
return buf + len; return buf + len;
} }
static inline void static inline int
maps_init (struct map_iterator *mi, pid_t pid) maps_init (struct map_iterator *mi, pid_t pid)
{ {
char path[PATH_MAX], *cp; char path[sizeof ("/proc/0123456789/maps")], *cp;
memcpy (path, "/proc/", 6); memcpy (path, "/proc/", 6);
cp = ltoa (path + 6, pid); cp = ltoa (path + 6, pid);
assert (cp + 6 < path + sizeof (path));
memcpy (cp, "/maps", 6); memcpy (cp, "/maps", 6);
mi->fd = open (path, O_RDONLY); mi->fd = open (path, O_RDONLY);
mi->offset = 0;
mi->buf_size = 0;
cp = NULL;
if (mi->fd >= 0) if (mi->fd >= 0)
{ {
/* Try to allocate a page-sized buffer. If that fails, we'll /* Try to allocate a page-sized buffer. */
fall back on reading one line at a time. */
mi->buf_size = getpagesize (); mi->buf_size = getpagesize ();
cp = mmap (0, mi->buf_size, PROT_READ | PROT_WRITE, cp = mmap (0, mi->buf_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (cp == MAP_FAILED) if (cp == MAP_FAILED)
cp = NULL; return -1;
else else
cp += mi->buf_size; {
mi->offset = 0;
mi->buf = mi->buf_end = cp + mi->buf_size;
return 0;
}
} }
mi->buf = mi->buf_end = cp; return -1;
} }
static inline char * static inline char *
@ -184,7 +185,7 @@ scan_string (char *cp, char *valp, size_t buf_size)
while (*cp != ' ' && *cp != '\t' && *cp != '\0') while (*cp != ' ' && *cp != '\t' && *cp != '\0')
{ {
if (i < buf_size - 1) if ((valp != NULL) && (i < buf_size - 1))
valp[i++] = *cp; valp[i++] = *cp;
++cp; ++cp;
} }
@ -196,12 +197,10 @@ scan_string (char *cp, char *valp, size_t buf_size)
static inline int static inline int
maps_next (struct map_iterator *mi, maps_next (struct map_iterator *mi,
unsigned long *low, unsigned long *high, unsigned long *offset, unsigned long *low, unsigned long *high, unsigned long *offset)
char *path, size_t path_size)
{ {
char line[256 + PATH_MAX], perm[16], dash, colon, *cp; char perm[16], dash, colon, *cp;
unsigned long major, minor, inum; unsigned long major, minor, inum;
size_t to_read = 256; /* most lines fit in 256 characters easy */
ssize_t i, nread; ssize_t i, nread;
if (mi->fd < 0) if (mi->fd < 0)
@ -209,80 +208,52 @@ maps_next (struct map_iterator *mi,
while (1) while (1)
{ {
if (mi->buf) ssize_t bytes_left = mi->buf_end - mi->buf;
char *eol = NULL;
for (i = 0; i < bytes_left; ++i)
{ {
ssize_t bytes_left = mi->buf_end - mi->buf; if (mi->buf[i] == '\n')
char *eol = NULL;
for (i = 0; i < bytes_left; ++i)
{ {
if (mi->buf[i] == '\n') eol = mi->buf + i;
{ break;
eol = mi->buf + i;
break;
}
else if (mi->buf[i] == '\0')
break;
} }
if (!eol) else if (mi->buf[i] == '\0')
{ break;
/* copy down the remaining bytes, if any */
if (bytes_left > 0)
memmove (mi->buf_end - mi->buf_size, mi->buf, bytes_left);
mi->buf = mi->buf_end - mi->buf_size;
nread = read (mi->fd, mi->buf + bytes_left,
mi->buf_size - bytes_left);
if (nread <= 0)
return 0;
else if ((size_t) (nread + bytes_left) < mi->buf_size)
{
/* Move contents to the end of the buffer so we
maintain the invariant that all bytes between
mi->buf and mi->buf_end are valid. */
memmove (mi->buf_end - nread - bytes_left, mi->buf,
nread + bytes_left);
mi->buf = mi->buf_end - nread - bytes_left;
}
eol = mi->buf + bytes_left + nread - 1;
for (i = bytes_left; i < bytes_left + nread; ++i)
if (mi->buf[i] == '\n')
{
eol = mi->buf + i;
break;
}
}
cp = mi->buf;
mi->buf = eol + 1;
*eol = '\0';
} }
else if (!eol)
{ {
/* maps_init() wasn't able to allocate a buffer; do it the /* copy down the remaining bytes, if any */
slow way. */ if (bytes_left > 0)
lseek (mi->fd, mi->offset, SEEK_SET); memmove (mi->buf_end - mi->buf_size, mi->buf, bytes_left);
if ((nread = read (mi->fd, line, to_read)) <= 0) mi->buf = mi->buf_end - mi->buf_size;
nread = read (mi->fd, mi->buf + bytes_left,
mi->buf_size - bytes_left);
if (nread <= 0)
return 0; return 0;
for (i = 0; i < nread && line[i] != '\n'; ++i) else if ((size_t) (nread + bytes_left) < mi->buf_size)
/* skip */;
if (i < nread)
{ {
line[i] = '\0'; /* Move contents to the end of the buffer so we
mi->offset += i + 1; maintain the invariant that all bytes between
mi->buf and mi->buf_end are valid. */
memmove (mi->buf_end - nread - bytes_left, mi->buf,
nread + bytes_left);
mi->buf = mi->buf_end - nread - bytes_left;
} }
else
{ eol = mi->buf + bytes_left + nread - 1;
if (to_read < sizeof (line))
to_read = sizeof (line) - 1; for (i = bytes_left; i < bytes_left + nread; ++i)
else if (mi->buf[i] == '\n')
mi->offset += nread; /* not supposed to happen... */ {
continue; /* duh, no newline found */ eol = mi->buf + i;
} break;
cp = line; }
} }
cp = mi->buf;
mi->buf = eol + 1;
*eol = '\0';
/* scan: "LOW-HIGH PERM OFFSET MAJOR:MINOR INUM PATH" */ /* scan: "LOW-HIGH PERM OFFSET MAJOR:MINOR INUM PATH" */
cp = scan_hex (cp, low); cp = scan_hex (cp, low);
@ -294,8 +265,11 @@ maps_next (struct map_iterator *mi,
cp = scan_char (cp, &colon); cp = scan_char (cp, &colon);
cp = scan_hex (cp, &minor); cp = scan_hex (cp, &minor);
cp = scan_dec (cp, &inum); cp = scan_dec (cp, &inum);
cp = scan_string (cp, path, path_size); cp = mi->path = skip_whitespace (cp);
if (!cp || dash != '-' || colon != ':') if (!cp)
continue;
cp = scan_string (cp, NULL, 0);
if (dash != '-' || colon != ':')
continue; /* skip line with unknown or bad format */ continue; /* skip line with unknown or bad format */
return 1; return 1;
} }

View file

@ -56,9 +56,9 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space; c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc; c->dwarf.as_arg = uc;
#ifdef UNW_TARGET_PPC64 #ifdef UNW_TARGET_PPC64
return common_init_ppc64 (c); return common_init_ppc64 (c, 1);
#else #else
return common_init_ppc32 (c); return common_init_ppc32 (c, 1);
#endif #endif
} }

View file

@ -50,9 +50,9 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
#ifdef UNW_TARGET_PPC64 #ifdef UNW_TARGET_PPC64
return common_init_ppc64(c); return common_init_ppc64 (c, 0);
#elif UNW_TARGET_PPC32 #elif UNW_TARGET_PPC32
return common_init_ppc32 (c); return common_init_ppc32 (c, 0);
#else #else
#error init_remote :: NO VALID PPC ARCH! #error init_remote :: NO VALID PPC ARCH!
#endif #endif

View file

@ -115,8 +115,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&ppc32_lock, saved_mask);
mutex_lock (&ppc32_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -132,6 +131,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&ppc32_lock); lock_release (&ppc32_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -30,7 +30,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* Here is the "common" init, for remote and local debuging" */ /* Here is the "common" init, for remote and local debuging" */
static inline int static inline int
common_init_ppc32 (struct cursor *c) common_init_ppc32 (struct cursor *c, unsigned use_prev_instr)
{ {
int ret; int ret;
int i; int i;
@ -62,6 +62,7 @@ common_init_ppc32 (struct cursor *c)
c->dwarf.args_size = 0; c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0; c->dwarf.ret_addr_column = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0; c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0; c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0; c->dwarf.hint = 0;

View file

@ -162,8 +162,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&ppc64_lock, saved_mask);
mutex_lock (&ppc64_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -179,6 +178,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&ppc64_lock); lock_release (&ppc64_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
static inline int static inline int
common_init_ppc64 (struct cursor *c) common_init_ppc64 (struct cursor *c, unsigned use_prev_instr)
{ {
int ret; int ret;
int i; int i;
@ -72,6 +72,7 @@ common_init_ppc64 (struct cursor *c)
c->dwarf.args_size = 0; c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0; c->dwarf.ret_addr_column = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0; c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0; c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0; c->dwarf.hint = 0;

View file

@ -1,6 +1,7 @@
/* libunwind - a platform-independent unwind library /* libunwind - a platform-independent unwind library
Copyright (C) 2003 Hewlett-Packard Co Copyright (C) 2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com> Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
This file is part of libunwind. This file is part of libunwind.
@ -25,6 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h" #include "_UPT_internal.h"
#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
int int
_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg) int write, void *arg)
@ -64,3 +66,40 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
} }
return 0; return 0;
} }
#elif HAVE_DECL_PT_GETFPREGS
int
_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
struct UPT_info *ui = arg;
pid_t pid = ui->pid;
fpregset_t fpreg;
if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
return -UNW_EBADREG;
if (ptrace(PT_GETFPREGS, pid, (caddr_t)&fpreg, 0) == -1)
return -UNW_EBADREG;
if (write) {
#if defined(__amd64__)
memcpy(&fpreg.fpr_xacc[reg], val, sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t));
#else
#error Fix me
#endif
if (ptrace(PT_SETFPREGS, pid, (caddr_t)&fpreg, 0) == -1)
return -UNW_EBADREG;
} else
#if defined(__amd64__)
memcpy(val, &fpreg.fpr_xacc[reg], sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t));
#else
#error Fix me
#endif
return 0;
}
#else
#error Fix me
#endif

View file

@ -1,6 +1,7 @@
/* libunwind - a platform-independent unwind library /* libunwind - a platform-independent unwind library
Copyright (C) 2003-2004 Hewlett-Packard Co Copyright (C) 2003-2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com> Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
This file is part of libunwind. This file is part of libunwind.
@ -25,6 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h" #include "_UPT_internal.h"
#if HAVE_DECL_PTRACE_POKEDATA || HAVE_TTRACE
int int
_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, _UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
int write, void *arg) int write, void *arg)
@ -57,3 +59,27 @@ _UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
} }
return 0; return 0;
} }
#elif HAVE_DECL_PT_IO
int
_UPT_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
int write, void *arg)
{
struct UPT_info *ui = arg;
pid_t pid = ui->pid;
struct ptrace_io_desc iod;
iod.piod_offs = (void *)addr;
iod.piod_addr = val;
iod.piod_len = sizeof(*val);
iod.piod_op = write ? PIOD_WRITE_D : PIOD_READ_D;
if (write)
Debug (16, "mem[%lx] <- %lx\n", (long) addr, (long) *val);
if (ptrace(PT_IO, pid, (caddr_t)&iod, 0) == -1)
return -UNW_EINVAL;
if (!write)
Debug (16, "mem[%lx] -> %lx\n", (long) addr, (long) *val);
return 0;
}
#else
#error Fix me
#endif

View file

@ -1,6 +1,7 @@
/* libunwind - a platform-independent unwind library /* libunwind - a platform-independent unwind library
Copyright (C) 2003-2005 Hewlett-Packard Co Copyright (C) 2003-2005 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com> Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
This file is part of libunwind. This file is part of libunwind.
@ -33,6 +34,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
# include "tdep-ia64/rse.h" # include "tdep-ia64/rse.h"
#endif #endif
#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
int int
_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
int write, void *arg) int write, void *arg)
@ -252,3 +254,40 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
Debug (1, "bad register number %u (error: %s)\n", reg, strerror (errno)); Debug (1, "bad register number %u (error: %s)\n", reg, strerror (errno));
return -UNW_EBADREG; return -UNW_EBADREG;
} }
#elif HAVE_DECL_PT_GETREGS
int
_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
int write, void *arg)
{
struct UPT_info *ui = arg;
pid_t pid = ui->pid;
gregset_t regs;
char *r;
#if UNW_DEBUG
if (write)
Debug (16, "%s <- %lx\n", unw_regname (reg), (long) *val);
#endif
if ((unsigned) reg >= sizeof (_UPT_reg_offset) / sizeof (_UPT_reg_offset[0]))
{
errno = EINVAL;
goto badreg;
}
r = (char *)&regs + _UPT_reg_offset[reg];
if (ptrace(PT_GETREGS, pid, (caddr_t)&regs, 0) == -1)
goto badreg;
if (write) {
memcpy(r, val, sizeof(unw_word_t));
if (ptrace(PT_SETREGS, pid, (caddr_t)&regs, 0) == -1)
goto badreg;
} else
memcpy(val, r, sizeof(unw_word_t));
return 0;
badreg:
Debug (1, "bad register number %u (error: %s)\n", reg, strerror (errno));
return -UNW_EBADREG;
}
#else
#error Port me
#endif

View file

@ -26,7 +26,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h" #include "_UPT_internal.h"
void void
_UPT_destroy (void *ui) _UPT_destroy (void *ptr)
{ {
free (ui); struct UPT_info *ui = (struct UPT_info *) ptr;
if (ui->ei.image)
{
munmap(ui->ei.image, ui->ei.size);
}
free (ptr);
} }

View file

@ -97,7 +97,8 @@ find_gp (struct UPT_info *ui, Elf64_Phdr *pdyn, Elf64_Addr load_base)
HIDDEN unw_dyn_info_t * HIDDEN unw_dyn_info_t *
_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff) char *path, unw_word_t segbase, unw_word_t mapoff,
unw_word_t ip)
{ {
Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL; Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL;
Elf64_Ehdr *ehdr; Elf64_Ehdr *ehdr;
@ -165,10 +166,12 @@ dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a,
HIDDEN unw_dyn_info_t * HIDDEN unw_dyn_info_t *
_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff) char *path, unw_word_t segbase, unw_word_t mapoff,
unw_word_t ip)
{ {
Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL; Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL;
unw_word_t addr, eh_frame_start, fde_count, load_base; unw_word_t addr, eh_frame_start, fde_count, load_base;
unw_word_t max_load_addr = 0;
struct dwarf_eh_frame_hdr *hdr; struct dwarf_eh_frame_hdr *hdr;
unw_proc_info_t pi; unw_proc_info_t pi;
unw_accessors_t *a; unw_accessors_t *a;
@ -190,6 +193,8 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
case PT_LOAD: case PT_LOAD:
if (phdr[i].p_offset == mapoff) if (phdr[i].p_offset == mapoff)
ptxt = phdr + i; ptxt = phdr + i;
if ((uintptr_t) ui->ei.image + phdr->p_filesz > max_load_addr)
max_load_addr = (uintptr_t) ui->ei.image + phdr->p_filesz;
break; break;
case PT_GNU_EH_FRAME: case PT_GNU_EH_FRAME:
@ -205,7 +210,35 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
} }
} }
if (!ptxt || !peh_hdr) if (!ptxt || !peh_hdr)
#ifdef CONFIG_DEBUG_FRAME
{
/* No .eh_frame found, try .debug_frame. */
struct dl_phdr_info info;
info.dlpi_name = path;
info.dlpi_phdr = phdr;
info.dlpi_phnum = ehdr->e_phnum;
/* Fixup segbase to match correct base address. */
for (i = 0; i < info.dlpi_phnum; i++)
{
if (info.dlpi_phdr[i].p_type == PT_LOAD &&
info.dlpi_phdr[i].p_offset == 0)
{
segbase -= info.dlpi_phdr[i].p_vaddr;
break;
}
}
info.dlpi_addr = segbase;
if (dwarf_find_debug_frame (0, &ui->di_cache, &info, ip))
return &ui->di_cache;
else
return NULL;
}
#else
return NULL; return NULL;
#endif
if (pdyn) if (pdyn)
{ {
@ -262,16 +295,18 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
{ {
#if 1
abort (); abort ();
#if 0 #else
unw_word_t eh_frame_end;
/* If there is no search table or it has an unsupported /* If there is no search table or it has an unsupported
encoding, fall back on linear search. */ encoding, fall back on linear search. */
if (hdr->table_enc == DW_EH_PE_omit) if (hdr->table_enc == DW_EH_PE_omit)
Debug (4, "table `%s' lacks search table; doing linear search\n", Debug (4, "EH lacks search table; doing linear search\n");
info->dlpi_name);
else else
Debug (4, "table `%s' has encoding 0x%x; doing linear search\n", Debug (4, "EH table has encoding 0x%x; doing linear search\n",
info->dlpi_name, hdr->table_enc); hdr->table_enc);
eh_frame_end = max_load_addr; /* XXX can we do better? */ eh_frame_end = max_load_addr; /* XXX can we do better? */
@ -280,7 +315,6 @@ _UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as,
if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
abort (); abort ();
cb_data->single_fde = 1;
return linear_search (unw_local_addr_space, ip, return linear_search (unw_local_addr_space, ip,
eh_frame_start, eh_frame_end, fde_count, eh_frame_start, eh_frame_end, fde_count,
pi, need_unwind_info, NULL); pi, need_unwind_info, NULL);
@ -338,12 +372,13 @@ get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip)
ui->di_cache.start_ip = ui->di_cache.end_ip = 0; ui->di_cache.start_ip = ui->di_cache.end_ip = 0;
} }
if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff) < 0) if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff, path,
sizeof(path)) < 0)
return NULL; return NULL;
/* Here, SEGBASE is the starting-address of the (mmap'ped) segment /* Here, SEGBASE is the starting-address of the (mmap'ped) segment
which covers the IP we're looking for. */ which covers the IP we're looking for. */
di = _UPTi_find_unwind_table (ui, as, path, segbase, mapoff); di = _UPTi_find_unwind_table (ui, as, path, segbase, mapoff, ip);
if (!di if (!di
/* This can happen in corner cases where dynamically generated /* This can happen in corner cases where dynamically generated
code falls into the same page that contains the data-segment code falls into the same page that contains the data-segment

View file

@ -26,14 +26,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef _UPT_internal_h #ifndef _UPT_internal_h
#define _UPT_internal_h #define _UPT_internal_h
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/ptrace.h>
#ifdef HAVE_SYS_PROCFS_H
#include <sys/procfs.h>
#endif
#include <errno.h> #include <errno.h>
#include <libunwind-ptrace.h> #include <libunwind-ptrace.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/ptrace.h>
#include "libunwind_i.h" #include "libunwind_i.h"
struct UPT_info struct UPT_info
@ -52,6 +62,7 @@ extern unw_dyn_info_t *_UPTi_find_unwind_table (struct UPT_info *ui,
unw_addr_space_t as, unw_addr_space_t as,
char *path, char *path,
unw_word_t segbase, unw_word_t segbase,
unw_word_t mapoff); unw_word_t mapoff,
unw_word_t ip);
#endif /* _UPT_internal_h */ #endif /* _UPT_internal_h */

View file

@ -25,6 +25,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "_UPT_internal.h" #include "_UPT_internal.h"
#include <stddef.h>
#ifdef HAVE_ASM_PTRACE_OFFSETS_H #ifdef HAVE_ASM_PTRACE_OFFSETS_H
# include <asm/ptrace_offsets.h> # include <asm/ptrace_offsets.h>
#endif #endif
@ -247,6 +249,22 @@ int _UPT_reg_offset[UNW_REG_LAST + 1] =
[UNW_HPPA_IP] = 0x1a8 /* IAOQ[0] */ [UNW_HPPA_IP] = 0x1a8 /* IAOQ[0] */
#elif defined(UNW_TARGET_X86) #elif defined(UNW_TARGET_X86)
#if defined __FreeBSD__
#define UNW_R_OFF(R, r) \
[UNW_X86_##R] = offsetof(gregset_t, r_##r),
UNW_R_OFF(EAX, eax)
UNW_R_OFF(EDX, edx)
UNW_R_OFF(ECX, ecx)
UNW_R_OFF(EBX, ebx)
UNW_R_OFF(ESI, esi)
UNW_R_OFF(EDI, edi)
UNW_R_OFF(EBP, ebp)
UNW_R_OFF(ESP, esp)
UNW_R_OFF(EIP, eip)
// UNW_R_OFF(CS, cs)
// UNW_R_OFF(EFLAGS, eflags)
// UNW_R_OFF(SS, ss)
#elif defined __linux__
[UNW_X86_EAX] = 0x18, [UNW_X86_EAX] = 0x18,
[UNW_X86_EBX] = 0x00, [UNW_X86_EBX] = 0x00,
[UNW_X86_ECX] = 0x04, [UNW_X86_ECX] = 0x04,
@ -264,7 +282,35 @@ int _UPT_reg_offset[UNW_REG_LAST + 1] =
/* ORIG_EAX = 0x2c, */ /* ORIG_EAX = 0x2c, */
/* EFLAGS = 0x38, */ /* EFLAGS = 0x38, */
/* SS = 0x40 */ /* SS = 0x40 */
#else
#error Port me
#endif
#elif defined(UNW_TARGET_X86_64) #elif defined(UNW_TARGET_X86_64)
#if defined __FreeBSD__
#define UNW_R_OFF(R, r) \
[UNW_X86_64_##R] = offsetof(gregset_t, r_##r),
UNW_R_OFF(RAX, rax)
UNW_R_OFF(RDX, rdx)
UNW_R_OFF(RCX, rcx)
UNW_R_OFF(RBX, rbx)
UNW_R_OFF(RSI, rsi)
UNW_R_OFF(RDI, rdi)
UNW_R_OFF(RBP, rbp)
UNW_R_OFF(RSP, rsp)
UNW_R_OFF(R8, r8)
UNW_R_OFF(R9, r9)
UNW_R_OFF(R10, r10)
UNW_R_OFF(R11, r11)
UNW_R_OFF(R12, r12)
UNW_R_OFF(R13, r13)
UNW_R_OFF(R14, r14)
UNW_R_OFF(R15, r15)
UNW_R_OFF(RIP, rip)
// UNW_R_OFF(CS, cs)
// UNW_R_OFF(EFLAGS, rflags)
// UNW_R_OFF(SS, ss)
#undef UNW_R_OFF
#elif defined __linux__
[UNW_X86_64_RAX] = 0x50, [UNW_X86_64_RAX] = 0x50,
[UNW_X86_64_RDX] = 0x60, [UNW_X86_64_RDX] = 0x60,
[UNW_X86_64_RCX] = 0x58, [UNW_X86_64_RCX] = 0x58,
@ -286,9 +332,28 @@ int _UPT_reg_offset[UNW_REG_LAST + 1] =
// [UNW_X86_64_EFLAGS] = 0x90, // [UNW_X86_64_EFLAGS] = 0x90,
// [UNW_X86_64_RSP] = 0x98, // [UNW_X86_64_RSP] = 0x98,
// [UNW_X86_64_SS] = 0xa0 // [UNW_X86_64_SS] = 0xa0
#else
#error Port me
#endif
#elif defined(UNW_TARGET_PPC32) #elif defined(UNW_TARGET_PPC32)
#elif defined(UNW_TARGET_PPC64) #elif defined(UNW_TARGET_PPC64)
#elif defined(UNW_TARGET_ARM) #elif defined(UNW_TARGET_ARM)
[UNW_ARM_R0] = 0x00,
[UNW_ARM_R1] = 0x04,
[UNW_ARM_R2] = 0x08,
[UNW_ARM_R3] = 0x0c,
[UNW_ARM_R4] = 0x10,
[UNW_ARM_R5] = 0x14,
[UNW_ARM_R6] = 0x18,
[UNW_ARM_R7] = 0x1c,
[UNW_ARM_R8] = 0x20,
[UNW_ARM_R9] = 0x24,
[UNW_ARM_R10] = 0x28,
[UNW_ARM_R11] = 0x2c,
[UNW_ARM_R12] = 0x30,
[UNW_ARM_R13] = 0x34,
[UNW_ARM_R14] = 0x38,
[UNW_ARM_R15] = 0x3c,
#elif defined(UNW_TARGET_MIPS) #elif defined(UNW_TARGET_MIPS)
#else #else
# error Fix me. # error Fix me.

View file

@ -32,7 +32,9 @@ _UPT_resume (unw_addr_space_t as, unw_cursor_t *c, void *arg)
#ifdef HAVE_TTRACE #ifdef HAVE_TTRACE
# warning No support for ttrace() yet. # warning No support for ttrace() yet.
#else #elif HAVE_DECL_PTRACE_CONT
return ptrace (PTRACE_CONT, ui->pid, 0, 0); return ptrace (PTRACE_CONT, ui->pid, 0, 0);
#elif HAVE_DECL_PT_CONTINUE
return ptrace(PT_CONTINUE, ui->pid, (caddr_t)1, 0);
#endif #endif
} }

View file

@ -50,7 +50,11 @@ _longjmp (jmp_buf env, int val)
{ {
if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
abort (); abort ();
#ifdef __FreeBSD__
if (sp != wp[JB_SP] + sizeof(unw_word_t))
#else
if (sp != wp[JB_SP]) if (sp != wp[JB_SP])
#endif
continue; continue;
if (!bsp_match (&c, wp)) if (!bsp_match (&c, wp))

View file

@ -31,6 +31,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "jmpbuf.h" #include "jmpbuf.h"
#include "setjmp_i.h" #include "setjmp_i.h"
#if !defined(_NSIG) && defined(_SIG_MAXSIG)
# define _NSIG (_SIG_MAXSIG - 1)
#endif
void void
siglongjmp (sigjmp_buf env, int val) siglongjmp (sigjmp_buf env, int val)
{ {
@ -49,7 +53,11 @@ siglongjmp (sigjmp_buf env, int val)
{ {
if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
abort (); abort ();
#ifdef __FreeBSD__
if (sp != wp[JB_SP] + sizeof(unw_word_t))
#else
if (sp != wp[JB_SP]) if (sp != wp[JB_SP])
#endif
continue; continue;
if (!bsp_match (&c, wp)) if (!bsp_match (&c, wp))

View file

@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
PROTECTED _Unwind_Reason_Code PROTECTED _Unwind_Reason_Code
_Unwind_RaiseException (struct _Unwind_Exception *exception_object) _Unwind_RaiseException (struct _Unwind_Exception *exception_object)
{ {
unsigned long exception_class = exception_object->exception_class; uint64_t exception_class = exception_object->exception_class;
_Unwind_Personality_Fn personality; _Unwind_Personality_Fn personality;
struct _Unwind_Context context; struct _Unwind_Context context;
_Unwind_Reason_Code reason; _Unwind_Reason_Code reason;

View file

@ -24,11 +24,17 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind-internal.h" #include "unwind-internal.h"
#ifdef UNW_TARGET_X86
#include "dwarf_i.h"
#endif
PROTECTED void PROTECTED void
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_SetGR (struct _Unwind_Context *context, int index,
unsigned long new_value) unsigned long new_value)
{ {
#ifdef UNW_TARGET_X86
index = dwarf_to_unw_regnum(index);
#endif
unw_set_reg (&context->cursor, index, new_value); unw_set_reg (&context->cursor, index, new_value);
#ifdef UNW_TARGET_IA64 #ifdef UNW_TARGET_IA64
if (index >= UNW_IA64_GR && index <= UNW_IA64_GR + 127) if (index >= UNW_IA64_GR && index <= UNW_IA64_GR + 127)

View file

@ -38,7 +38,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define _U_VERSION 1 #define _U_VERSION 1
typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn) typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)
(int, _Unwind_Action, unsigned long, struct _Unwind_Exception *, (int, _Unwind_Action, uint64_t, struct _Unwind_Exception *,
struct _Unwind_Context *); struct _Unwind_Context *);
struct _Unwind_Context { struct _Unwind_Context {
@ -59,7 +59,7 @@ _Unwind_Phase2 (struct _Unwind_Exception *exception_object,
struct _Unwind_Context *context) struct _Unwind_Context *context)
{ {
_Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) exception_object->private_1; _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) exception_object->private_1;
unsigned long exception_class = exception_object->exception_class; uint64_t exception_class = exception_object->exception_class;
void *stop_parameter = (void *) exception_object->private_2; void *stop_parameter = (void *) exception_object->private_2;
_Unwind_Personality_Fn personality; _Unwind_Personality_Fn personality;
_Unwind_Reason_Code reason; _Unwind_Reason_Code reason;

View file

@ -27,6 +27,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
#if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN)
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#endif
PROTECTED unw_addr_space_t PROTECTED unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order) unw_create_addr_space (unw_accessors_t *a, int byte_order)
{ {

View file

@ -47,8 +47,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&x86_lock, saved_mask);
mutex_lock (&x86_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -64,6 +63,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&x86_lock); lock_release (&x86_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -24,6 +24,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -40,43 +44,12 @@ static struct unw_addr_space local_addr_space;
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_GS: addr = &uc->uc_mcontext.gregs[REG_GS]; break;
case UNW_X86_FS: addr = &uc->uc_mcontext.gregs[REG_FS]; break;
case UNW_X86_ES: addr = &uc->uc_mcontext.gregs[REG_ES]; break;
case UNW_X86_DS: addr = &uc->uc_mcontext.gregs[REG_DS]; break;
case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
case UNW_X86_CS: addr = &uc->uc_mcontext.gregs[REG_CS]; break;
case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
case UNW_X86_SS: addr = &uc->uc_mcontext.gregs[REG_SS]; break;
default:
addr = NULL;
}
return addr;
}
# ifdef UNW_LOCAL_ONLY # ifdef UNW_LOCAL_ONLY
HIDDEN void * HIDDEN void *
tdep_uc_addr (ucontext_t *uc, int reg) tdep_uc_addr (ucontext_t *uc, int reg)
{ {
return uc_addr (uc, reg); return x86_r_uc_addr (uc, reg);
} }
# endif /* UNW_LOCAL_ONLY */ # endif /* UNW_LOCAL_ONLY */
@ -114,16 +87,32 @@ static int
validate_mem (unw_word_t addr) validate_mem (unw_word_t addr)
{ {
int i, victim; int i, victim;
#ifdef HAVE_MINCORE
unsigned char mvec[2]; /* Unaligned access may cross page boundary */
#endif
size_t len;
if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
len = PAGE_SIZE;
else
len = PAGE_SIZE * 2;
addr = PAGE_START(addr); addr = PAGE_START(addr);
if (addr == 0)
return -1;
for (i = 0; i < NLGA; i++) for (i = 0; i < NLGA; i++)
{ {
if (last_good_addr[i] && (addr == last_good_addr[i])) if (last_good_addr[i] && (addr == last_good_addr[i]))
return 0; return 0;
} }
if (msync ((void *) addr, 1, MS_SYNC) == -1) #ifdef HAVE_MINCORE
if (mincore ((void *) addr, len, mvec) == -1)
#else
if (msync ((void *) addr, len, MS_ASYNC) == -1)
#endif
return -1; return -1;
victim = lga_victim; victim = lga_victim;
@ -174,7 +163,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
if (unw_is_fpreg (reg)) if (unw_is_fpreg (reg))
goto badreg; goto badreg;
if (!(addr = uc_addr (uc, reg))) if (!(addr = x86_r_uc_addr (uc, reg)))
goto badreg; goto badreg;
if (write) if (write)
@ -204,7 +193,7 @@ access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
if (!unw_is_fpreg (reg)) if (!unw_is_fpreg (reg))
goto badreg; goto badreg;
if (!(addr = uc_addr (uc, reg))) if (!(addr = x86_r_uc_addr (uc, reg)))
goto badreg; goto badreg;
if (write) if (write)

View file

@ -50,7 +50,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as_arg = c; c->dwarf.as_arg = c;
c->uc = uc; c->uc = uc;
c->validate = 0; c->validate = 0;
return common_init (c); return common_init (c, 1);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */

View file

@ -51,6 +51,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
c->uc = 0; c->uc = 0;
} }
return common_init (c); return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */ #endif /* !UNW_LOCAL_ONLY */
} }

View file

@ -1,71 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.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. */
#include "unwind_i.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Check if EIP points at sigreturn() sequence. On Linux, this is:
__restore:
0x58 pop %eax
0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
0xcd 0x80 int 0x80
without SA_SIGINFO, and
__restore_rt:
0xb8 0xad 0x00 0x00 0x00 movl 0x80,%eax
0xcd 0x80 int 0x80
0x90 nop
if SA_SIGINFO is specified.
*/
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
return ret;
ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000)
|| (w0 == 0x0000adb8 && w1 == 0x9080cd00));
Debug (16, "returning %d\n", ret);
return ret;
#else
printf ("%s: implement me\n", __FUNCTION__);
#endif
return -UNW_ENOINFO;
}

364
src/x86/Gos-freebsd.c Normal file
View file

@ -0,0 +1,364 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
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. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <signal.h>
#include <stddef.h>
#include <ucontext.h>
#include <machine/sigframe.h>
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, w3, w4, w5, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Check if EIP points at sigreturn() sequence. It can be:
sigcode+4: from amd64 freebsd32 environment
8d 44 24 20 lea 0x20(%esp),%eax
50 push %eax
b8 a1 01 00 00 mov $0x1a1,%eax
50 push %eax
cd 80 int $0x80
sigcode+4: from real i386
8d 44 24 20 lea 0x20(%esp),%eax
50 push %eax
f7 40 54 00 02 00 testl $0x20000,0x54(%eax)
75 03 jne sigcode+21
8e 68 14 mov 0x14(%eax),%gs
b8 a1 01 00 00 mov $0x1a1,%eax
50 push %eax
cd 80 int $0x80
freebsd4_sigcode+4:
XXX
osigcode:
XXX
*/
ip = c->dwarf.ip;
ret = X86_SCF_NONE;
c->sigcontext_format = ret;
if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 8, &w2, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 12, &w3, 0, arg) < 0)
return ret;
if (w0 == 0x2024448d && w1 == 0x01a1b850 && w2 == 0xcd500000 &&
(w3 & 0xff) == 0x80)
ret = X86_SCF_FREEBSD_SIGFRAME;
else {
if ((*a->access_mem) (as, ip + 16, &w4, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 20, &w5, 0, arg) < 0)
return ret;
if (w0 == 0x2024448d && w1 == 0x5440f750 && w2 == 0x75000200 &&
w3 == 0x14688e03 && w4 == 0x0001a1b8 && w5 == 0x80cd5000)
ret = X86_SCF_FREEBSD_SIGFRAME;
}
Debug (16, "returning %d\n", ret);
c->sigcontext_format = ret;
return (ret);
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) {
struct sigframe *sf;
uintptr_t uc_addr;
struct dwarf_loc esp_loc;
sf = (struct sigframe *)c->dwarf.cfa;
uc_addr = (uintptr_t)&(sf->sf_uc);
c->sigcontext_addr = c->dwarf.cfa;
esp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EIP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EIP_OFF, 0);
c->dwarf.loc[ESP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
c->dwarf.loc[EAX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0);
c->dwarf.loc[TRAPNO] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_TRAPNO_OFF, 0);
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
} else {
Debug (8, "Gstep: not handling frame format %d\n", c->sigcontext_format);
abort();
}
return 0;
}
HIDDEN dwarf_loc_t
x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
{
unw_word_t addr = c->sigcontext_addr, off, xmm_off;
unw_word_t fpstate, fpformat;
int ret, is_fpstate = 0, is_xmmstate = 0;
switch (c->sigcontext_format)
{
case X86_SCF_NONE:
return DWARF_REG_LOC (&c->dwarf, reg);
case X86_SCF_FREEBSD_SIGFRAME:
addr += offsetof(struct sigframe, sf_uc) + FREEBSD_UC_MCONTEXT_OFF;
break;
case X86_SCF_FREEBSD_SIGFRAME4:
abort();
break;
case X86_SCF_FREEBSD_OSIGFRAME:
/* XXXKIB */
abort();
break;
case X86_SCF_FREEBSD_SYSCALL:
/* XXXKIB */
abort();
break;
default:
/* XXXKIB */
abort();
break;
}
off = 0; /* shut gcc warning */
switch (reg)
{
case UNW_X86_GS: off = FREEBSD_UC_MCONTEXT_GS_OFF; break;
case UNW_X86_FS: off = FREEBSD_UC_MCONTEXT_FS_OFF; break;
case UNW_X86_ES: off = FREEBSD_UC_MCONTEXT_ES_OFF; break;
case UNW_X86_DS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;
case UNW_X86_EDI: off = FREEBSD_UC_MCONTEXT_EDI_OFF; break;
case UNW_X86_ESI: off = FREEBSD_UC_MCONTEXT_ESI_OFF; break;
case UNW_X86_EBP: off = FREEBSD_UC_MCONTEXT_EBP_OFF; break;
case UNW_X86_ESP: off = FREEBSD_UC_MCONTEXT_ESP_OFF; break;
case UNW_X86_EBX: off = FREEBSD_UC_MCONTEXT_EBX_OFF; break;
case UNW_X86_EDX: off = FREEBSD_UC_MCONTEXT_EDX_OFF; break;
case UNW_X86_ECX: off = FREEBSD_UC_MCONTEXT_ECX_OFF; break;
case UNW_X86_EAX: off = FREEBSD_UC_MCONTEXT_EAX_OFF; break;
case UNW_X86_TRAPNO: off = FREEBSD_UC_MCONTEXT_TRAPNO_OFF; break;
case UNW_X86_EIP: off = FREEBSD_UC_MCONTEXT_EIP_OFF; break;
case UNW_X86_CS: off = FREEBSD_UC_MCONTEXT_CS_OFF; break;
case UNW_X86_EFLAGS: off = FREEBSD_UC_MCONTEXT_EFLAGS_OFF; break;
case UNW_X86_SS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;
case UNW_X86_FCW:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_CW_OFF;
xmm_off = FREEBSD_UC_MCONTEXT_CW_XMM_OFF;
break;
case UNW_X86_FSW:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_SW_OFF;
xmm_off = FREEBSD_UC_MCONTEXT_SW_XMM_OFF;
break;
case UNW_X86_FTW:
is_fpstate = 1;
xmm_off = FREEBSD_UC_MCONTEXT_TAG_XMM_OFF;
off = FREEBSD_UC_MCONTEXT_TAG_OFF;
break;
case UNW_X86_FCS:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_CSSEL_OFF;
xmm_off = FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF;
break;
case UNW_X86_FIP:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_IPOFF_OFF;
xmm_off = FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF;
break;
case UNW_X86_FEA:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_DATAOFF_OFF;
xmm_off = FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF;
break;
case UNW_X86_FDS:
is_fpstate = 1;
off = FREEBSD_US_MCONTEXT_DATASEL_OFF;
xmm_off = FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF;
break;
case UNW_X86_MXCSR:
is_fpstate = 1;
is_xmmstate = 1;
xmm_off = FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF;
break;
/* stacked fp registers */
case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
is_fpstate = 1;
off = FREEBSD_UC_MCONTEXT_ST0_OFF + 10*(reg - UNW_X86_ST0);
xmm_off = FREEBSD_UC_MCONTEXT_ST0_XMM_OFF + 10*(reg - UNW_X86_ST0);
break;
/* SSE fp registers */
case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
is_fpstate = 1;
is_xmmstate = 1;
xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
break;
case UNW_X86_XMM0:
case UNW_X86_XMM1:
case UNW_X86_XMM2:
case UNW_X86_XMM3:
case UNW_X86_XMM4:
case UNW_X86_XMM5:
case UNW_X86_XMM6:
case UNW_X86_XMM7:
is_fpstate = 1;
is_xmmstate = 1;
xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
break;
case UNW_X86_FOP:
case UNW_X86_TSS:
case UNW_X86_LDT:
default:
return DWARF_REG_LOC (&c->dwarf, reg);
}
if (is_fpstate)
{
if ((ret = dwarf_get (&c->dwarf,
DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPSTATE_OFF),
&fpstate)) < 0)
return DWARF_NULL_LOC;
if (fpstate == FREEBSD_UC_MCONTEXT_FPOWNED_NONE)
return DWARF_NULL_LOC;
if ((ret = dwarf_get (&c->dwarf,
DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPFORMAT_OFF),
&fpformat)) < 0)
return DWARF_NULL_LOC;
if (fpformat == FREEBSD_UC_MCONTEXT_FPFMT_NODEV ||
(is_xmmstate && fpformat != FREEBSD_UC_MCONTEXT_FPFMT_XMM))
return DWARF_NULL_LOC;
if (is_xmmstate)
off = xmm_off;
}
return DWARF_MEM_LOC (c, addr + off);
}
#ifndef UNW_REMOTE_ONLY
HIDDEN void *
x86_r_uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_GS: addr = &uc->uc_mcontext.mc_gs; break;
case UNW_X86_FS: addr = &uc->uc_mcontext.mc_fs; break;
case UNW_X86_ES: addr = &uc->uc_mcontext.mc_es; break;
case UNW_X86_DS: addr = &uc->uc_mcontext.mc_ds; break;
case UNW_X86_EAX: addr = &uc->uc_mcontext.mc_eax; break;
case UNW_X86_EBX: addr = &uc->uc_mcontext.mc_ebx; break;
case UNW_X86_ECX: addr = &uc->uc_mcontext.mc_ecx; break;
case UNW_X86_EDX: addr = &uc->uc_mcontext.mc_edx; break;
case UNW_X86_ESI: addr = &uc->uc_mcontext.mc_esi; break;
case UNW_X86_EDI: addr = &uc->uc_mcontext.mc_edi; break;
case UNW_X86_EBP: addr = &uc->uc_mcontext.mc_ebp; break;
case UNW_X86_EIP: addr = &uc->uc_mcontext.mc_eip; break;
case UNW_X86_ESP: addr = &uc->uc_mcontext.mc_esp; break;
case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.mc_trapno; break;
case UNW_X86_CS: addr = &uc->uc_mcontext.mc_cs; break;
case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.mc_eflags; break;
case UNW_X86_SS: addr = &uc->uc_mcontext.mc_ss; break;
default:
addr = NULL;
}
return addr;
}
HIDDEN int
x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = c->uc;
/* Ensure c->pi is up-to-date. On x86, it's relatively common to be
missing DWARF unwind info. We don't want to fail in that case,
because the frame-chain still would let us do a backtrace at
least. */
dwarf_make_proc_info (&c->dwarf);
if (c->sigcontext_format == X86_SCF_NONE) {
Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
setcontext (uc);
abort();
} else if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) {
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
sigreturn((ucontext_t *)((const char *)sc + FREEBSD_SC_UCONTEXT_OFF));
abort();
} else {
Debug (8, "resuming at ip=%x for sigcontext format %d not implemented\n",
c->dwarf.ip, c->sigcontext_format);
abort();
}
return -UNW_EINVAL;
}
#endif

307
src/x86/Gos-linux.c Normal file
View file

@ -0,0 +1,307 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.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. */
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Check if EIP points at sigreturn() sequence. On Linux, this is:
__restore:
0x58 pop %eax
0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
0xcd 0x80 int 0x80
without SA_SIGINFO, and
__restore_rt:
0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
0xcd 0x80 int 0x80
0x00
if SA_SIGINFO is specified.
*/
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
return ret;
ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000)
|| (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00));
Debug (16, "returning %d\n", ret);
return ret;
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
/* c->esp points at the arguments to the handler. Without
SA_SIGINFO, the arguments consist of a signal number
followed by a struct sigcontext. With SA_SIGINFO, the
arguments consist a signal number, a siginfo *, and a
ucontext *. */
unw_word_t sc_addr;
unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
unw_word_t siginfo_ptr, sigcontext_ptr;
struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
| dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
if (siginfo_ptr < c->dwarf.cfa
|| siginfo_ptr > c->dwarf.cfa + 256
|| sigcontext_ptr < c->dwarf.cfa
|| sigcontext_ptr > c->dwarf.cfa + 256)
{
/* Not plausible for SA_SIGINFO signal */
c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
}
else
{
/* If SA_SIGINFO were not specified, we actually read
various segment pointers instead. We believe that at
least fs and _fsh are always zero for linux, so it is
not just unlikely, but impossible that we would end
up here. */
c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = sigcontext_ptr;
sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
}
esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
c->dwarf.loc[EIP] = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
c->dwarf.loc[ESP] = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
return 0;
}
HIDDEN dwarf_loc_t
x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
{
unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
int ret, is_fpstate = 0;
switch (c->sigcontext_format)
{
case X86_SCF_NONE:
return DWARF_REG_LOC (&c->dwarf, reg);
case X86_SCF_LINUX_SIGFRAME:
break;
case X86_SCF_LINUX_RT_SIGFRAME:
addr += LINUX_UC_MCONTEXT_OFF;
break;
default:
return DWARF_NULL_LOC;
}
switch (reg)
{
case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;
/* The following is probably not correct for all possible cases.
Somebody who understands this better should review this for
correctness. */
case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;
/* stacked fp registers */
case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
is_fpstate = 1;
off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
break;
/* SSE fp registers */
case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
is_fpstate = 1;
off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
break;
case UNW_X86_XMM0:
case UNW_X86_XMM1:
case UNW_X86_XMM2:
case UNW_X86_XMM3:
case UNW_X86_XMM4:
case UNW_X86_XMM5:
case UNW_X86_XMM6:
case UNW_X86_XMM7:
is_fpstate = 1;
off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
break;
case UNW_X86_FOP:
case UNW_X86_TSS:
case UNW_X86_LDT:
default:
return DWARF_REG_LOC (&c->dwarf, reg);
}
if (is_fpstate)
{
if ((ret = dwarf_get (&c->dwarf,
DWARF_MEM_LOC (&c->dwarf,
addr + LINUX_SC_FPSTATE_OFF),
&fpstate_addr)) < 0)
return DWARF_NULL_LOC;
if (!fpstate_addr)
return DWARF_NULL_LOC;
return DWARF_MEM_LOC (c, fpstate_addr + off);
}
else
return DWARF_MEM_LOC (c, addr + off);
}
#ifndef UNW_REMOTE_ONLY
HIDDEN void *
x86_r_uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_GS: addr = &uc->uc_mcontext.gregs[REG_GS]; break;
case UNW_X86_FS: addr = &uc->uc_mcontext.gregs[REG_FS]; break;
case UNW_X86_ES: addr = &uc->uc_mcontext.gregs[REG_ES]; break;
case UNW_X86_DS: addr = &uc->uc_mcontext.gregs[REG_DS]; break;
case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
case UNW_X86_TRAPNO: addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
case UNW_X86_CS: addr = &uc->uc_mcontext.gregs[REG_CS]; break;
case UNW_X86_EFLAGS: addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
case UNW_X86_SS: addr = &uc->uc_mcontext.gregs[REG_SS]; break;
default:
addr = NULL;
}
return addr;
}
HIDDEN int
x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = c->uc;
/* Ensure c->pi is up-to-date. On x86, it's relatively common to be
missing DWARF unwind info. We don't want to fail in that case,
because the frame-chain still would let us do a backtrace at
least. */
dwarf_make_proc_info (&c->dwarf);
if (unlikely (c->sigcontext_format != X86_SCF_NONE))
{
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
sigreturn (sc);
}
else
{
Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
setcontext (uc);
}
return -UNW_EINVAL;
}
#endif

View file

@ -26,118 +26,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "offsets.h" #include "offsets.h"
#include "unwind_i.h" #include "unwind_i.h"
static inline dwarf_loc_t
linux_scratch_loc (struct cursor *c, unw_regnum_t reg)
{
unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
int ret, is_fpstate = 0;
switch (c->sigcontext_format)
{
case X86_SCF_NONE:
return DWARF_REG_LOC (&c->dwarf, reg);
case X86_SCF_LINUX_SIGFRAME:
break;
case X86_SCF_LINUX_RT_SIGFRAME:
addr += LINUX_UC_MCONTEXT_OFF;
break;
}
switch (reg)
{
case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;
/* The following is probably not correct for all possible cases.
Somebody who understands this better should review this for
correctness. */
case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;
/* stacked fp registers */
case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
is_fpstate = 1;
off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
break;
/* SSE fp registers */
case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
is_fpstate = 1;
off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
break;
case UNW_X86_XMM0:
case UNW_X86_XMM1:
case UNW_X86_XMM2:
case UNW_X86_XMM3:
case UNW_X86_XMM4:
case UNW_X86_XMM5:
case UNW_X86_XMM6:
case UNW_X86_XMM7:
is_fpstate = 1;
off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
break;
case UNW_X86_FOP:
case UNW_X86_TSS:
case UNW_X86_LDT:
default:
return DWARF_REG_LOC (&c->dwarf, reg);
}
if (is_fpstate)
{
if ((ret = dwarf_get (&c->dwarf,
DWARF_MEM_LOC (&c->dwarf,
addr + LINUX_SC_FPSTATE_OFF),
&fpstate_addr)) < 0)
return DWARF_NULL_LOC;
if (!fpstate_addr)
return DWARF_NULL_LOC;
return DWARF_MEM_LOC (c, fpstate_addr + off);
}
else
return DWARF_MEM_LOC (c, addr + off);
}
HIDDEN dwarf_loc_t HIDDEN dwarf_loc_t
x86_scratch_loc (struct cursor *c, unw_regnum_t reg) x86_scratch_loc (struct cursor *c, unw_regnum_t reg)
{ {
if (c->sigcontext_addr) if (c->sigcontext_addr)
return linux_scratch_loc (c, reg); return x86_get_scratch_loc (c, reg);
else else
return DWARF_REG_LOC (&c->dwarf, reg); return DWARF_REG_LOC (&c->dwarf, reg);
} }

View file

@ -26,41 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h> #include <stdlib.h>
#include "unwind_i.h" #include "unwind_i.h"
#include "offsets.h"
#ifndef UNW_REMOTE_ONLY
HIDDEN inline int
x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
#if defined(__linux)
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = c->uc;
/* Ensure c->pi is up-to-date. On x86, it's relatively common to be
missing DWARF unwind info. We don't want to fail in that case,
because the frame-chain still would let us do a backtrace at
least. */
dwarf_make_proc_info (&c->dwarf);
if (unlikely (c->sigcontext_format != X86_SCF_NONE))
{
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
sigreturn (sc);
}
else
{
Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
setcontext (uc);
}
#else
# warning Implement me!
#endif
return -UNW_EINVAL;
}
#endif /* !UNW_REMOTE_ONLY */
/* This routine is responsible for copying the register values in /* This routine is responsible for copying the register values in
cursor C and establishing them as the current machine state. */ cursor C and establishing them as the current machine state. */

View file

@ -56,70 +56,14 @@ unw_step (unw_cursor_t *cursor)
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret); Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
if (unw_is_signal_frame (cursor)) if (unw_is_signal_frame (cursor))
{ {
/* XXX This code is Linux-specific! */ ret = unw_handle_signal_frame(cursor);
/* c->esp points at the arguments to the handler. Without
SA_SIGINFO, the arguments consist of a signal number
followed by a struct sigcontext. With SA_SIGINFO, the
arguments consist a signal number, a siginfo *, and a
ucontext *. */
unw_word_t sc_addr;
unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
unw_word_t siginfo_ptr, sigcontext_ptr;
struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
| dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
if (ret < 0) if (ret < 0)
{ {
Debug (2, "returning 0\n"); Debug (2, "returning 0\n");
return 0; return 0;
} }
if (siginfo_ptr < c->dwarf.cfa }
|| siginfo_ptr > c->dwarf.cfa + 256
|| sigcontext_ptr < c->dwarf.cfa
|| sigcontext_ptr > c->dwarf.cfa + 256)
{
/* Not plausible for SA_SIGINFO signal */
c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
}
else
{
/* If SA_SIGINFO were not specified, we actually read
various segment pointers instead. We believe that at
least fs and _fsh are always zero for linux, so it is
not just unlikely, but impossible that we would end
up here. */
c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = sigcontext_ptr;
sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
}
esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
ebp_loc = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
eip_loc = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
}
else else
{ {
ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa); ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa);
@ -141,9 +85,10 @@ unw_step (unw_cursor_t *cursor)
EIP. */ EIP. */
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC; c->dwarf.loc[i] = DWARF_NULL_LOC;
c->dwarf.loc[EBP] = ebp_loc;
c->dwarf.loc[EIP] = eip_loc;
} }
c->dwarf.loc[EBP] = ebp_loc;
c->dwarf.loc[EIP] = eip_loc;
c->dwarf.ret_addr_column = EIP; c->dwarf.ret_addr_column = EIP;
if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP])) if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP]))
@ -151,9 +96,15 @@ unw_step (unw_cursor_t *cursor)
ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip); ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip);
if (ret < 0) if (ret < 0)
{ {
Debug (13, "dwarf_get([EIP=0x%x]) failed\n", DWARF_GET_LOC (c->dwarf.loc[EIP]));
Debug (2, "returning %d\n", ret); Debug (2, "returning %d\n", ret);
return ret; return ret;
} }
else
{
Debug (13, "[EIP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EIP]),
c->dwarf.ip);
}
} }
else else
c->dwarf.ip = 0; c->dwarf.ip = 0;

View file

@ -1,5 +1,5 @@
#define UNW_LOCAL_ONLY #define UNW_LOCAL_ONLY
#include <libunwind.h> #include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY) #if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gis_signal_frame.c" #include "Gos-freebsd.c"
#endif #endif

5
src/x86/Los-linux.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gos-linux.c"
#endif

View file

@ -0,0 +1,112 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
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. */
#include "offsets.h"
.global _Ux86_getcontext
.type _Ux86_getcontext, @function
_Ux86_getcontext:
.cfi_startproc
pushl %eax
.cfi_adjust_cfa_offset 4
mov 8(%esp),%eax /* ucontext_t* */
popl FREEBSD_UC_MCONTEXT_EAX_OFF(%eax)
.cfi_adjust_cfa_offset 4
movl %ebx, FREEBSD_UC_MCONTEXT_EBX_OFF(%eax)
movl %ecx, FREEBSD_UC_MCONTEXT_ECX_OFF(%eax)
movl %edx, FREEBSD_UC_MCONTEXT_EDX_OFF(%eax)
movl %edi, FREEBSD_UC_MCONTEXT_EDI_OFF(%eax)
movl %esi, FREEBSD_UC_MCONTEXT_ESI_OFF(%eax)
movl %ebp, FREEBSD_UC_MCONTEXT_EBP_OFF(%eax)
movl (%esp), %ecx
movl %ecx, FREEBSD_UC_MCONTEXT_EIP_OFF(%eax)
leal 4(%esp), %ecx /* Exclude the return address. */
movl %ecx, FREEBSD_UC_MCONTEXT_ESP_OFF(%eax)
xorl %ecx, %ecx
movw %fs, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_FS_OFF(%eax)
movw %gs, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_GS_OFF(%eax)
movw %ds, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_DS_OFF(%eax)
movw %es, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_ES_OFF(%eax)
movw %ss, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_SS_OFF(%eax)
movw %cs, %cx
movl %ecx, FREEBSD_UC_MCONTEXT_CS_OFF(%eax)
pushfl
.cfi_adjust_cfa_offset 4
popl FREEBSD_UC_MCONTEXT_EFLAGS_OFF(%eax)
.cfi_adjust_cfa_offset -4
movl $0, FREEBSD_UC_MCONTEXT_TRAPNO_OFF(%eax)
movl $FREEBSD_UC_MCONTEXT_FPOWNED_FPU,\
FREEBSD_UC_MCONTEXT_OWNEDFP_OFF(%eax)
movl $FREEBSD_UC_MCONTEXT_FPFMT_XMM,\
FREEBSD_UC_MCONTEXT_FPFORMAT_OFF(%eax)
/*
* Require CPU with fxsave implemented, and enabled by OS.
*
* If passed ucontext is not aligned to 16-byte boundary,
* save fpu context into temporary aligned location on stack
* and then copy.
*/
leal FREEBSD_UC_MCONTEXT_FPSTATE_OFF(%eax), %edx
testl $0xf, %edx
jne 2f
fxsave (%edx) /* fast path, passed ucontext save area was aligned */
1: movl $FREEBSD_UC_MCONTEXT_MC_LEN_VAL,\
FREEBSD_UC_MCONTEXT_MC_LEN_OFF(%eax)
xorl %eax, %eax
ret
2: movl %edx, %edi /* not aligned, do the dance */
subl $512 + 16, %esp /* save area and 16 bytes for alignment */
.cfi_adjust_cfa_offset 512 + 16
movl %esp, %edx
orl $0xf, %edx /* align *%edx to 16-byte up */
incl %edx
fxsave (%edx)
movl %edx, %esi /* copy to the final destination */
movl $512/4,%ecx
rep; movsl
addl $512 + 16, %esp /* restore the stack */
.cfi_adjust_cfa_offset -512 - 16
movl FREEBSD_UC_MCONTEXT_ESI_OFF(%eax), %esi
movl FREEBSD_UC_MCONTEXT_EDI_OFF(%eax), %edi
jmp 1b
.cfi_endproc
.size _Ux86_getcontext, . - _Ux86_getcontext
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits

View file

@ -0,0 +1,74 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2009 Google, Inc
Contributed by Paul Pluzhnikov <ppluzhnikov@google.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. */
#include "offsets.h"
/* int _Ux86_getcontext (ucontext_t *ucp)
Saves the machine context in UCP necessary for libunwind.
Unlike the libc implementation, we don't save the signal mask
and hence avoid the cost of a system call per unwind.
*/
.global _Ux86_getcontext
.type _Ux86_getcontext, @function
_Ux86_getcontext:
.cfi_startproc
mov 4(%esp),%eax /* ucontext_t* */
/* EAX is not preserved. */
movl $0, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EAX_OFF)(%eax)
movl %ebx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EBX_OFF)(%eax)
movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ECX_OFF)(%eax)
movl %edx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EDX_OFF)(%eax)
movl %edi, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EDI_OFF)(%eax)
movl %esi, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ESI_OFF)(%eax)
movl %ebp, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EBP_OFF)(%eax)
movl (%esp), %ecx
movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_EIP_OFF)(%eax)
leal 4(%esp), %ecx /* Exclude the return address. */
movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_ESP_OFF)(%eax)
/* glibc getcontext saves FS, but not GS */
xorl %ecx, %ecx
movw %fs, %cx
movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FS_OFF)(%eax)
leal LINUX_UC_FPREGS_MEM_OFF(%eax), %ecx
movl %ecx, (LINUX_UC_MCONTEXT_OFF+LINUX_SC_FPSTATE_OFF)(%eax)
fnstenv (%ecx)
fldenv (%ecx)
xor %eax, %eax
ret
.cfi_endproc
.size _Ux86_getcontext, . - _Ux86_getcontext
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits

View file

@ -26,7 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
static inline int static inline int
common_init (struct cursor *c) common_init (struct cursor *c, unsigned use_prev_instr)
{ {
int ret, i; int ret, i;
@ -59,6 +59,7 @@ common_init (struct cursor *c)
c->dwarf.args_size = 0; c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0; c->dwarf.ret_addr_column = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0; c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0; c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0; c->dwarf.hint = 0;

View file

@ -9,6 +9,7 @@
#define LINUX_UC_STACK_OFF 0x08 #define LINUX_UC_STACK_OFF 0x08
#define LINUX_UC_MCONTEXT_OFF 0x14 #define LINUX_UC_MCONTEXT_OFF 0x14
#define LINUX_UC_SIGMASK_OFF 0x6c #define LINUX_UC_SIGMASK_OFF 0x6c
#define LINUX_UC_FPREGS_MEM_OFF 0xec
/* The struct sigcontext is located at an offset of 4 /* The struct sigcontext is located at an offset of 4
from the stack pointer in the signal frame. */ from the stack pointer in the signal frame. */
@ -81,3 +82,59 @@
#define LINUX_FPSTATE_XMM5_OFF 0x160 #define LINUX_FPSTATE_XMM5_OFF 0x160
#define LINUX_FPSTATE_XMM6_OFF 0x170 #define LINUX_FPSTATE_XMM6_OFF 0x170
#define LINUX_FPSTATE_XMM7_OFF 0x180 #define LINUX_FPSTATE_XMM7_OFF 0x180
/* FreeBSD-specific definitions: */
#define FREEBSD_SC_UCONTEXT_OFF 0x20
#define FREEBSD_UC_MCONTEXT_OFF 0x10
#define FREEBSD_UC_MCONTEXT_GS_OFF 0x14
#define FREEBSD_UC_MCONTEXT_FS_OFF 0x18
#define FREEBSD_UC_MCONTEXT_ES_OFF 0x1c
#define FREEBSD_UC_MCONTEXT_DS_OFF 0x20
#define FREEBSD_UC_MCONTEXT_EDI_OFF 0x24
#define FREEBSD_UC_MCONTEXT_ESI_OFF 0x28
#define FREEBSD_UC_MCONTEXT_EBP_OFF 0x2c
#define FREEBSD_UC_MCONTEXT_EBX_OFF 0x34
#define FREEBSD_UC_MCONTEXT_EDX_OFF 0x38
#define FREEBSD_UC_MCONTEXT_ECX_OFF 0x3c
#define FREEBSD_UC_MCONTEXT_EAX_OFF 0x40
#define FREEBSD_UC_MCONTEXT_TRAPNO_OFF 0x44
#define FREEBSD_UC_MCONTEXT_EIP_OFF 0x4c
#define FREEBSD_UC_MCONTEXT_ESP_OFF 0x58
#define FREEBSD_UC_MCONTEXT_CS_OFF 0x50
#define FREEBSD_UC_MCONTEXT_EFLAGS_OFF 0x54
#define FREEBSD_UC_MCONTEXT_SS_OFF 0x5c
#define FREEBSD_UC_MCONTEXT_MC_LEN_OFF 0x60
#define FREEBSD_UC_MCONTEXT_FPFORMAT_OFF 0x64
#define FREEBSD_UC_MCONTEXT_OWNEDFP_OFF 0x68
#define FREEBSD_UC_MCONTEXT_FPSTATE_OFF 0x70
#define FREEBSD_UC_MCONTEXT_CW_OFF 0x70
#define FREEBSD_UC_MCONTEXT_SW_OFF 0x74
#define FREEBSD_UC_MCONTEXT_TAG_OFF 0x78
#define FREEBSD_UC_MCONTEXT_IPOFF_OFF 0x7c
#define FREEBSD_UC_MCONTEXT_CSSEL_OFF 0x80
#define FREEBSD_UC_MCONTEXT_DATAOFF_OFF 0x84
#define FREEBSD_US_MCONTEXT_DATASEL_OFF 0x88
#define FREEBSD_UC_MCONTEXT_ST0_OFF 0x8c
#define FREEBSD_UC_MCONTEXT_CW_XMM_OFF 0x70
#define FREEBSD_UC_MCONTEXT_SW_XMM_OFF 0x72
#define FREEBSD_UC_MCONTEXT_TAG_XMM_OFF 0x74
#define FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF 0x78
#define FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF 0x7c
#define FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF 0x80
#define FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF 0x84
#define FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF 0x88
#define FREEBSD_UC_MCONTEXT_ST0_XMM_OFF 0x90
#define FREEBSD_UC_MCONTEXT_XMM0_OFF 0x110
#define FREEBSD_UC_MCONTEXT_MC_LEN_VAL 0x280
#define FREEBSD_UC_MCONTEXT_FPFMT_NODEV 0x10000
#define FREEBSD_UC_MCONTEXT_FPFMT_387 0x10001
#define FREEBSD_UC_MCONTEXT_FPFMT_XMM 0x10002
#define FREEBSD_UC_MCONTEXT_FPOWNED_NONE 0x20000
#define FREEBSD_UC_MCONTEXT_FPOWNED_FPU 0x20001
#define FREEBSD_UC_MCONTEXT_FPOWNED_PCB 0x20002

View file

@ -51,10 +51,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define x86_local_resume UNW_OBJ(local_resume) #define x86_local_resume UNW_OBJ(local_resume)
#define x86_local_addr_space_init UNW_OBJ(local_addr_space_init) #define x86_local_addr_space_init UNW_OBJ(local_addr_space_init)
#define x86_scratch_loc UNW_OBJ(scratch_loc) #define x86_scratch_loc UNW_OBJ(scratch_loc)
#define x86_get_scratch_loc UNW_OBJ(get_scratch_loc)
#define x86_r_uc_addr UNW_OBJ(r_uc_addr)
extern void x86_local_addr_space_init (void); extern void x86_local_addr_space_init (void);
extern int x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, extern int x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
void *arg); void *arg);
extern dwarf_loc_t x86_scratch_loc (struct cursor *c, unw_regnum_t reg); extern dwarf_loc_t x86_scratch_loc (struct cursor *c, unw_regnum_t reg);
extern dwarf_loc_t x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg);
extern void *x86_r_uc_addr (ucontext_t *uc, int reg);
#endif /* unwind_i_h */ #endif /* unwind_i_h */

View file

@ -29,6 +29,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
#if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN)
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#endif
PROTECTED unw_addr_space_t PROTECTED unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order) unw_create_addr_space (unw_accessors_t *a, int byte_order)
{ {

View file

@ -61,8 +61,7 @@ tdep_init (void)
sigfillset (&unwi_full_mask); sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask); lock_acquire (&x86_64_lock, saved_mask);
mutex_lock (&x86_64_lock);
{ {
if (!tdep_needs_initialization) if (!tdep_needs_initialization)
/* another thread else beat us to it... */ /* another thread else beat us to it... */
@ -78,6 +77,5 @@ tdep_init (void)
tdep_needs_initialization = 0; /* signal that we're initialized... */ tdep_needs_initialization = 0; /* signal that we're initialized... */
} }
out: out:
mutex_unlock (&x86_64_lock); lock_release (&x86_64_lock, saved_mask);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
} }

View file

@ -26,6 +26,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -43,43 +47,12 @@ static struct unw_addr_space local_addr_space;
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
default:
addr = NULL;
}
return addr;
}
# ifdef UNW_LOCAL_ONLY # ifdef UNW_LOCAL_ONLY
HIDDEN void * HIDDEN void *
tdep_uc_addr (ucontext_t *uc, int reg) tdep_uc_addr (ucontext_t *uc, int reg)
{ {
return uc_addr (uc, reg); return x86_64_r_uc_addr (uc, reg);
} }
# endif /* UNW_LOCAL_ONLY */ # endif /* UNW_LOCAL_ONLY */
@ -117,16 +90,32 @@ static int
validate_mem (unw_word_t addr) validate_mem (unw_word_t addr)
{ {
int i, victim; int i, victim;
#ifdef HAVE_MINCORE
unsigned char mvec[2]; /* Unaligned access may cross page boundary */
#endif
size_t len;
if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
len = PAGE_SIZE;
else
len = PAGE_SIZE * 2;
addr = PAGE_START(addr); addr = PAGE_START(addr);
if (addr == 0)
return -1;
for (i = 0; i < NLGA; i++) for (i = 0; i < NLGA; i++)
{ {
if (last_good_addr[i] && (addr == last_good_addr[i])) if (last_good_addr[i] && (addr == last_good_addr[i]))
return 0; return 0;
} }
if (msync ((void *) addr, 1, MS_SYNC) == -1) #ifdef HAVE_MINCORE
if (mincore ((void *) addr, len, mvec) == -1)
#else
if (msync ((void *) addr, len, MS_ASYNC) == -1)
#endif
return -1; return -1;
victim = lga_victim; victim = lga_victim;
@ -177,7 +166,7 @@ access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
if (unw_is_fpreg (reg)) if (unw_is_fpreg (reg))
goto badreg; goto badreg;
if (!(addr = uc_addr (uc, reg))) if (!(addr = x86_64_r_uc_addr (uc, reg)))
goto badreg; goto badreg;
if (write) if (write)
@ -207,7 +196,7 @@ access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
if (!unw_is_fpreg (reg)) if (!unw_is_fpreg (reg))
goto badreg; goto badreg;
if (!(addr = uc_addr (uc, reg))) if (!(addr = x86_64_r_uc_addr (uc, reg)))
goto badreg; goto badreg;
if (write) if (write)

View file

@ -51,8 +51,12 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
c->dwarf.as = unw_local_addr_space; c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = c; c->dwarf.as_arg = c;
c->uc = uc; c->uc = uc;
#if CONSERVATIVE_CHECKS
c->validate = 1;
#else
c->validate = 0; c->validate = 0;
return common_init (c); #endif
return common_init (c, 1);
} }
#endif /* !UNW_REMOTE_ONLY */ #endif /* !UNW_REMOTE_ONLY */

View file

@ -52,6 +52,6 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
c->dwarf.as_arg = as_arg; c->dwarf.as_arg = as_arg;
c->uc = 0; c->uc = 0;
} }
return common_init (c); return common_init (c, 0);
#endif /* !UNW_LOCAL_ONLY */ #endif /* !UNW_LOCAL_ONLY */
} }

View file

@ -1,76 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.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. */
#include "unwind_i.h"
#ifdef __linux__
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Check if RIP points at sigreturn sequence.
on x86_64 Linux that is (see libc.so):
48 c7 c0 0f 00 00 00 mov $0xf,%rax
0f 05 syscall
66 data16
*/
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0)
return 0;
w1 &= 0xff;
return (w0 == 0x0f0000000fc0c748 && w1 == 0x05);
}
#elif defined(__sun) /* __linux__ */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
return 0;
}
#else /* __sun */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
}
#endif /* __linux__ */

197
src/x86_64/Gos-freebsd.c Normal file
View file

@ -0,0 +1,197 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
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. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/ucontext.h>
#include <machine/sigframe.h>
#include <signal.h>
#include <stddef.h>
#include "unwind_i.h"
#include "ucontext_i.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
/* XXXKIB */
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, b0, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* Check if RIP points at sigreturn sequence.
48 8d 7c 24 10 lea SIGF_UC(%rsp),%rdi
6a 00 pushq $0
48 c7 c0 a1 01 00 00 movq $SYS_sigreturn,%rax
0f 05 syscall
f4 0: hlt
eb fd jmp 0b
*/
ip = c->dwarf.ip;
c->sigcontext_format = X86_64_SCF_NONE;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0)
return 0;
w2 &= 0xffffff;
if (w0 == 0x48006a10247c8d48 &&
w1 == 0x050f000001a1c0c7 &&
w2 == 0x0000000000fdebf4)
{
c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME;
return (c->sigcontext_format);
}
/* Check if RIP points at standard syscall sequence.
49 89 ca mov %rcx,%r10
0f 05 syscall
*/
if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0)
return (0);
b0 &= 0xffffffffff;
if (b0 == 0x000000050fca8949)
{
c->sigcontext_format = X86_64_SCF_FREEBSD_SYSCALL;
return (c->sigcontext_format);
}
return (X86_64_SCF_NONE);
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t ucontext;
int ret;
if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME)
{
ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc);
c->sigcontext_addr = c->dwarf.cfa;
Debug(1, "signal frame, skip over trampoline\n");
struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning %d\n", ret);
return ret;
}
c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
return 0;
}
else if (c->sigcontext_format == X86_64_SCF_FREEBSD_SYSCALL)
{
c->dwarf.loc[RCX] = c->dwarf.loc[R10];
/* rsp_loc = DWARF_LOC(c->dwarf.cfa - 8, 0); */
/* rbp_loc = c->dwarf.loc[RBP]; */
c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",
(unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RIP]),
(unsigned long long) c->dwarf.ip);
if (ret < 0)
{
Debug (2, "returning %d\n", ret);
return ret;
}
c->dwarf.cfa += 8;
return 1;
}
else
return -UNW_EBADFRAME;
}
#ifndef UNW_REMOTE_ONLY
HIDDEN void *
x86_64_r_uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_64_R8: addr = &uc->uc_mcontext.mc_r8; break;
case UNW_X86_64_R9: addr = &uc->uc_mcontext.mc_r9; break;
case UNW_X86_64_R10: addr = &uc->uc_mcontext.mc_r10; break;
case UNW_X86_64_R11: addr = &uc->uc_mcontext.mc_r11; break;
case UNW_X86_64_R12: addr = &uc->uc_mcontext.mc_r12; break;
case UNW_X86_64_R13: addr = &uc->uc_mcontext.mc_r13; break;
case UNW_X86_64_R14: addr = &uc->uc_mcontext.mc_r14; break;
case UNW_X86_64_R15: addr = &uc->uc_mcontext.mc_r15; break;
case UNW_X86_64_RDI: addr = &uc->uc_mcontext.mc_rdi; break;
case UNW_X86_64_RSI: addr = &uc->uc_mcontext.mc_rsi; break;
case UNW_X86_64_RBP: addr = &uc->uc_mcontext.mc_rbp; break;
case UNW_X86_64_RBX: addr = &uc->uc_mcontext.mc_rbx; break;
case UNW_X86_64_RDX: addr = &uc->uc_mcontext.mc_rdx; break;
case UNW_X86_64_RAX: addr = &uc->uc_mcontext.mc_rax; break;
case UNW_X86_64_RCX: addr = &uc->uc_mcontext.mc_rcx; break;
case UNW_X86_64_RSP: addr = &uc->uc_mcontext.mc_rsp; break;
case UNW_X86_64_RIP: addr = &uc->uc_mcontext.mc_rip; break;
default:
addr = NULL;
}
return addr;
}
HIDDEN NORETURN void
x86_64_sigreturn (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
ucontext_t *uc = (ucontext_t *)(c->sigcontext_addr +
offsetof(struct sigframe, sf_uc));
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, uc);
sigreturn(uc);
abort();
}
#endif

155
src/x86_64/Gos-linux.c Normal file
View file

@ -0,0 +1,155 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Modified for x86_64 by Max Asbock <masbock@us.ibm.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. */
#include "unwind_i.h"
#include "ucontext_i.h"
#include <sys/syscall.h>
HIDDEN void
tdep_fetch_frame (struct dwarf_cursor *dw, unw_word_t ip, int need_unwind_info)
{
struct cursor *c = (struct cursor *) dw;
assert(! need_unwind_info || dw->pi_valid);
assert(! need_unwind_info || dw->pi.unwind_info);
if (dw->pi_valid
&& dw->pi.unwind_info
&& ((struct dwarf_cie_info *) dw->pi.unwind_info)->signal_frame)
{
c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = dw->cfa;
}
else
{
c->sigcontext_format = X86_64_SCF_NONE;
c->sigcontext_addr = 0;
}
Debug(15, "fetch frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n",
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr);
}
HIDDEN void
tdep_cache_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
{
struct cursor *c = (struct cursor *) dw;
rs->signal_frame = c->sigcontext_format;
Debug(15, "cache frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n",
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr);
}
HIDDEN void
tdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
{
struct cursor *c = (struct cursor *) dw;
c->sigcontext_format = rs->signal_frame;
if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME)
c->sigcontext_addr = dw->cfa;
else
c->sigcontext_addr = 0;
Debug(15, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx\n",
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr);
}
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
return c->sigcontext_format != X86_64_SCF_NONE;
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
#if UNW_DEBUG /* To silence compiler warnings */
/* Should not get here because we now use kernel-provided dwarf
information for the signal trampoline and dwarf_step() works.
Hence dwarf_step() should never call this function. Maybe
restore old non-dwarf signal handling here, but then the
gating on unw_is_signal_frame() needs to be removed. */
struct cursor *c = (struct cursor *) cursor;
Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n",
c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa);
assert(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME);
assert(c->sigcontext_addr == c->dwarf.cfa);
assert(0);
#endif
return 1;
}
#ifndef UNW_REMOTE_ONLY
HIDDEN void *
x86_64_r_uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
default:
addr = NULL;
}
return addr;
}
/* sigreturn() is a no-op on x86_64 glibc. */
HIDDEN NORETURN void
x86_64_sigreturn (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, sc);
__asm__ __volatile__ ("mov %0, %%rsp;"
"mov %1, %%rax;"
"syscall"
:: "r"(sc), "i"(SYS_rt_sigreturn)
: "memory");
abort();
}
#endif

View file

@ -41,6 +41,10 @@ linux_scratch_loc (struct cursor *c, unw_regnum_t reg)
case X86_64_SCF_LINUX_RT_SIGFRAME: case X86_64_SCF_LINUX_RT_SIGFRAME:
addr += LINUX_UC_MCONTEXT_OFF; addr += LINUX_UC_MCONTEXT_OFF;
break; break;
case X86_64_SCF_FREEBSD_SIGFRAME:
addr += FREEBSD_UC_MCONTEXT_OFF;
break;
} }
return DWARF_REG_LOC (&c->dwarf, reg); return DWARF_REG_LOC (&c->dwarf, reg);

View file

@ -27,29 +27,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h> #include <stdlib.h>
#include "offsets.h"
#include "unwind_i.h" #include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY #ifndef UNW_REMOTE_ONLY
#include <sys/syscall.h>
#ifdef __linux__
/* sigreturn() is a no-op on x86_64 glibc. */
static NORETURN inline long
my_rt_sigreturn (void *new_sp)
{
__asm__ __volatile__ ("mov %0, %%rsp;"
"mov %1, %%rax;"
"syscall"
:: "r"(new_sp), "i"(SYS_rt_sigreturn)
: "memory");
abort ();
}
#endif // __linux__
HIDDEN inline int HIDDEN inline int
x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{ {
@ -64,21 +46,14 @@ x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
if (unlikely (c->sigcontext_format != X86_64_SCF_NONE)) if (unlikely (c->sigcontext_format != X86_64_SCF_NONE))
{ {
#ifdef __linux__ x86_64_sigreturn(cursor);
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; abort();
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, sc);
my_rt_sigreturn (sc);
#else // __linux__
assert(0 && "Unimplemented");
#endif // __linux__
} }
else else
{ {
Debug (8, "resuming at ip=%llx via setcontext()\n", Debug (8, "resuming at ip=%llx via setcontext()\n",
(unsigned long long) c->dwarf.ip); (unsigned long long) c->dwarf.ip);
_Ux86_64_setcontext (uc); setcontext (uc);
} }
return -UNW_EINVAL; return -UNW_EINVAL;
} }

View file

@ -26,19 +26,43 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h" #include "unwind_i.h"
#include "ucontext_i.h"
#include <signal.h> #include <signal.h>
/* Recognise PLT entries such as:
3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip)
3bdf6: 68 ae 03 00 00 pushq $0x3ae
3bdfb: e9 00 c5 ff ff jmpq 38300 <_init+0x18> */
static int
is_plt_entry (struct dwarf_cursor *c)
{
unw_word_t w0, w1;
unw_accessors_t *a;
int ret;
a = unw_get_accessors (c->as);
if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0
|| (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0)
return 0;
ret = (((w0 & 0xffff) == 0x25ff)
&& (((w0 >> 48) & 0xff) == 0x68)
&& (((w1 >> 24) & 0xff) == 0xe9));
Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
return ret;
}
PROTECTED int PROTECTED int
unw_step (unw_cursor_t *cursor) unw_step (unw_cursor_t *cursor)
{ {
struct cursor *c = (struct cursor *) cursor; struct cursor *c = (struct cursor *) cursor;
int ret, i; int ret, i;
Debug (1, "(cursor=%p, ip=0x%016llx)\n", Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
c, (unsigned long long) c->dwarf.ip); c, c->dwarf.ip, c->dwarf.cfa);
/* Try DWARF-based unwinding... */ /* Try DWARF-based unwinding... */
c->sigcontext_format = X86_64_SCF_NONE;
ret = dwarf_step (&c->dwarf); ret = dwarf_step (&c->dwarf);
if (ret < 0 && ret != -UNW_ENOINFO) if (ret < 0 && ret != -UNW_ENOINFO)
@ -79,40 +103,23 @@ unw_step (unw_cursor_t *cursor)
if (unw_is_signal_frame (cursor)) if (unw_is_signal_frame (cursor))
{ {
unw_word_t ucontext = c->dwarf.cfa; ret = unw_handle_signal_frame(cursor);
Debug(1, "signal frame, skip over trampoline\n");
c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = c->dwarf.cfa;
rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
rbp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
rip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
if (ret < 0) if (ret < 0)
{ {
Debug (2, "returning %d\n", ret); Debug (2, "returning 0\n");
return ret; return 0;
} }
}
c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0); else if (is_plt_entry (&c->dwarf))
c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0); {
c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0); Debug (2, "found plt entry\n");
c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0); c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0); c->dwarf.cfa += 8;
c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0); }
c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0); else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0); {
c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0); for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0); c->dwarf.loc[i] = DWARF_NULL_LOC;
c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
} }
else else
{ {
@ -121,7 +128,8 @@ unw_step (unw_cursor_t *cursor)
ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp); ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
if (ret < 0) if (ret < 0)
{ {
Debug (2, "returning %d\n", ret); Debug (2, "returning %d [RBP=0x%lx]\n", ret,
DWARF_GET_LOC (c->dwarf.loc[RBP]));
return ret; return ret;
} }
@ -153,14 +161,15 @@ unw_step (unw_cursor_t *cursor)
/* Mark all registers unsaved */ /* Mark all registers unsaved */
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC; c->dwarf.loc[i] = DWARF_NULL_LOC;
c->dwarf.loc[RBP] = rbp_loc;
c->dwarf.loc[RSP] = rsp_loc;
c->dwarf.loc[RIP] = rip_loc;
} }
c->dwarf.loc[RBP] = rbp_loc;
c->dwarf.loc[RSP] = rsp_loc;
c->dwarf.loc[RIP] = rip_loc;
c->dwarf.ret_addr_column = RIP; c->dwarf.ret_addr_column = RIP;
if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])) if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP]))
{ {
ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip); ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n", Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",

Some files were not shown because too many files have changed in this diff Show more