diff --git a/configure.in b/configure.in index 6e55563..5734f71 100644 --- a/configure.in +++ b/configure.in @@ -27,8 +27,9 @@ CHECK_ATOMIC_OPS dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h execinfo.h ia64intrin.h \ - sys/uc_access.h unistd.h signal.h) +AC_CHECK_HEADERS(asm/ptrace_offsets.h endian.h machine/endian.h execinfo.h \ + ia64intrin.h sys/uc_access.h unistd.h signal.h link.h \ + execinfo.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -44,6 +45,8 @@ else fi AC_CHECK_MEMBERS([struct dl_phdr_info.dlpi_subs],,,[#include ]) +AC_CHECK_MEMBERS([Link_map.l_addr],,,[#include ]) +AC_CHECK_MEMBERS([Dl_info.dli_fbase],,,[#include ]) AC_CHECK_TYPES([sighandler_t], [], [], [$ac_includes_default #if HAVE_SIGNAL_H @@ -54,8 +57,8 @@ AC_CHECK_TYPES([sighandler_t], [], [], dnl Checks for library functions. AC_FUNC_MEMCMP AC_TYPE_SIGNAL -AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo getunwind \ - ttrace) +AC_CHECK_FUNCS(dl_iterate_phdr dl_phdr_removals_counter dlmodinfo dladdr \ + dlinfo getunwind ttrace backtrace) is_gcc_m64() { if test `echo $CFLAGS | grep "\-m64" -c` -eq 1 ; then echo ppc64; else @@ -80,6 +83,7 @@ get_arch() { hppa*) echo hppa;; mips*) echo mips;; powerpc*) is_gcc_m64;; + amd64*) echo x86_64;; *) echo $1;; esac } @@ -99,6 +103,10 @@ AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32) AM_CONDITIONAL(ARCH_PPC64, test x$target_arch = xppc64) 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_FREEBSD, expr x$target_os : xfreebsd >/dev/null) +# XXX +AM_CONDITIONAL(PTRACE, test x$target_os = xlinux) +AM_CONDITIONAL(EXECINFO, test x$target_os = xlinux) if test x$target_arch = xppc64; then libdir='${exec_prefix}/lib64' diff --git a/include/libunwind-x86_64.h b/include/libunwind-x86_64.h index e337351..98af8e7 100644 --- a/include/libunwind-x86_64.h +++ b/include/libunwind-x86_64.h @@ -33,6 +33,7 @@ extern "C" { #endif #include +#include #include #define UNW_TARGET x86_64 diff --git a/include/libunwind_i.h b/include/libunwind_i.h index 27bfd8d..9971b3a 100644 --- a/include/libunwind_i.h +++ b/include/libunwind_i.h @@ -56,6 +56,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_ENDIAN_H # include +#elif defined(HAVE_MACHINE_ENDIAN_H) +# include +# define __LITTLE_ENDIAN _LITTLE_ENDIAN +# define __BIG_ENDIAN _BIG_ENDIAN #else # define __LITTLE_ENDIAN 1234 # define __BIG_ENDIAN 4321 @@ -206,6 +210,10 @@ do { \ #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) \ do { \ /* Hopefully, mmap() goes straight through to a system call stub... */ \ diff --git a/include/remote.h b/include/remote.h index 9fb90c3..c81f21a 100644 --- a/include/remote.h +++ b/include/remote.h @@ -1,6 +1,8 @@ #ifndef REMOTE_H #define REMOTE_H +#define WSIZE (sizeof (unw_word_t)) + /* Helper functions for accessing (remote) memory. These functions assume that all addresses are naturally aligned (e.g., 32-bit quantity is stored at a 32-bit-aligned address. */ @@ -45,8 +47,6 @@ fetchw (unw_addr_space_t as, unw_accessors_t *a, #else /* !UNW_LOCAL_ONLY */ -#define WSIZE (sizeof (unw_word_t)) - static inline int fetch8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, int8_t *valp, void *arg) diff --git a/src/Makefile.am b/src/Makefile.am index e6e3b33..dd9c9a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,21 +10,23 @@ LIBRARIES_cdep = lib_LTLIBRARIES_cdep = lib_LTLIBRARIES_cdep_setjmp = else -LIBRARIES_cdep = libunwind-ptrace.a +LIBRARIES_cdep = lib_LTLIBRARIES_cdep = libunwind.la lib_LTLIBRARIES_cdep_setjmp = libunwind-setjmp.la endif +if PTRACE ### libunwind-ptrace: -libunwind_ptrace_a_SOURCES = \ - ptrace/_UPT_elf.c \ - ptrace/_UPT_internal.h \ - ptrace/_UPT_accessors.c ptrace/_UPT_access_fpreg.c \ - ptrace/_UPT_access_mem.c ptrace/_UPT_access_reg.c \ - ptrace/_UPT_create.c ptrace/_UPT_destroy.c \ - ptrace/_UPT_find_proc_info.c ptrace/_UPT_get_dyn_info_list_addr.c \ - ptrace/_UPT_put_unwind_info.c ptrace/_UPT_get_proc_name.c \ - ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.c +libunwind_ptrace_a_SOURCES = \ + ptrace/_UPT_elf.c \ + ptrace/_UPT_internal.h \ + ptrace/_UPT_accessors.c ptrace/_UPT_access_fpreg.c \ + ptrace/_UPT_access_mem.c ptrace/_UPT_access_reg.c \ + ptrace/_UPT_create.c ptrace/_UPT_destroy.c \ + ptrace/_UPT_find_proc_info.c ptrace/_UPT_get_dyn_info_list_addr.c \ + ptrace/_UPT_put_unwind_info.c ptrace/_UPT_get_proc_name.c \ + ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.c +endif #PTRACE ### libunwind-setjmp: libunwind_setjmp_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \ @@ -97,6 +99,8 @@ libunwind_la_SOURCES_os_linux = os-linux.h os-linux.c libunwind_la_SOURCES_os_hpux = os-hpux.c +libunwind_la_SOURCES_os_freebsd = os-freebsd.h os-freebsd.c + dwarf_SOURCES_common = \ dwarf/global.c @@ -351,6 +355,11 @@ if OS_HPUX libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_hpux_local) endif +if OS_FREEBSD + libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_freebsd) + libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_freebsd_local) +endif + if ARCH_ARM lib_LTLIBRARIES_arch = libunwind-arm.la libunwind_la_SOURCES = $(libunwind_la_SOURCES_arm) @@ -488,7 +497,6 @@ EXTRA_DIST = elfxx.h elfxx.c unwind/unwind-internal.h \ $(libunwind_mips_la_SOURCES_mips) \ $(libunwind_x86_la_SOURCES_x86) \ $(libunwind_x86_64_la_SOURCES_x86_64) \ - $(libunwind_ptrace_a_SOURCES) \ $(libunwind_setjmp_la_SOURCES_common) \ $(libunwind_setjmp_la_SOURCES_arm) \ $(libunwind_setjmp_la_SOURCES_hppa) \ @@ -499,6 +507,10 @@ EXTRA_DIST = elfxx.h elfxx.c unwind/unwind-internal.h \ $(libunwind_setjmp_la_SOURCES_ppc32) \ $(libunwind_setjmp_la_SOURCES_ppc64) +if PTRACE +EXTRA_DIST += $(libunwind_ptrace_a_SOURCES) +endif #PTRACE + # The -version-info flag accepts an argument of the form # `current[:revision[:age]]'. So, passing `-version-info 3:12:1' sets diff --git a/src/setjmp/siglongjmp.c b/src/setjmp/siglongjmp.c index 9a091fa..b2195c9 100644 --- a/src/setjmp/siglongjmp.c +++ b/src/setjmp/siglongjmp.c @@ -31,6 +31,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "jmpbuf.h" #include "setjmp_i.h" +#ifndef _NSIG +/* FreeBSD defines it differently */ +#define _NSIG _SIG_MAXSIG +#endif + void siglongjmp (sigjmp_buf env, int val) { diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c index 031deaa..ae8a411 100644 --- a/src/x86_64/Ginit.c +++ b/src/x86_64/Ginit.c @@ -43,6 +43,7 @@ static struct unw_addr_space local_addr_space; PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space; +#ifdef __linux__ static inline void * uc_addr (ucontext_t *uc, int reg) { @@ -73,6 +74,40 @@ uc_addr (ucontext_t *uc, int reg) } return addr; } +#elif defined(__FreeBSD__) +static inline void * +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; +} +#else +#error "Unknown OS. Don't know how to decode mcontext" +#endif # ifdef UNW_LOCAL_ONLY diff --git a/src/x86_64/Gis_signal_frame.c b/src/x86_64/Gis_signal_frame.c index 72edf46..0ed93f6 100644 --- a/src/x86_64/Gis_signal_frame.c +++ b/src/x86_64/Gis_signal_frame.c @@ -27,7 +27,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "unwind_i.h" -#ifdef __linux__ +#include + +#if defined(__linux__) PROTECTED int unw_is_signal_frame (unw_cursor_t *cursor) { @@ -56,9 +58,43 @@ unw_is_signal_frame (unw_cursor_t *cursor) w1 &= 0xff; return (w0 == 0x0f0000000fc0c748 && w1 == 0x05); } +#elif defined(__FreeBSD__) +PROTECTED int +unw_is_signal_frame (unw_cursor_t *cursor) +{ +#ifdef notyet + 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; -#else /* __linux__ */ + as = c->dwarf.as; + a = unw_get_accessors (as); + arg = c->dwarf.as_arg; + + /* FreeBSD/amd64 sigreturn sequence looks like this + (see obj/lib/libc/sigreturn.o): + 48 c7 c0 a1 01 00 00 mov $0x1a1,%rax + 49 89 ca mov %rcx,%r10 + 0f 05 syscall + ... but what we probably need to look for is in fact + the trampoline (see src/contrib/gdb). + */ + 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 &= 0xffffffffff; + return (w0 == 0x49000001a1c0c48) && (w1 == 0x050fca89); +#else //notyet + printf ("%s: implement me\n", __FUNCTION__); + return -UNW_ENOINFO; +#endif +} +#else /* !defined(__linux__) && !defined(__FreeBSD__) */ PROTECTED int unw_is_signal_frame (unw_cursor_t *cursor) { diff --git a/src/x86_64/Gresume.c b/src/x86_64/Gresume.c index 54215c3..d3ffb65 100644 --- a/src/x86_64/Gresume.c +++ b/src/x86_64/Gresume.c @@ -35,13 +35,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* sigreturn() is a no-op on x86_64 glibc. */ +#ifdef __linux__ +#define SYS_SIGRETURN SYS_rt_sigreturn +#elif defined(__FreeBSD__) +#define SYS_SIGRETURN SYS_sigreturn +#endif + 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) + :: "r"(new_sp), "i"(SYS_SIGRETURN) : "memory"); abort (); } diff --git a/tests/Gtest-dyn1.c b/tests/Gtest-dyn1.c index de9854d..6bbc275 100644 --- a/tests/Gtest-dyn1.c +++ b/tests/Gtest-dyn1.c @@ -26,12 +26,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* This file tests dynamic code-generation via function-cloning. */ #include -#include #include #include #include #include +#ifndef __FreeBSD__ +#include +#endif + #include #if UNW_TARGET_ARM diff --git a/tests/Makefile.am b/tests/Makefile.am index 401a6ec..6f68df1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,18 +33,29 @@ endif #USE_ALTIVEC noinst_PROGRAMS_arch = $(noinst_PROGRAMS_arch_altivec) ppc64-test-wchar endif #ARCH_PPC64 endif #ARCH_IA64 - check_SCRIPTS_cdep = run-ptrace-mapper run-ptrace-misc - check_PROGRAMS_cdep = Gtest-bt Ltest-bt Gtest-exc Ltest-exc \ + + check_PROGRAMS_cdep = Ltest-bt Gtest-exc Ltest-exc \ Gtest-init Ltest-init \ Gtest-concurrent Ltest-concurrent \ Gtest-resume-sig Ltest-resume-sig \ Gtest-dyn1 Ltest-dyn1 \ - test-async-sig test-flush-cache test-init-remote \ - test-mem test-setjmp test-ptrace \ - Ltest-nomalloc rs-race - noinst_PROGRAMS_cdep = forker mapper test-ptrace-misc test-varargs \ + test-async-sig test-init-remote \ + test-mem test-setjmp \ + Ltest-nomalloc +if EXECINFO + check_PROGRAMS_cdep += Gtest-bt rs-race test-flush-cache +endif #EXECINFO + + noinst_PROGRAMS_cdep = forker mapper \ + test-varargs \ Gperf-simple Lperf-simple +if PTRACE + check_SCRIPTS_cdep = run-ptrace-mapper run-ptrace-misc + check_PROGRAMS_cdep += test-ptrace + noinst_PROGRAMS_cdep += test-ptrace-misc +endif #PTRACE + perf: perf-startup Gperf-simple Lperf-simple @echo "########## Basic performance of generic libunwind:" @./Gperf-simple @@ -88,19 +99,22 @@ test_static_link_LDFLAGS = -static forker_LDFLAGS = -static Gtest_bt_SOURCES = Gtest-bt.c ident.c Ltest_bt_SOURCES = Ltest-bt.c ident.c +if PTRACE test_ptrace_misc_SOURCES = test-ptrace-misc.c ident.c +endif #PTRACE LIBUNWIND = ../src/libunwind-$(arch).la $(LIBUNWIND_local) LDADD = $(LIBUNWIND) test_setjmp_LDADD = ../src/libunwind-setjmp.la $(LIBUNWIND_local) ia64_test_setjmp_LDADD = ../src/libunwind-setjmp.la $(LIBUNWIND_local) +if PTRACE test_ptrace_LDADD = ../src/libunwind-ptrace.a $(LIBUNWIND) +endif #PTRACE Ltest_concurrent_LDADD = $(LIBUNWIND) -lpthread Gtest_concurrent_LDADD = $(LIBUNWIND) -lpthread test_async_sig_LDADD = $(LIBUNWIND) -lpthread rs_race_LDADD = $(LIBUNWIND) -lpthread -LDADD += -ldl Ltest_nomalloc_SOURCES = Ltest-nomalloc.c diff --git a/tests/mapper.c b/tests/mapper.c index 1006a8c..423c048 100644 --- a/tests/mapper.c +++ b/tests/mapper.c @@ -36,6 +36,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + int main (int argc, char **argv) { diff --git a/tests/test-ptrace.c b/tests/test-ptrace.c index 1f46f7d..cc4a3b6 100644 --- a/tests/test-ptrace.c +++ b/tests/test-ptrace.c @@ -43,10 +43,15 @@ main (int argc, char **argv) #include #include #include +#include #include #include +#ifdef __FreeBSD__ +extern char **environ; +#endif + static const int nerrors_max = 100; int nerrors; @@ -209,7 +214,11 @@ main (int argc, char **argv) if (!verbose) dup2 (open ("/dev/null", O_WRONLY), 1); +#ifdef __FreeBSD__ + ptrace (PT_TRACE_ME, 0, 0, 0); +#else ptrace (PTRACE_TRACEME, 0, 0, 0); +#endif execve (argv[optind], argv + optind, environ); _exit (-1); } @@ -274,11 +283,19 @@ main (int argc, char **argv) { case TRIGGER: if (state) +#ifdef __FreeBSD__ + ptrace (PT_CONTINUE, target_pid, (caddr_t)1, 0); +#else ptrace (PTRACE_CONT, target_pid, 0, 0); +#endif else { do_backtrace (target_pid); +#ifdef __FreeBSD__ + ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig); +#else ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig); +#endif } break; @@ -286,12 +303,20 @@ main (int argc, char **argv) if (!state) do_backtrace (target_pid); state ^= 1; +#ifdef __FreeBSD__ + abort(); +#else ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig); +#endif break; case INSTRUCTION: do_backtrace (target_pid); +#ifdef __FreeBSD__ + ptrace (PT_STEP, target_pid, (caddr_t)1, pending_sig); +#else ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig); +#endif break; } if (killed)