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:
commit
70d23830fa
122 changed files with 4342 additions and 1016 deletions
|
@ -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
11
README
|
@ -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
|
||||||
|
|
||||||
|
|
45
configure.in
45
configure.in
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 *,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
101
src/os-freebsd.c
Normal 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 */
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
138
src/os-linux.h
138
src/os-linux.h
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 *)®s + _UPT_reg_offset[reg];
|
||||||
|
if (ptrace(PT_GETREGS, pid, (caddr_t)®s, 0) == -1)
|
||||||
|
goto badreg;
|
||||||
|
if (write) {
|
||||||
|
memcpy(r, val, sizeof(unw_word_t));
|
||||||
|
if (ptrace(PT_SETREGS, pid, (caddr_t)®s, 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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
364
src/x86/Gos-freebsd.c
Normal 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
307
src/x86/Gos-linux.c
Normal 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
|
109
src/x86/Gregs.c
109
src/x86/Gregs.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
5
src/x86/Los-linux.c
Normal 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
|
112
src/x86/getcontext-freebsd.S
Normal file
112
src/x86/getcontext-freebsd.S
Normal 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
|
74
src/x86/getcontext-linux.S
Normal file
74
src/x86/getcontext-linux.S
Normal 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
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
197
src/x86_64/Gos-freebsd.c
Normal 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
155
src/x86_64/Gos-linux.c
Normal 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
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in a new issue