-include_HEADERS = include/libunwind-dynamic.h \
- include/libunwind-ptrace.h \
- include/libunwind-coredump.h
+include_HEADERS = include/libunwind-dynamic.h
+
+if BUILD_PTRACE
+include_HEADERS += include/libunwind-ptrace.h
+endif BUILD_PTRACE
+
+if BUILD_COREDUMP
+include_HEADERS += include/libunwind-coredump.h
+endif BUILD_COREDUMP
if ARCH_AARCH64
include_HEADERS += include/libunwind-aarch64.h
nodist_include_HEADERS = include/libunwind-common.h
-SUBDIRS = src tests
+SUBDIRS = src
+
+if CONFIG_TESTS
+SUBDIRS += tests
+endif
if CONFIG_DOCS
SUBDIRS += doc
-*-Mode: outline-*-
+* News for v1.3:
+
+** Iteration of unwind register states support
+ Doug Moore <dougm@rice.edu>
+** Freebsd/Armv6 support
+ Konstantin Belousov <kib@freebsd.org>
+** Many, many dwarf bugfixes
+** Mips remote unwind support
+** aarch64 ptrace support
+
+* News for v1.2:
+
+** aarch64 port
+** dwarf parsing improvements
+** Fast stacktraces for aarch64 & arm
+** tilegx port
+** powerpc64 port
+
* News for v1.1:
** coredump unwind support
-*- mode: Outline -*-
-This is version 1.0 of the unwind library. This library supports
+[![Build Status](https://travis-ci.org/libunwind/libunwind.svg?branch=master)](https://travis-ci.org/libunwind/libunwind)
+
+This is version 1.3 of the unwind library. This library supports
several architecture/operating-system combinations:
Linux/x86-64: Works well.
Linux/x86: Works well.
Linux/ARM: Works well.
- Linux/IA-64: Fully tested and supported.
+ Linux/IA-64: Works well.
Linux/PARISC: Works well, but C library missing unwind-info.
HP-UX/IA-64: Mostly works but known to have some serious limitations.
- Linux/AArch64: Newly added.
+ MIPS: Newly added.
+ Linux/AArch64: Works well.
Linux/PPC64: Newly added.
Linux/SuperH: Newly added.
- FreeBSD/i386: Newly added.
+ FreeBSD/i386: Works well.
FreeBSD/x86-64: Newly added (FreeBSD architecture is known as amd64).
Linux/Tilegx: Newly added (64-bit mode only).
The following tests are expected to fail on x86 Linux:
- Gtest-resume-sig (fails to get SIGUSR2)
- Ltest-resume-sig (likewise)
- Gtest-dyn1 (no dynamic unwind info support yet)
- Ltest-dyn1 (no dynamic unwind info support yet)
- test-setjmp (longjmp() not implemented yet)
- run-check-namespace (no _Ux86_getcontext yet)
test-ptrace
** Expected results on x86-64 Linux
The following tests are expected to fail on x86-64 Linux:
- Gtest-dyn1 (no dynamic unwind info support yet)
- Ltest-dyn1 (no dynamic unwind info support yet)
- Gtest-init (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18743)
- Ltest-init (likewise)
- test-async-sig (crashes due to bad unwind-info?)
- test-setjmp (longjmp() not implemented yet)
- run-check-namespace (no _Ux86_64_getcontext yet)
- run-ptrace-mapper (??? investigate)
run-ptrace-misc (see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18748
and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18749)
web-interface at:
https://savannah.nongnu.org/mail/?group=libunwind
+
+Or interact at the gihub page:
+
+ https://github.com/libunwind/libunwind
define(pkg_major, 1)
-define(pkg_minor, 2)
-define(pkg_extra, )
+define(pkg_minor, 3)
+define(pkg_extra, 1)
define(pkg_maintainer, libunwind-devel@nongnu.org)
-define(mkvers, $1.$2$3)
+define(mkvers, $1.$2.$3)
dnl Process this file with autoconf to produce a configure script.
AC_INIT([libunwind],[mkvers(pkg_major, pkg_minor, pkg_extra)],[pkg_maintainer])
AC_CONFIG_SRCDIR(src/mi/backtrace.c)
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_MAKE_SET
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT
AM_PROG_AS
AM_PROG_CC_C_O
#endif
])
-AC_CHECK_DECLS([PTRACE_POKEUSER, PTRACE_POKEDATA,
+AC_CHECK_DECLS([PTRACE_POKEUSER, PTRACE_POKEDATA, PTRACE_SETREGSET,
PTRACE_TRACEME, PTRACE_CONT, PTRACE_SINGLESTEP,
PTRACE_SYSCALL, PT_IO, PT_GETREGS,
PT_GETFPREGS, PT_CONTINUE, PT_TRACE_ME,
SET_ARCH([$host_cpu],[host_arch])
SET_ARCH([$target_cpu],[target_arch])
+# Check for Android
+AC_MSG_CHECKING([for Android])
+android="no"
+case "$host_os" in
+ *android*)
+ android="yes"
+ AC_MSG_RESULT([yes])
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+esac
+
AC_ARG_ENABLE(coredump,
AS_HELP_STRING([--enable-coredump],[building libunwind-coredump library]),,
[AS_CASE([$host_arch], [aarch64*|arm*|mips*|sh*|x86*|tile*], [enable_coredump=yes], [enable_coredump=no])]
AS_HELP_STRING([--disable-documentation],[Disable generating the man pages]),,
[enable_documentation=yes])
+AC_ARG_ENABLE(tests,
+ AS_HELP_STRING([--disable-tests],[Disable tests build]),,
+ [enable_tests=yes])
+
AC_MSG_CHECKING([if we should build libunwind-setjmp])
AC_MSG_RESULT([$enable_setjmp])
AM_CONDITIONAL(BUILD_COREDUMP, test x$enable_coredump = xyes)
AM_CONDITIONAL(BUILD_PTRACE, test x$enable_ptrace = xyes)
AM_CONDITIONAL(BUILD_SETJMP, test x$enable_setjmp = xyes)
+AM_CONDITIONAL(NO_PTRACE_TEST, test x$build_arch != x$host_arch)
AM_CONDITIONAL(REMOTE_ONLY, test x$target_arch != x$host_arch)
AM_CONDITIONAL(ARCH_AARCH64, test x$target_arch = xaarch64)
AM_CONDITIONAL(ARCH_ARM, test x$target_arch = xarm)
AS_HELP_STRING([--enable-debug-frame],[Load the ".debug_frame" section if available]),, [
case "${target_arch}" in
(arm) enable_debug_frame=yes;;
+ (aarch64) enable_debug_frame=yes;;
(*) enable_debug_frame=no;;
esac])
if test x$enable_debug_frame = xyes; then
AC_SUBST([LIBLZMA])
AM_CONDITIONAL(HAVE_LZMA, test x$enable_minidebuginfo = xyes)
-LIBUNWIND___THREAD
+AC_MSG_CHECKING([whether to support UNW_CACHE_PER_THREAD])
+AC_ARG_ENABLE([per-thread-cache],
+AS_HELP_STRING([--enable-per-thread-cache], [build with support for UNW_CACHE_PER_THREAD (which imposes a hight TLS memory usage) (default: disabled)]))
+AC_MSG_RESULT([$enable_per_thread_cache])
+AS_IF([test x$enable_per_thread_cache = xyes], [
+ LIBUNWIND___THREAD
+ AS_IF([test x$libc_cv_gcc___thread = xno], [
+ AC_MSG_FAILURE([UNW_CACHE_PER_THREAD requires __thread])
+ ])
+])
AC_MSG_CHECKING([for Intel compiler])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[#ifndef __INTEL_COMPILER
LDFLAGS_NOSTARTFILES="-XCClinker -nostartfiles"
fi
-if test x$GCC = xyes -a x$intel_compiler != xyes -a x$qcc_compiler != xyes; then
+if test x$GCC = xyes -a x$intel_compiler != xyes -a x$qcc_compiler != xyes -a x$android != xyes; then
LIBCRTS="-lgcc_s"
fi
LIBS=""
AC_SEARCH_LIBS(backtrace, execinfo)
LIBS="$old_LIBS"
+case "$ac_cv_search_backtrace" in
+ -l*) BACKTRACELIB=$ac_cv_search_backtrace;;
+ *) BACKTRACELIB="";;
+esac
+
AC_SUBST(build_arch)
AC_SUBST(target_os)
AC_SUBST(enable_cxx_exceptions)
AC_SUBST(enable_debug_frame)
AC_SUBST(DLLIB)
+AC_SUBST(BACKTRACELIB)
AC_PATH_PROG([LATEX2MAN],[latex2man])
if test "x$LATEX2MAN" = "x"; then
AC_CONFIG_FILES(doc/Makefile doc/common.tex)
fi
-AC_CONFIG_FILES(Makefile src/Makefile tests/Makefile tests/check-namespace.sh
- include/libunwind-common.h
+AM_CONDITIONAL([CONFIG_TESTS], [test x$enable_tests = xyes])
+if test "x$enable_tests" = "xyes"; then
+ AC_CONFIG_FILES(tests/Makefile tests/check-namespace.sh)
+fi
+
+AC_CONFIG_FILES(Makefile src/Makefile
+ include/libunwind-common.h
include/libunwind.h include/tdep/libunwind_i.h)
AC_CONFIG_FILES(src/unwind/libunwind.pc src/coredump/libunwind-coredump.pc
src/ptrace/libunwind-ptrace.pc src/setjmp/libunwind-setjmp.pc
# man pages that go into section 3:
man3_MANS = libunwind.man libunwind-dynamic.man libunwind-ia64.man \
libunwind-ptrace.man libunwind-setjmp.man \
+ unw_apply_reg_state.man \
unw_backtrace.man \
unw_flush_cache.man \
unw_get_accessors.man \
unw_get_reg.man \
unw_getcontext.man \
unw_init_local.man unw_init_remote.man \
+ unw_init_local2.man \
unw_is_fpreg.man \
unw_is_signal_frame.man \
unw_create_addr_space.man \
unw_destroy_addr_space.man \
unw_regname.man unw_resume.man \
+ unw_reg_states_iterate.man \
unw_set_caching_policy.man \
+ unw_set_cache_size.man \
unw_set_fpreg.man \
unw_set_reg.man \
unw_step.man \
EXTRA_DIST = NOTES libunwind.trans \
libunwind.tex libunwind-dynamic.tex libunwind-ia64.tex \
libunwind-ptrace.tex libunwind-setjmp.tex \
+ unw_apply_reg_state.tex \
unw_backtrace.tex \
unw_flush_cache.tex \
unw_get_accessors.tex \
unw_is_signal_frame.tex \
unw_create_addr_space.tex unw_destroy_addr_space.tex \
unw_regname.tex unw_resume.tex unw_set_caching_policy.tex \
+ unw_reg_states_iterate.tex \
+ unw_set_cache_size.tex \
unw_set_fpreg.tex \
unw_set_reg.tex \
unw_step.tex \
'\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:43 MDT 2007
+.\" Manual page created with latex2man on Thu Jan 12 06:50:29 PST 2017
.\" NOTE: This file is generated, DO NOT EDIT.
.de Vb
.ft CW
.fi
..
-.TH "LIBUNWIND" "3" "16 August 2007" "Programming Library " "Programming Library "
+.TH "LIBUNWIND" "3" "12 January 2017" "Programming Library " "Programming Library "
.SH NAME
libunwind
\-\- a (mostly) platform\-independent unwind API
unw_set_caching_policy(unw_addr_space_t,
unw_caching_policy_t);
.br
+int
+unw_set_cache_size(unw_addr_space_t,
+size_t,
+int);
+.br
.PP
const char *unw_regname(unw_regnum_t);
.br
it is possible to turn off caching
completely, therefore eliminating the risk of stale data alltogether
(at the cost of slower execution). By default, caching is enabled for
-local unwinding only.
+local unwinding only. The cache size can be dynamically changed with
+unw_set_cache_size(),
+which also fluches the current cache.
.PP
.SH FILES
unw_regname(3),
unw_resume(3),
unw_set_caching_policy(3),
+unw_set_cache_size(3),
unw_set_fpreg(3),
unw_set_reg(3),
unw_step(3),
\Type{void} \Func{unw\_flush\_cache}(\Type{unw\_addr\_space\_t}, \Type{unw\_word\_t}, \Type{unw\_word\_t});\\
\noindent
\Type{int} \Func{unw\_set\_caching\_policy}(\Type{unw\_addr\_space\_t}, \Type{unw\_caching\_policy\_t});\\
+\noindent
+\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t}, \Type{size\_t}, \Type{int});\\
\noindent
\Type{const char *}\Func{unw\_regname}(\Type{unw\_regnum\_t});\\
\Const{UNW\_CACHE\_NONE}, it is possible to turn off caching
completely, therefore eliminating the risk of stale data alltogether
(at the cost of slower execution). By default, caching is enabled for
-local unwinding only.
+local unwinding only. The cache size can be dynamically changed with
+\Func{unw\_set\_cache\_size}(), which also fluches the current cache.
\section{Files}
\SeeAlso{unw\_regname(3)},
\SeeAlso{unw\_resume(3)},
\SeeAlso{unw\_set\_caching\_policy(3)},
+\SeeAlso{unw\_set\_cache\_size(3)},
\SeeAlso{unw\_set\_fpreg(3)},
\SeeAlso{unw\_set\_reg(3)},
\SeeAlso{unw\_step(3)},
--- /dev/null
+'\" t
+.\" Manual page created with latex2man on Wed Aug 16 11:09:44 PDT 2017
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "UNW\\_APPLY\\_REG\\_STATE" "3" "16 August 2017" "Programming Library " "Programming Library "
+.SH NAME
+unw_apply_reg_state
+\-\- apply a register state update to a cursor
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <libunwind.h>
+.br
+.PP
+int
+unw_apply_reg_state(unw_cursor_t *cp,
+void *reg_states_data);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unw_apply_reg_state()
+routine updates the register values
+of a cursor according to the instructions in reg_states_data,
+which have been obtained by calling unw_reg_states_iterate\&.
+.PP
+.SH RETURN VALUE
+
+.PP
+On successful completion, unw_apply_reg_state()
+returns 0.
+Otherwise the negative value of one of the error\-codes below is
+returned.
+.PP
+.SH THREAD AND SIGNAL SAFETY
+
+.PP
+unw_apply_reg_state()
+is thread\-safe. If cursor cp
+is
+in the local address\-space, this routine is also safe to use from a
+signal handler.
+.PP
+.SH ERRORS
+
+.PP
+.TP
+UNW_EUNSPEC
+ An unspecified error occurred.
+.TP
+UNW_ENOINFO
+ Libunwind
+was unable to locate
+unwind\-info for the procedure.
+.TP
+UNW_EBADVERSION
+ The unwind\-info for the procedure has
+version or format that is not understood by libunwind\&.
+.PP
+In addition, unw_apply_reg_state()
+may return any error
+returned by the access_mem()
+call\-back (see
+unw_create_addr_space(3)).
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+unw_reg_states_iterate(3)
+.PP
+.SH AUTHOR
+
+.PP
+David Mosberger\-Tang
+.br
+Email: \fBdmosberger@gmail.com\fP
+.br
+WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&.
+.\" NOTE: This file is generated, DO NOT EDIT.
--- /dev/null
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{unw\_apply\_reg\_state}{David Mosberger-Tang}{Programming Library}{unw\_apply\_reg\_state}unw\_apply\_reg\_state -- apply a register state update to a cursor
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$libunwind.h$>$}\\
+
+\Type{int}
+\Func{unw\_apply\_reg\_state}(\Type{unw\_cursor\_t~*}\Var{cp},
+\Type{void~*}\Var{reg\_states\_data});\\
+
+\section{Description}
+
+The \Func{unw\_apply\_reg\_state}() routine updates the register values
+of a cursor according to the instructions in \Var{reg\_states\_data},
+which have been obtained by calling \Var{unw\_reg\_states\_iterate}.
+
+\section{Return Value}
+
+On successful completion, \Func{unw\_apply\_reg\_state}() returns 0.
+Otherwise the negative value of one of the error-codes below is
+returned.
+
+\section{Thread and Signal Safety}
+
+\Func{unw\_apply\_reg\_state}() is thread-safe. If cursor \Var{cp} is
+in the local address-space, this routine is also safe to use from a
+signal handler.
+
+\section{Errors}
+
+\begin{Description}
+\item[\Const{UNW\_EUNSPEC}] An unspecified error occurred.
+\item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate
+ unwind-info for the procedure.
+\item[\Const{UNW\_EBADVERSION}] The unwind-info for the procedure has
+ version or format that is not understood by \Prog{libunwind}.
+\end{Description}
+In addition, \Func{unw\_apply\_reg\_state}() may return any error
+returned by the \Func{access\_mem}() call-back (see
+\Func{unw\_create\_addr\_space}(3)).
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+\SeeAlso{unw\_reg\_states\_iterate(3)}
+
+\section{Author}
+
+\noindent
+David Mosberger-Tang\\
+Email: \Email{dmosberger@gmail.com}\\
+WWW: \URL{http://www.nongnu.org/libunwind/}.
+\LatexManEnd
+
+\end{document}
'\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:44 MDT 2007
+.\" Manual page created with latex2man on Fri Dec 2 16:09:33 PST 2016
.\" NOTE: This file is generated, DO NOT EDIT.
.de Vb
.ft CW
.fi
..
-.TH "UNW\\_FLUSH\\_CACHE" "3" "16 August 2007" "Programming Library " "Programming Library "
+.TH "UNW\\_FLUSH\\_CACHE" "3" "02 December 2016" "Programming Library " "Programming Library "
.SH NAME
unw_flush_cache
\-\- flush cached info
.PP
libunwind(3),
unw_set_caching_policy(3)
+unw_set_cache_size(3)
.PP
.SH AUTHOR
\SeeAlso{libunwind(3)},
\SeeAlso{unw\_set\_caching\_policy(3)}
+\SeeAlso{unw\_set\_cache\_size(3)}
\section{Author}
'\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007
+.\" Manual page created with latex2man on Wed Aug 16 12:11:05 PDT 2017
.\" NOTE: This file is generated, DO NOT EDIT.
.de Vb
.ft CW
.fi
..
-.TH "UNW\\_INIT\\_LOCAL" "3" "16 August 2007" "Programming Library " "Programming Library "
+.TH "UNW\\_INIT\\_LOCAL" "3" "16 August 2017" "Programming Library " "Programming Library "
.SH NAME
unw_init_local
\-\- initialize cursor for local unwinding
unw_init_local(unw_cursor_t *c,
unw_context_t *ctxt);
.br
+int
+unw_init_local2(unw_cursor_t *c,
+unw_context_t *ctxt,
+int
+flag);
+.br
.PP
.SH DESCRIPTION
As such, the machine\-state pointed to by
ctxt
identifies the initial stack frame at which unwinding
-starts. The machine\-state must remain valid for the duration for
+starts. The machine\-state is expected to be one provided by a call to
+unw_getcontext; as such, the instruction pointer may point to the
+instruction after the last instruction of a function, and libunwind
+will back\-up the instruction pointer before beginning a walk up the
+call stack. The machine\-state must remain valid for the duration for
which the cursor c
is in use.
.PP
the address space of the current process (i.e., for local unwinding).
For all other cases, unw_init_remote()
must be used instead.
-From a behavioral point of view, the call:
-.PP
-.Vb
- ret = unw_init_local(&cursor, &ucontext);
-.Ve
-is equivalent to:
-.PP
-.Vb
- ret = unw_init_remote(&cursor, unw_local_addr_space,
- &ucontext);
-.Ve
However, unwind performance may be better when using
unw_init_local().
Also, unw_init_local()
whereas unw_init_remote()
is not.
.PP
+If the unw_context_t is known to be a signal frame (i.e., from the
+third argument in a sigaction handler on linux),
+unw_init_local2()
+should be used for correct initialization
+on some platforms, passing the UNW_INIT_SIGNAL_FRAME flag.
+.PP
.SH RETURN VALUE
.PP
\File{\#include $<$libunwind.h$>$}\\
\Type{int} \Func{unw\_init\_local}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_context\_t~*}\Var{ctxt});\\
+\Type{int} \Func{unw\_init\_local2}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_context\_t~*}\Var{ctxt}, \Type{int} \Var{flag});\\
\section{Description}
pointed to by \Var{c} with the machine-state in the context structure
pointed to by \Var{ctxt}. As such, the machine-state pointed to by
\Var{ctxt} identifies the initial stack frame at which unwinding
-starts. The machine-state must remain valid for the duration for
+starts. The machine-state is expected to be one provided by a call to
+unw_getcontext; as such, the instruction pointer may point to the
+instruction after the last instruction of a function, and libunwind
+will back-up the instruction pointer before beginning a walk up the
+call stack. The machine-state must remain valid for the duration for
which the cursor \Var{c} is in use.
The \Func{unw\_init\_local}() routine can be used only for unwinding in
the address space of the current process (i.e., for local unwinding).
For all other cases, \Func{unw\_init\_remote}() must be used instead.
-From a behavioral point of view, the call:
-
-\begin{verbatim}
- ret = unw_init_local(&cursor, &ucontext);
-\end{verbatim}
-is equivalent to:
-
-\begin{verbatim}
- ret = unw_init_remote(&cursor, unw_local_addr_space,
- &ucontext);
-\end{verbatim}
However, unwind performance may be better when using
\Func{unw\_init\_local}(). Also, \Func{unw\_init\_local}() is
available even when \Const{UNW\_LOCAL\_ONLY} has been defined before
including \File{$<$libunwind.h$>$}, whereas \Func{unw\_init\_remote}()
is not.
+If the unw_context_t is known to be a signal frame (i.e., from the
+third argument in a sigaction handler on linux),
+\Func{unw\_init\_local2}() should be used for correct initialization
+on some platforms, passing the UNW_INIT_SIGNAL_FRAME flag.
+
\section{Return Value}
On successful completion, \Func{unw\_init\_local}() returns 0.
--- /dev/null
+.so man3/unw_init_local.3
--- /dev/null
+'\" t
+.\" Manual page created with latex2man on Wed Aug 16 11:09:44 PDT 2017
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "UNW\\_REG\\_STATES\\_ITERATE" "3" "16 August 2017" "Programming Library " "Programming Library "
+.SH NAME
+unw_reg_states_iterate
+\-\- get register state info on current procedure
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <libunwind.h>
+.br
+.PP
+int
+unw_reg_states_iterate(unw_cursor_t *cp,
+unw_reg_states_callbackcb,
+void *token);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unw_reg_states_iterate()
+routine provides
+information about the procedure that created the stack frame
+identified by argument cp\&.
+The cb
+argument is a pointer
+to a function of type unw_reg_states_callback
+which is used to
+return the information. The function unw_reg_states_callback
+has the
+following definition:
+.PP
+int
+( *unw_reg_states_callback)(void *token,
+void *reg_states_data,
+size_t
+reg_states_data_size,
+unw_word_t
+start_ip,
+unw_word_t
+end_ip);
+.PP
+The callback function may be invoked several times for each call of unw_reg_states_iterate\&.
+Each call is associcated with a instruction address range and a set of instructions on how to update register values when returning from the procedure in that address range. For each invocation, the arguments to the callback function are:
+.TP
+void * token
+ The token value passed to unw_reg_states_callback\&.
+.br
+.TP
+void * reg_states_data
+ A pointer to data about
+updating register values. This data, or a copy of it, can be passed
+to unw_apply_reg_state\&.
+.br
+.TP
+int reg_states_data_size
+ The size of the register update data.
+.br
+.TP
+unw_word_t start_ip
+ The address of the first
+instruction of the address range.
+.br
+.TP
+unw_word_t end_ip
+ The address of the first
+instruction \fIbeyond\fP
+the end of the address range.
+.br
+.PP
+.SH RETURN VALUE
+
+.PP
+On successful completion, unw_reg_states_iterate()
+returns
+0. If the callback function returns a nonzero value, that indicates
+failure and the function returns immediately. Otherwise the negative
+value of one of the error\-codes below is returned.
+.PP
+.SH THREAD AND SIGNAL SAFETY
+
+.PP
+unw_reg_states_iterate()
+is thread\-safe. If cursor cp
+is
+in the local address\-space, this routine is also safe to use from a
+signal handler.
+.PP
+.SH ERRORS
+
+.PP
+.TP
+UNW_EUNSPEC
+ An unspecified error occurred.
+.TP
+UNW_ENOINFO
+ Libunwind
+was unable to locate
+unwind\-info for the procedure.
+.TP
+UNW_EBADVERSION
+ The unwind\-info for the procedure has
+version or format that is not understood by libunwind\&.
+.PP
+In addition, unw_reg_states_iterate()
+may return any error
+returned by the access_mem()
+call\-back (see
+unw_create_addr_space(3)).
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+unw_apply_reg_state(3)
+.PP
+.SH AUTHOR
+
+.PP
+David Mosberger\-Tang
+.br
+Email: \fBdmosberger@gmail.com\fP
+.br
+WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&.
+.\" NOTE: This file is generated, DO NOT EDIT.
--- /dev/null
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{unw\_reg\_states\_iterate}{David Mosberger-Tang}{Programming Library}{unw\_reg\_states\_iterate}unw\_reg\_states\_iterate -- get register state info on current procedure
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$libunwind.h$>$}\\
+
+\Type{int} \Func{unw\_reg\_states\_iterate}(\Type{unw\_cursor\_t~*}\Var{cp}, \Type{unw\_reg\_states\_callback}\Var{cb}, \Type{void~*}\Var{token});\\
+
+\section{Description}
+
+The \Func{unw\_reg\_states\_iterate}() routine provides
+information about the procedure that created the stack frame
+identified by argument \Var{cp}. The \Var{cb} argument is a pointer
+to a function of type \Type{unw\_reg\_states\_callback} which is used to
+return the information. The function \Type{unw\_reg\_states\_callback} has the
+following definition:
+
+\Type{int} (~*\Var{unw\_reg\_states\_callback})(\Type{void~*}\Var{token},
+ \Type{void~*}\Var{reg\_states\_data},
+ \Type{size\_t} \Var{reg\_states\_data\_size},
+ \Type{unw\_word\_t} \Var{start\_ip}, \Type{unw\_word\_t} \Var{end\_ip});
+
+The callback function may be invoked several times for each call of \Func{unw\_reg\_states\_iterate}. Each call is associcated with a instruction address range and a set of instructions on how to update register values when returning from the procedure in that address range. For each invocation, the arguments to the callback function are:
+\begin{description}
+\item[\Type{void~*} \Var{token}] The token value passed to \Var{unw\_reg\_states\_callback}. \\
+\item[\Type{void~*} \Var{reg\_states\_data}] A pointer to data about
+ updating register values. This data, or a copy of it, can be passed
+ to \Var{unw\_apply\_reg\_state}.\\
+\item[\Type{int} \Var{reg\_states\_data\_size}] The size of the register update data. \\
+\item[\Type{unw\_word\_t} \Var{start\_ip}] The address of the first
+ instruction of the address range. \\
+\item[\Type{unw\_word\_t} \Var{end\_ip}] The address of the first
+ instruction \emph{beyond} the end of the address range. \\
+\end{description}
+
+\section{Return Value}
+
+On successful completion, \Func{unw\_reg\_states\_iterate}() returns
+0. If the callback function returns a nonzero value, that indicates
+failure and the function returns immediately. Otherwise the negative
+value of one of the error-codes below is returned.
+
+\section{Thread and Signal Safety}
+
+\Func{unw\_reg\_states\_iterate}() is thread-safe. If cursor \Var{cp} is
+in the local address-space, this routine is also safe to use from a
+signal handler.
+
+\section{Errors}
+
+\begin{Description}
+\item[\Const{UNW\_EUNSPEC}] An unspecified error occurred.
+\item[\Const{UNW\_ENOINFO}] \Prog{Libunwind} was unable to locate
+ unwind-info for the procedure.
+\item[\Const{UNW\_EBADVERSION}] The unwind-info for the procedure has
+ version or format that is not understood by \Prog{libunwind}.
+\end{Description}
+In addition, \Func{unw\_reg\_states\_iterate}() may return any error
+returned by the \Func{access\_mem}() call-back (see
+\Func{unw\_create\_addr\_space}(3)).
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+\SeeAlso{unw\_apply\_reg\_state(3)}
+
+\section{Author}
+
+\noindent
+David Mosberger-Tang\\
+Email: \Email{dmosberger@gmail.com}\\
+WWW: \URL{http://www.nongnu.org/libunwind/}.
+\LatexManEnd
+
+\end{document}
--- /dev/null
+'\" t
+.\" Manual page created with latex2man on Fri Jan 13 08:33:21 PST 2017
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "UNW\\_SET\\_CACHE\\_SIZE" "3" "13 January 2017" "Programming Library " "Programming Library "
+.SH NAME
+unw_set_cache_size
+\-\- set unwind cache size
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <libunwind.h>
+.br
+.PP
+int
+unw_set_cache_size(unw_addr_space_t
+as,
+size_t
+size,
+int
+flag);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unw_set_cache_size()
+routine sets the cache size of
+address space as
+to hold at least as many items as given by
+argument size\&.
+It may hold more items as determined by the
+implementation. To disable caching, call
+unw_set_caching_policy)
+with a policy of
+UNW_CACHE_NONE\&.
+Flag is currently unused and must be 0.
+.PP
+.SH RETURN VALUE
+
+.PP
+On successful completion, unw_set_cache_size()
+returns 0.
+Otherwise the negative value of one of the error\-codes below is
+returned.
+.PP
+.SH THREAD AND SIGNAL SAFETY
+
+.PP
+unw_set_cache_size()
+is thread\-safe but \fInot\fP
+safe
+to use from a signal handler.
+.PP
+.SH ERRORS
+
+.PP
+.TP
+UNW_ENOMEM
+ The desired cache size could not be
+established because the application is out of memory.
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+unw_create_addr_space(3),
+unw_set_caching_policy(3),
+unw_flush_cache(3)
+.PP
+.SH AUTHOR
+
+.PP
+Dave Watson
+.br
+Email: \fBdade.watson@gmail.com\fP
+.br
+WWW: \fBhttp://www.nongnu.org/libunwind/\fP\&.
+.\" NOTE: This file is generated, DO NOT EDIT.
--- /dev/null
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{unw\_set\_cache\_size}{Dave Watson}{Programming Library}{unw\_set\_cache\_size}unw\_set\_cache\_size -- set unwind cache size
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$libunwind.h$>$}\\
+
+\Type{int} \Func{unw\_set\_cache\_size}(\Type{unw\_addr\_space\_t} \Var{as}, \Type{size\_t} \Var{size}, \Type{int} \Var{flag});\\
+
+\section{Description}
+
+The \Func{unw\_set\_cache\_size}() routine sets the cache size of
+address space \Var{as} to hold at least as many items as given by
+argument \Var{size}. It may hold more items as determined by the
+implementation. To disable caching, call
+\Func{unw\_set\_caching\_policy}) with a policy of
+\Const{UNW\_CACHE\_NONE}. Flag is currently unused and must be 0.
+
+\section{Return Value}
+
+On successful completion, \Func{unw\_set\_cache\_size}() returns 0.
+Otherwise the negative value of one of the error-codes below is
+returned.
+
+\section{Thread and Signal Safety}
+
+\Func{unw\_set\_cache\_size}() is thread-safe but \emph{not} safe
+to use from a signal handler.
+
+\section{Errors}
+
+\begin{Description}
+\item[\Const{UNW\_ENOMEM}] The desired cache size could not be
+ established because the application is out of memory.
+\end{Description}
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+\SeeAlso{unw\_create\_addr\_space(3)},
+\SeeAlso{unw\_set\_caching\_policy(3)},
+\SeeAlso{unw\_flush\_cache(3)}
+
+\section{Author}
+
+\noindent
+Dave Watson\\
+Email: \Email{dade.watson@gmail.com}\\
+WWW: \URL{http://www.nongnu.org/libunwind/}.
+\LatexManEnd
+
+\end{document}
'\" t
-.\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007
+.\" Manual page created with latex2man on Fri Dec 2 16:09:33 PST 2016
.\" NOTE: This file is generated, DO NOT EDIT.
.de Vb
.ft CW
.fi
..
-.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "16 August 2007" "Programming Library " "Programming Library "
+.TH "UNW\\_SET\\_CACHING\\_POLICY" "3" "02 December 2016" "Programming Library " "Programming Library "
.SH NAME
unw_set_caching_policy
\-\- set unwind caching policy
.PP
libunwind(3),
unw_create_addr_space(3),
+unw_set_cache_size(3),
unw_flush_cache(3)
.PP
.SH AUTHOR
\SeeAlso{libunwind(3)},
\SeeAlso{unw\_create\_addr\_space(3)},
+\SeeAlso{unw\_set\_cache\_size(3)},
\SeeAlso{unw\_flush\_cache(3)}
\section{Author}
# define UNUSED __attribute__((unused))
# define NOINLINE __attribute__((noinline))
# define NORETURN __attribute__((noreturn))
-# define ALIAS(name) __attribute__((alias (#name)))
+# define ALIAS2(name) #name
+# define ALIAS(name) __attribute__((alias (ALIAS2(name))))
# if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
# define ALWAYS_INLINE inline __attribute__((always_inline))
# define HIDDEN __attribute__((visibility ("hidden")))
-# define PROTECTED __attribute__((visibility ("protected")))
# else
# define ALWAYS_INLINE
# define HIDDEN
-# define PROTECTED
# endif
# define WEAK __attribute__((weak))
# if (__GNUC__ >= 3)
# define NORETURN
# define ALIAS(name)
# define HIDDEN
-# define PROTECTED
# define WEAK
# define likely(x) (x)
# define unlikely(x) (x)
#define DW_EH_VERSION 1 /* The version we're implementing */
-struct dwarf_eh_frame_hdr
+struct __attribute__((packed)) dwarf_eh_frame_hdr
{
unsigned char version;
unsigned char eh_frame_ptr_enc;
unsigned char fde_count_enc;
unsigned char table_enc;
+ Elf_W (Addr) eh_frame;
/* The rest of the header is variable-length and consists of the
following members:
- encoded_t eh_frame_ptr;
encoded_t fde_count;
struct
{
# include "config.h"
#endif
-#ifdef HAVE___THREAD
- /* For now, turn off per-thread caching. It uses up too much TLS
- memory per thread even when the thread never uses libunwind at
- all. */
-# undef HAVE___THREAD
-#endif
-
#ifndef UNW_REMOTE_ONLY
#if defined(HAVE_LINK_H)
#include <link.h>
}
dwarf_expr_op_t;
-#define DWARF_CIE_VERSION 3 /* GCC emits version 1??? */
+#define DWARF_CIE_VERSION 3
+#define DWARF_CIE_VERSION_MAX 4
#define DWARF_CFA_OPCODE_MASK 0xc0
#define DWARF_CFA_OPERAND_MASK 0x3f
}
dwarf_where_t;
-typedef struct
- {
- dwarf_where_t where; /* how is the register saved? */
- unw_word_t val; /* where it's saved */
- }
-dwarf_save_loc_t;
-
/* For uniformity, we'd like to treat the CFA save-location like any
other register save-location, but this doesn't quite work, because
the CFA can be expressed as a (REGISTER,OFFSET) pair. To handle
#define DWARF_CFA_REG_COLUMN DWARF_NUM_PRESERVED_REGS
#define DWARF_CFA_OFF_COLUMN (DWARF_NUM_PRESERVED_REGS + 1)
+typedef struct dwarf_reg_only_state
+ {
+ char where[DWARF_NUM_PRESERVED_REGS + 2]; /* how is the register saved? */
+ unw_word_t val[DWARF_NUM_PRESERVED_REGS + 2]; /* where it's saved */
+ }
+dwarf_reg_only_state_t;
+
typedef struct dwarf_reg_state
{
- struct dwarf_reg_state *next; /* for rs_stack */
- dwarf_save_loc_t reg[DWARF_NUM_PRESERVED_REGS + 2];
+ unw_word_t ret_addr_column; /* which column in rule table represents return address */
+ dwarf_reg_only_state_t reg;
+ }
+dwarf_reg_state_t;
+
+typedef struct dwarf_stackable_reg_state
+ {
+ struct dwarf_stackable_reg_state *next; /* for rs_stack */
+ dwarf_reg_state_t state;
+ }
+dwarf_stackable_reg_state_t;
+
+typedef struct dwarf_reg_cache_entry
+ {
unw_word_t ip; /* ip this rs is for */
- unw_word_t ret_addr_column; /* indicates which column in the rule table represents return address */
- unsigned short lru_chain; /* used for least-recently-used chain */
unsigned short coll_chain; /* used for hash collisions */
unsigned short hint; /* hint for next rs to try (or -1) */
unsigned short valid : 1; /* optional machine-dependent signal info */
unsigned short signal_frame : 1; /* optional machine-dependent signal info */
}
-dwarf_reg_state_t;
+dwarf_reg_cache_entry_t;
typedef struct dwarf_cie_info
{
unw_word_t cfa; /* canonical frame address; aka frame-/stack-pointer */
unw_word_t ip; /* instruction pointer */
unw_word_t args_size; /* size of arguments */
- unw_word_t ret_addr_column; /* column for return-address */
unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS];
unsigned int eh_valid_mask;
}
dwarf_cursor_t;
-#define DWARF_LOG_UNW_CACHE_SIZE 7
-#define DWARF_UNW_CACHE_SIZE (1 << DWARF_LOG_UNW_CACHE_SIZE)
+#define DWARF_DEFAULT_LOG_UNW_CACHE_SIZE 7
+#define DWARF_DEFAULT_UNW_CACHE_SIZE (1 << DWARF_DEFAULT_LOG_UNW_CACHE_SIZE)
-#define DWARF_LOG_UNW_HASH_SIZE (DWARF_LOG_UNW_CACHE_SIZE + 1)
-#define DWARF_UNW_HASH_SIZE (1 << DWARF_LOG_UNW_HASH_SIZE)
+#define DWARF_DEFAULT_LOG_UNW_HASH_SIZE (DWARF_DEFAULT_LOG_UNW_CACHE_SIZE + 1)
+#define DWARF_DEFAULT_UNW_HASH_SIZE (1 << DWARF_DEFAULT_LOG_UNW_HASH_SIZE)
typedef unsigned char unw_hash_index_t;
struct dwarf_rs_cache
{
pthread_mutex_t lock;
- unsigned short lru_head; /* index of lead-recently used rs */
- unsigned short lru_tail; /* index of most-recently used rs */
+ unsigned short rr_head; /* index of least-recently allocated rs */
+
+ unsigned short log_size;
+ unsigned short prev_log_size;
/* hash table that maps instruction pointer to rs index: */
- unsigned short hash[DWARF_UNW_HASH_SIZE];
+ unsigned short *hash;
uint32_t generation; /* generation number */
/* rs cache: */
- dwarf_reg_state_t buckets[DWARF_UNW_CACHE_SIZE];
+ dwarf_reg_state_t *buckets;
+ dwarf_reg_cache_entry_t *links;
+
+ /* default memory, loaded in BSS segment */
+ unsigned short default_hash[DWARF_DEFAULT_UNW_HASH_SIZE];
+ dwarf_reg_state_t default_buckets[DWARF_DEFAULT_UNW_CACHE_SIZE];
+ dwarf_reg_cache_entry_t default_links[DWARF_DEFAULT_UNW_CACHE_SIZE];
};
/* A list of descriptors for loaded .debug_frame sections. */
struct unw_debug_frame_list *next;
};
-struct dwarf_callback_data
- {
- /* in: */
- unw_word_t ip; /* instruction-pointer we're looking for */
- unw_proc_info_t *pi; /* proc-info pointer */
- int need_unwind_info;
- /* out: */
- int single_fde; /* did we find a single FDE? (vs. a table) */
- unw_dyn_info_t di; /* table info (if single_fde is false) */
- unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
- };
-
/* Convenience macros: */
#define dwarf_init UNW_ARCH_OBJ (dwarf_init)
#define dwarf_callback UNW_OBJ (dwarf_callback)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
#define dwarf_put_unwind_info UNW_OBJ (dwarf_put_unwind_info)
#define dwarf_eval_expr UNW_OBJ (dwarf_eval_expr)
+#define dwarf_stack_aligned UNW_OBJ (dwarf_stack_aligned)
#define dwarf_extract_proc_info_from_fde \
UNW_OBJ (dwarf_extract_proc_info_from_fde)
#define dwarf_find_save_locs UNW_OBJ (dwarf_find_save_locs)
-#define dwarf_create_state_record UNW_OBJ (dwarf_create_state_record)
#define dwarf_make_proc_info UNW_OBJ (dwarf_make_proc_info)
+#define dwarf_apply_reg_state UNW_OBJ (dwarf_apply_reg_state)
+#define dwarf_reg_states_iterate UNW_OBJ (dwarf_reg_states_iterate)
#define dwarf_read_encoded_pointer UNW_OBJ (dwarf_read_encoded_pointer)
#define dwarf_step UNW_OBJ (dwarf_step)
+#define dwarf_flush_rs_cache UNW_OBJ (dwarf_flush_rs_cache)
extern int dwarf_init (void);
#ifndef UNW_REMOTE_ONLY
unw_dyn_info_t *di,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
+
extern int dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff,
unw_word_t ip);
extern int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr,
unw_word_t len, unw_word_t *valp,
int *is_register);
+extern int
+dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr,
+ unw_word_t rbp_addr, unw_word_t *offset);
+
extern int dwarf_extract_proc_info_from_fde (unw_addr_space_t as,
unw_accessors_t *a,
unw_word_t *fde_addr,
int is_debug_frame,
void *arg);
extern int dwarf_find_save_locs (struct dwarf_cursor *c);
-extern int dwarf_create_state_record (struct dwarf_cursor *c,
- dwarf_state_record_t *sr);
extern int dwarf_make_proc_info (struct dwarf_cursor *c);
+extern int dwarf_apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs);
+extern int dwarf_reg_states_iterate (struct dwarf_cursor *c, unw_reg_states_callback cb, void *token);
extern int dwarf_read_encoded_pointer (unw_addr_space_t as,
unw_accessors_t *a,
unw_word_t *addr,
const unw_proc_info_t *pi,
unw_word_t *valp, void *arg);
extern int dwarf_step (struct dwarf_cursor *c);
+extern int dwarf_flush_rs_cache (struct dwarf_rs_cache *cache);
#endif /* dwarf_h */
uint16_t uval16;
uint32_t uval32;
uint64_t uval64;
- int16_t sval16;
- int32_t sval32;
- int64_t sval64;
+ int16_t sval16 = 0;
+ int32_t sval32 = 0;
+ int64_t sval64 = 0;
int ret;
/* DW_EH_PE_omit and DW_EH_PE_aligned don't follow the normal
relatively cheap and unwind-state copying is relatively rare, so we
want to err on making it rather too big than too small. */
-#define UNW_TDEP_CURSOR_LEN 4096
+#define UNW_TDEP_CURSOR_LEN 512
typedef uint64_t unw_word_t;
typedef int64_t unw_sword_t;
#include "libunwind-common.h"
#include "libunwind-dynamic.h"
-#define unw_tdep_getcontext(uc) (getcontext (uc), 0)
-#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
+#define unw_tdep_getcontext(uc) (({ \
+ unw_tdep_context_t *unw_ctx = (uc); \
+ register uint64_t *unw_base asm ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs; \
+ __asm__ __volatile__ ( \
+ "stp x0, x1, [%[base], #0]\n" \
+ "stp x2, x3, [%[base], #16]\n" \
+ "stp x4, x5, [%[base], #32]\n" \
+ "stp x6, x7, [%[base], #48]\n" \
+ "stp x8, x9, [%[base], #64]\n" \
+ "stp x10, x11, [%[base], #80]\n" \
+ "stp x12, x13, [%[base], #96]\n" \
+ "stp x14, x13, [%[base], #112]\n" \
+ "stp x16, x17, [%[base], #128]\n" \
+ "stp x18, x19, [%[base], #144]\n" \
+ "stp x20, x21, [%[base], #160]\n" \
+ "stp x22, x23, [%[base], #176]\n" \
+ "stp x24, x25, [%[base], #192]\n" \
+ "stp x26, x27, [%[base], #208]\n" \
+ "stp x28, x29, [%[base], #224]\n" \
+ "str x30, [%[base], #240]\n" \
+ "mov x1, sp\n" \
+ "stp x1, x30, [%[base], #248]\n" \
+ : [base] "+r" (unw_base) : : "x1", "memory"); \
+ }), 0)
+#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int);
#ifndef __thumb__
#define unw_tdep_getcontext(uc) (({ \
unw_tdep_context_t *unw_ctx = (uc); \
- register unsigned long *unw_base asm ("r0") = unw_ctx->regs; \
+ register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \
__asm__ __volatile__ ( \
"stmia %[base], {r0-r15}" \
: : [base] "r" (unw_base) : "memory"); \
#else /* __thumb__ */
#define unw_tdep_getcontext(uc) (({ \
unw_tdep_context_t *unw_ctx = (uc); \
- register unsigned long *unw_base asm ("r0") = unw_ctx->regs; \
+ register unsigned long *unw_base __asm__ ("r0") = unw_ctx->regs; \
__asm__ __volatile__ ( \
".align 2\nbx pc\nnop\n.code 32\n" \
"stmia %[base], {r0-r15}\n" \
- "orr %[base], pc, #1\nbx %[base]" \
+ "orr %[base], pc, #1\nbx %[base]\n" \
+ ".code 16\n" \
: [base] "+r" (unw_base) : : "memory", "cc"); \
}), 0)
#endif
}
unw_caching_policy_t;
+typedef enum
+ {
+ UNW_INIT_SIGNAL_FRAME = 1, /* We know this is a signal frame */
+ }
+unw_init_local2_flags_t;
+
typedef int unw_regnum_t;
/* The unwind cursor starts at the youngest (most deeply nested) frame
{
unw_word_t start_ip; /* first IP covered by this procedure */
unw_word_t end_ip; /* first IP NOT covered by this procedure */
+#if defined(NEED_LAST_IP)
+ unw_word_t last_ip; /* first IP that could begin another procedure */
+#endif
unw_word_t lsda; /* address of lang.-spec. data area (if any) */
unw_word_t handler; /* optional personality routine */
unw_word_t gp; /* global-pointer value for this procedure */
}
unw_proc_info_t;
+typedef int (*unw_reg_states_callback)(void *token,
+ void *reg_states_data,
+ size_t reg_states_data_size,
+ unw_word_t start_ip, unw_word_t end_ip);
+
/* These are backend callback routines that provide access to the
state of a "remote" process. This can be used, for example, to
unwind another process through the ptrace() interface. */
#define unw_create_addr_space UNW_OBJ(create_addr_space)
#define unw_destroy_addr_space UNW_OBJ(destroy_addr_space)
#define unw_get_accessors UNW_ARCH_OBJ(get_accessors)
+#define unw_get_accessors_int UNW_ARCH_OBJ(get_accessors_int)
#define unw_init_local UNW_OBJ(init_local)
+#define unw_init_local2 UNW_OBJ(init_local2)
#define unw_init_remote UNW_OBJ(init_remote)
#define unw_step UNW_OBJ(step)
#define unw_resume UNW_OBJ(resume)
#define unw_get_proc_info UNW_OBJ(get_proc_info)
#define unw_get_proc_info_by_ip UNW_OBJ(get_proc_info_by_ip)
+#define unw_reg_states_iterate UNW_OBJ(reg_states_iterate)
+#define unw_apply_reg_state UNW_OBJ(apply_reg_state)
#define unw_get_reg UNW_OBJ(get_reg)
#define unw_set_reg UNW_OBJ(set_reg)
#define unw_get_fpreg UNW_OBJ(get_fpreg)
#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame)
#define unw_get_proc_name UNW_OBJ(get_proc_name)
#define unw_set_caching_policy UNW_OBJ(set_caching_policy)
+#define unw_set_cache_size UNW_OBJ(set_cache_size)
#define unw_regname UNW_ARCH_OBJ(regname)
#define unw_flush_cache UNW_ARCH_OBJ(flush_cache)
#define unw_strerror UNW_ARCH_OBJ(strerror)
extern unw_addr_space_t unw_create_addr_space (unw_accessors_t *, int);
extern void unw_destroy_addr_space (unw_addr_space_t);
extern unw_accessors_t *unw_get_accessors (unw_addr_space_t);
+extern unw_accessors_t *unw_get_accessors_int (unw_addr_space_t);
extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t);
extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t);
+extern int unw_set_cache_size (unw_addr_space_t, size_t, int);
extern const char *unw_regname (unw_regnum_t);
extern int unw_init_local (unw_cursor_t *, unw_context_t *);
+extern int unw_init_local2 (unw_cursor_t *, unw_context_t *, int);
extern int unw_init_remote (unw_cursor_t *, unw_addr_space_t, void *);
extern int unw_step (unw_cursor_t *);
extern int unw_resume (unw_cursor_t *);
extern int unw_get_proc_info (unw_cursor_t *, unw_proc_info_t *);
extern int unw_get_proc_info_by_ip (unw_addr_space_t, unw_word_t,
unw_proc_info_t *, void *);
+extern int unw_reg_states_iterate (unw_cursor_t *, unw_reg_states_callback, void *);
+extern int unw_apply_reg_state (unw_cursor_t *, void *);
extern int unw_get_reg (unw_cursor_t *, int, unw_word_t *);
extern int unw_set_reg (unw_cursor_t *, int, unw_word_t);
extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *);
#endif
#include <inttypes.h>
-#include <ucontext.h>
+#include <sys/ucontext.h>
#ifdef mips
# undef mips
/* FIXME for MIPS. Too big? What do other things use for similar tasks? */
#define UNW_TDEP_CURSOR_LEN 4096
-/* The size of a "word" varies on MIPS. This type is used for memory
- addresses and register values. To allow a single library to support
- multiple ABIs, and to support N32 at all, we must use a 64-bit type
- even when addresses are only 32 bits. */
+/* The size of a "word" varies on MIPS. This type is used for memory
+ addresses and register values, which are 32-bit wide for O32 and N32
+ ABIs, and 64-bit wide for N64 ABI. */
+#if _MIPS_SIM == _ABI64
typedef uint64_t unw_word_t;
+#else
+typedef uint32_t unw_word_t;
+#endif
typedef int32_t unw_sword_t;
/* FIXME: MIPS ABIs. */
previous frame. */
UNW_MIPS_CFA,
- UNW_TDEP_LAST_REG = UNW_MIPS_R31,
+ UNW_TDEP_LAST_REG = UNW_MIPS_PC,
UNW_TDEP_IP = UNW_MIPS_R31,
UNW_TDEP_SP = UNW_MIPS_R29,
#include "compiler.h"
-#ifdef HAVE___THREAD
- /* For now, turn off per-thread caching. It uses up too much TLS
- memory per thread even when the thread never uses libunwind at
- all. */
-# undef HAVE___THREAD
+#if defined(HAVE___THREAD) && HAVE___THREAD
+#define UNWI_DEFAULT_CACHING_POLICY UNW_CACHE_PER_THREAD
+#else
+#define UNWI_DEFAULT_CACHING_POLICY UNW_CACHE_GLOBAL
#endif
/* Platform-independent libunwind-internal declarations. */
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
+# if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN)
+# define __LITTLE_ENDIAN _LITTLE_ENDIAN
+# endif
+# if defined(_BIG_ENDIAN) && !defined(__BIG_ENDIAN)
+# define __BIG_ENDIAN _BIG_ENDIAN
+# endif
+# if defined(_BYTE_ORDER) && !defined(__BYTE_ORDER)
+# define __BYTE_ORDER _BYTE_ORDER
+# endif
#else
# define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321
unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr;
int ret;
- assert ((off & 0x1) == 0);
+ if ((off & 0x1) != 0)
+ return -UNW_EINVAL;
*addr += 2;
unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr;
int ret;
- assert ((off & 0x3) == 0);
+ if ((off & 0x3) != 0)
+ return -UNW_EINVAL;
*addr += 4;
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame UNW_OBJ(tdep_stash_frame)
#define tdep_trace UNW_OBJ(tdep_trace)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
typedef enum
{
+ UNW_ARM_FRAME_SYSCALL = -3, /* r7 saved in r12, sp offset zero */
UNW_ARM_FRAME_STANDARD = -2, /* regular r7, sp +/- offset */
UNW_ARM_FRAME_SIGRETURN = -1, /* special sigreturn frame */
UNW_ARM_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */
typedef struct
{
uint32_t virtual_address;
- int32_t frame_type : 2; /* unw_tdep_frame_type_t classification */
+ int32_t frame_type : 3; /* unw_tdep_frame_type_t classification */
int32_t last_frame : 1; /* non-zero if last frame in chain */
int32_t cfa_reg_sp : 1; /* cfa dwarf base register is sp vs. r7 */
int32_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */
ARM_SCF_LINUX_SIGFRAME, /* non-RT signal frame, kernel >=2.6.18 */
ARM_SCF_LINUX_RT_SIGFRAME, /* RT signal frame, kernel >=2.6.18 */
ARM_SCF_LINUX_OLD_SIGFRAME, /* non-RT signal frame, kernel < 2.6.18 */
- ARM_SCF_LINUX_OLD_RT_SIGFRAME /* RT signal frame, kernel < 2.6.18 */
+ ARM_SCF_LINUX_OLD_RT_SIGFRAME, /* RT signal frame, kernel < 2.6.18 */
+ ARM_SCF_FREEBSD_SIGFRAME, /* FreeBSD sigframe */
+ ARM_SCF_FREEBSD_SYSCALL, /* FreeBSD syscall stub */
}
sigcontext_format;
unw_word_t sigcontext_addr;
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame UNW_OBJ(tdep_stash_frame)
#define tdep_trace UNW_OBJ(tdep_trace)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_proc_info UNW_OBJ(find_proc_info)
#define tdep_uc_addr UNW_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
#define tdep_get_as(c) ((c)->as)
/* This can't be an UNW_ARCH_OBJ() because we need separate
unw.initialized flags for the local-only and generic versions of
the library. Also, if we wanted to have a single, shared global
- data structure, we couldn't declare "unw" as HIDDEN/PROTECTED. */
+ data structure, we couldn't declare "unw" as HIDDEN. */
#define unw UNW_OBJ(data)
extern void tdep_init (void);
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
#define tdep_get_func_addr UNW_OBJ(get_func_addr)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t * valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
#define tdep_get_func_addr UNW_OBJ(get_func_addr)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t * valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#include "mempool.h"
#include "dwarf.h"
-#ifdef HAVE___THREAD
-# undef HAVE___THREAD
-#endif
-
typedef struct
{
/* no Tilegx-specific fast trace */
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
unsigned long *segbase,
unsigned long *mapoff,
char *path, size_t pathlen);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c,
unw_regnum_t reg,
unw_word_t *valp,
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#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_cache_frame(c) 0
+#define tdep_reuse_frame(c,frame) do {} while(0)
#define tdep_stash_frame(c,rs) do {} while(0)
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
typedef enum
{
+ UNW_X86_64_FRAME_ALIGNED = -3, /* frame stack pointer aligned */
UNW_X86_64_FRAME_STANDARD = -2, /* regular rbp, rsp +/- offset */
UNW_X86_64_FRAME_SIGRETURN = -1, /* special sigreturn frame */
UNW_X86_64_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */
typedef struct
{
uint64_t virtual_address;
- int64_t frame_type : 2; /* unw_tdep_frame_type_t classification */
+ int64_t frame_type : 3; /* unw_tdep_frame_type_t classification */
int64_t last_frame : 1; /* non-zero if last frame in chain */
int64_t cfa_reg_rsp : 1; /* cfa dwarf base register is rsp vs. rbp */
- int64_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */
+ int64_t cfa_reg_offset : 29; /* cfa is at this offset from base register value */
int64_t rbp_cfa_offset : 15; /* rbp saved at this offset from cfa (-1 = not saved) */
int64_t rsp_cfa_offset : 15; /* rsp saved at this offset from cfa (-1 = not saved) */
}
#define tdep_search_unwind_table dwarf_search_unwind_table
#define tdep_find_unwind_table dwarf_find_unwind_table
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
+#define tdep_get_exe_image_path UNW_ARCH_OBJ(get_exe_image_path)
#define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg)
#if __linux__
# 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)
+# define tdep_cache_frame(c) 0
+# define tdep_reuse_frame(c,frame) do {} while(0)
#endif
#define tdep_stash_frame UNW_OBJ(stash_frame)
#define tdep_trace UNW_OBJ(tdep_trace)
extern 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);
+extern void tdep_get_exe_image_path (char *path);
extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
#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 int tdep_cache_frame (struct dwarf_cursor *c);
extern void tdep_reuse_frame (struct dwarf_cursor *c,
- struct dwarf_reg_state *rs);
+ int frame);
extern void tdep_stash_frame (struct dwarf_cursor *c,
struct dwarf_reg_state *rs);
#endif
#if defined __aarch64__
# include "tdep-aarch64/jmpbuf.h"
-#if defined __arm__
+#elif defined __arm__
# include "tdep-arm/jmpbuf.h"
#elif defined __hppa__
# include "tdep-hppa/jmpbuf.h"
mi/Gput_dynamic_unwind_info.c mi/Gdestroy_addr_space.c \
mi/Gget_reg.c mi/Gset_reg.c \
mi/Gget_fpreg.c mi/Gset_fpreg.c \
- mi/Gset_caching_policy.c
+ mi/Gset_caching_policy.c \
+ mi/Gset_cache_size.c
if SUPPORT_CXX_EXCEPTIONS
libunwind_la_SOURCES_local_unwind = \
mi/Lput_dynamic_unwind_info.c mi/Ldestroy_addr_space.c \
mi/Lget_reg.c mi/Lset_reg.c \
mi/Lget_fpreg.c mi/Lset_fpreg.c \
- mi/Lset_caching_policy.c
+ mi/Lset_caching_policy.c \
+ mi/Lset_cache_size.c
libunwind_la_SOURCES_local = \
$(libunwind_la_SOURCES_local_nounwind) \
libunwind_dwarf_common_la_SOURCES = dwarf/global.c
libunwind_dwarf_local_la_SOURCES = \
- dwarf/Lexpr.c dwarf/Lfde.c dwarf/Lparser.c dwarf/Lpe.c dwarf/Lstep.c \
+ dwarf/Lexpr.c dwarf/Lfde.c dwarf/Lparser.c dwarf/Lpe.c \
dwarf/Lfind_proc_info-lsb.c \
dwarf/Lfind_unwind_table.c
libunwind_dwarf_local_la_LIBADD = libunwind-dwarf-common.la
libunwind_dwarf_generic_la_SOURCES = \
- 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/Gfind_proc_info-lsb.c \
dwarf/Gfind_unwind_table.c
libunwind_dwarf_generic_la_LIBADD = libunwind-dwarf-common.la
# The list of files that go into libunwind:
libunwind_la_SOURCES_aarch64 = $(libunwind_la_SOURCES_aarch64_common) \
$(libunwind_la_SOURCES_local) \
+ aarch64/Lapply_reg_state.c aarch64/Lreg_states_iterate.c \
aarch64/Lcreate_addr_space.c aarch64/Lget_proc_info.c \
aarch64/Lget_save_loc.c aarch64/Lglobal.c aarch64/Linit.c \
aarch64/Linit_local.c aarch64/Linit_remote.c \
libunwind_aarch64_la_SOURCES_aarch64 = $(libunwind_la_SOURCES_aarch64_common) \
$(libunwind_la_SOURCES_generic) \
+ aarch64/Gapply_reg_state.c aarch64/Greg_states_iterate.c \
aarch64/Gcreate_addr_space.c aarch64/Gget_proc_info.c \
aarch64/Gget_save_loc.c aarch64/Gglobal.c aarch64/Ginit.c \
aarch64/Ginit_local.c aarch64/Ginit_remote.c \
# The list of files that go into libunwind:
libunwind_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
+ $(libunwind_la_SOURCES_arm_os_local) \
$(libunwind_la_SOURCES_local) \
arm/getcontext.S \
+ arm/Lapply_reg_state.c arm/Lreg_states_iterate.c \
arm/Lcreate_addr_space.c arm/Lget_proc_info.c arm/Lget_save_loc.c \
arm/Lglobal.c arm/Linit.c arm/Linit_local.c arm/Linit_remote.c \
- arm/Lis_signal_frame.c arm/Lregs.c arm/Lresume.c arm/Lstep.c \
+ arm/Lregs.c arm/Lresume.c arm/Lstep.c \
arm/Lex_tables.c arm/Lstash_frame.c arm/Ltrace.c
+# The list of files that go into libunwind-arm:
libunwind_arm_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
+ $(libunwind_la_SOURCES_arm_os) \
$(libunwind_la_SOURCES_generic) \
+ arm/Gapply_reg_state.c arm/Greg_states_iterate.c \
arm/Gcreate_addr_space.c arm/Gget_proc_info.c arm/Gget_save_loc.c \
arm/Gglobal.c arm/Ginit.c arm/Ginit_local.c arm/Ginit_remote.c \
- arm/Gis_signal_frame.c arm/Gregs.c arm/Gresume.c arm/Gstep.c \
+ arm/Gregs.c arm/Gresume.c arm/Gstep.c \
arm/Gex_tables.c arm/Gstash_frame.c arm/Gtrace.c
# The list of files that go both into libunwind and libunwind-ia64:
\
ia64/dyn_info_list.S ia64/getcontext.S \
\
+ ia64/Lapply_reg_state.c ia64/Lreg_states_iterate.c \
ia64/Lcreate_addr_space.c ia64/Lget_proc_info.c ia64/Lget_save_loc.c \
ia64/Lglobal.c ia64/Linit.c ia64/Linit_local.c ia64/Linit_remote.c \
ia64/Linstall_cursor.S ia64/Lis_signal_frame.c ia64/Lparser.c \
# The list of files that go into libunwind-ia64:
libunwind_ia64_la_SOURCES_ia64 = $(libunwind_la_SOURCES_ia64_common) \
$(libunwind_la_SOURCES_generic) \
+ ia64/Gapply_reg_state.c ia64/Greg_states_iterate.c \
ia64/Gcreate_addr_space.c ia64/Gget_proc_info.c ia64/Gget_save_loc.c \
ia64/Gglobal.c ia64/Ginit.c ia64/Ginit_local.c ia64/Ginit_remote.c \
ia64/Ginstall_cursor.S ia64/Gis_signal_frame.c ia64/Gparser.c \
libunwind_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \
$(libunwind_la_SOURCES_local) \
hppa/getcontext.S hppa/setcontext.S \
+ hppa/Lapply_reg_state.c hppa/Lreg_states_iterate.c \
hppa/Lcreate_addr_space.c hppa/Lget_save_loc.c hppa/Lglobal.c \
hppa/Linit.c hppa/Linit_local.c hppa/Linit_remote.c \
hppa/Lis_signal_frame.c hppa/Lget_proc_info.c hppa/Lregs.c \
# The list of files that go into libunwind-hppa:
libunwind_hppa_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \
$(libunwind_la_SOURCES_generic) \
+ hppa/Gapply_reg_state.c hppa/Greg_states_iterate.c \
hppa/Gcreate_addr_space.c hppa/Gget_save_loc.c hppa/Gglobal.c \
hppa/Ginit.c hppa/Ginit_local.c hppa/Ginit_remote.c \
hppa/Gis_signal_frame.c hppa/Gget_proc_info.c hppa/Gregs.c \
hppa/Gresume.c hppa/Gstep.c
# The list of files that go info libunwind and libunwind-mips:
-noinst_HEADERS += mips/init.h mips/offsets.h
+noinst_HEADERS += mips/init.h mips/offsets.h mips/unwind_i.h
libunwind_la_SOURCES_mips_common = $(libunwind_la_SOURCES_common) \
mips/is_fpreg.c mips/regname.c
libunwind_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \
$(libunwind_la_SOURCES_local) \
mips/getcontext.S \
+ mips/Lapply_reg_state.c mips/Lreg_states_iterate.c \
mips/Lcreate_addr_space.c mips/Lget_proc_info.c mips/Lget_save_loc.c \
mips/Lglobal.c mips/Linit.c mips/Linit_local.c mips/Linit_remote.c \
mips/Lis_signal_frame.c mips/Lregs.c mips/Lresume.c mips/Lstep.c
libunwind_mips_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \
$(libunwind_la_SOURCES_generic) \
+ mips/Gapply_reg_state.c mips/Greg_states_iterate.c \
mips/Gcreate_addr_space.c mips/Gget_proc_info.c mips/Gget_save_loc.c \
mips/Gglobal.c mips/Ginit.c mips/Ginit_local.c mips/Ginit_remote.c \
mips/Gis_signal_frame.c mips/Gregs.c mips/Gresume.c mips/Gstep.c
# The list of files that go info libunwind and libunwind-tilegx:
-noinst_HEADERS += tilegx/init.h tilegx/offsets.h
+noinst_HEADERS += tilegx/init.h tilegx/offsets.h tilegx/unwind_i.h
libunwind_la_SOURCES_tilegx_common = $(libunwind_la_SOURCES_common) \
tilegx/is_fpreg.c tilegx/regname.c
libunwind_la_SOURCES_tilegx = $(libunwind_la_SOURCES_tilegx_common) \
$(libunwind_la_SOURCES_local) \
tilegx/getcontext.S \
+ tilegx/Lapply_reg_state.c tilegx/Lreg_states_iterate.c \
tilegx/Lcreate_addr_space.c tilegx/Lget_proc_info.c tilegx/Lget_save_loc.c \
tilegx/Lglobal.c tilegx/Linit.c tilegx/Linit_local.c tilegx/Linit_remote.c \
tilegx/Lis_signal_frame.c tilegx/Lregs.c tilegx/Lresume.c tilegx/Lstep.c
libunwind_tilegx_la_SOURCES_tilegx = $(libunwind_la_SOURCES_tilegx_common) \
$(libunwind_la_SOURCES_generic) \
+ tilegx/Gapply_reg_state.c tilegx/Greg_states_iterate.c \
tilegx/Gcreate_addr_space.c tilegx/Gget_proc_info.c tilegx/Gget_save_loc.c \
tilegx/Gglobal.c tilegx/Ginit.c tilegx/Ginit_local.c tilegx/Ginit_remote.c \
tilegx/Gis_signal_frame.c tilegx/Gregs.c tilegx/Gresume.c tilegx/Gstep.c
libunwind_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os_local) \
$(libunwind_la_SOURCES_local) \
+ x86/Lapply_reg_state.c x86/Lreg_states_iterate.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/Lget_proc_info.c x86/Lregs.c \
libunwind_x86_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os) \
$(libunwind_la_SOURCES_generic) \
+ x86/Gapply_reg_state.c x86/Greg_states_iterate.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/Gget_proc_info.c x86/Gregs.c \
$(libunwind_la_SOURCES_x86_64_os_local) \
$(libunwind_la_SOURCES_local) \
x86_64/setcontext.S \
+ x86_64/Lapply_reg_state.c x86_64/Lreg_states_iterate.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/Lget_proc_info.c x86_64/Lregs.c x86_64/Lresume.c \
libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
$(libunwind_la_SOURCES_x86_64_os) \
$(libunwind_la_SOURCES_generic) \
+ x86_64/Gapply_reg_state.c x86_64/Greg_states_iterate.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/Gget_proc_info.c x86_64/Gregs.c x86_64/Gresume.c \
libunwind_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
$(libunwind_la_SOURCES_local) \
$(libunwind_la_SOURCES_ppc) \
+ ppc32/Lapply_reg_state.c ppc32/Lreg_states_iterate.c \
ppc32/Lcreate_addr_space.c \
ppc32/Lglobal.c ppc32/Linit.c \
ppc32/Lregs.c ppc32/Lresume.c ppc32/Lstep.c
libunwind_ppc32_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
$(libunwind_la_SOURCES_generic) \
$(libunwind_ppc_la_SOURCES_ppc_generic) \
+ ppc32/Gapply_reg_state.c ppc32/Greg_states_iterate.c \
ppc32/Gcreate_addr_space.c \
ppc32/Gglobal.c ppc32/Ginit.c \
ppc32/Gregs.c ppc32/Gresume.c ppc32/Gstep.c
libunwind_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
$(libunwind_la_SOURCES_local) \
$(libunwind_la_SOURCES_ppc) \
+ ppc64/Lapply_reg_state.c ppc64/Lreg_states_iterate.c \
ppc64/Lcreate_addr_space.c \
ppc64/Lglobal.c ppc64/Linit.c \
ppc64/Lregs.c ppc64/Lresume.c ppc64/Lstep.c
libunwind_ppc64_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
$(libunwind_la_SOURCES_generic) \
$(libunwind_ppc_la_SOURCES_ppc_generic) \
+ ppc64/Gapply_reg_state.c ppc64/Greg_states_iterate.c \
ppc64/Gcreate_addr_space.c \
ppc64/Gglobal.c ppc64/Ginit.c \
ppc64/Gregs.c ppc64/Gresume.c ppc64/Gstep.c
# The list of files that go into libunwind:
libunwind_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common) \
$(libunwind_la_SOURCES_local) \
+ sh/Lapply_reg_state.c sh/Lreg_states_iterate.c \
sh/Lcreate_addr_space.c sh/Lget_proc_info.c sh/Lget_save_loc.c \
sh/Lglobal.c sh/Linit.c sh/Linit_local.c sh/Linit_remote.c \
sh/Lis_signal_frame.c sh/Lregs.c sh/Lresume.c sh/Lstep.c
libunwind_sh_la_SOURCES_sh = $(libunwind_la_SOURCES_sh_common) \
$(libunwind_la_SOURCES_generic) \
+ sh/Gapply_reg_state.c sh/Greg_states_iterate.c \
sh/Gcreate_addr_space.c sh/Gget_proc_info.c sh/Gget_save_loc.c \
sh/Gglobal.c sh/Ginit.c sh/Ginit_local.c sh/Ginit_remote.c \
sh/Gis_signal_frame.c sh/Gregs.c sh/Gresume.c sh/Gstep.c
# to be there if the user configured with --disable-shared.
#
install-exec-hook:
- cd $(DESTDIR)$(libdir) && $(LN_S) -f libunwind-$(arch).a libunwind-generic.a
+ if test -f $(DESTDIR)$(libdir)/libunwind-$(arch).a; then \
+ cd $(DESTDIR)$(libdir) && $(LN_S) -f libunwind-$(arch).a libunwind-generic.a; \
+ fi
if test -f $(DESTDIR)$(libdir)/libunwind-$(arch).so; then \
cd $(DESTDIR)$(libdir) && $(LN_S) -f libunwind-$(arch).so \
libunwind-generic.so; \
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
+ libunwind_la_SOURCES_arm_os = arm/Gos-linux.c
+ libunwind_la_SOURCES_arm_os_local = arm/Los-linux.c
libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_linux.c
endif
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
+ libunwind_la_SOURCES_arm_os = arm/Gos-freebsd.c
+ libunwind_la_SOURCES_arm_os_local = arm/Los-freebsd.c
libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_freebsd.c
endif
if OS_QNX
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_qnx)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_qnx_local)
+ libunwind_la_SOURCES_arm_os = arm/Gos-other.c
+ libunwind_la_SOURCES_arm_os_local = arm/Los-other.c
endif
if ARCH_AARCH64
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
- if (reg >= UNW_AARCH64_X0 && reg <= UNW_AARCH64_V31)
+ if (reg >= UNW_AARCH64_X0 && reg < UNW_AARCH64_V0)
return &uc->uc_mcontext.regs[reg];
+ else if (reg >= UNW_AARCH64_V0 && reg <= UNW_AARCH64_V31)
+ return &GET_FPCTX(uc)->vregs[reg - UNW_AARCH64_V0];
else
return NULL;
}
aarch64_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+static int
+unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
d4000001 svc #0x0
*/
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
ip = c->dwarf.ip;
/* libunwind - a platform-independent unwind library
- Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
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
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 "dwarf.h"
-#include "libunwind_i.h"
+#include "unwind_i.h"
-HIDDEN int
-dwarf_step (struct dwarf_cursor *c)
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
{
- int ret;
-
- if ((ret = dwarf_find_save_locs (c)) >= 0) {
- c->pi_valid = 0;
- ret = 1;
- }
+ struct cursor *c = (struct cursor *) cursor;
- Debug (15, "returning %d\n", ret);
- return ret;
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
}
loc = c->dwarf.loc[reg];
break;
+ case UNW_AARCH64_X30:
+ if (write)
+ c->dwarf.ip = *valp; /* update the IP cache */
case UNW_AARCH64_X4:
case UNW_AARCH64_X5:
case UNW_AARCH64_X6:
case UNW_AARCH64_X27:
case UNW_AARCH64_X28:
case UNW_AARCH64_X29:
- case UNW_AARCH64_X30:
case UNW_AARCH64_PC:
case UNW_AARCH64_PSTATE:
loc = c->dwarf.loc[reg];
tdep_access_fpreg (struct cursor *c, unw_regnum_t reg, unw_fpreg_t *valp,
int write)
{
- Debug (1, "bad register number %u\n", reg);
- return -UNW_EBADREG;
+ dwarf_loc_t loc = c->dwarf.loc[reg];
+ if (write)
+ return dwarf_putfp (&c->dwarf, loc, *valp);
+ else
+ return dwarf_getfp (&c->dwarf, loc, valp);
}
{
/* Since there are no signals involved here we restore EH and non scratch
registers only. */
- unsigned long regs[15];
+ unsigned long regs[24];
regs[0] = uc->uc_mcontext.regs[0];
regs[1] = uc->uc_mcontext.regs[1];
regs[2] = uc->uc_mcontext.regs[2];
regs[11] = uc->uc_mcontext.regs[26];
regs[12] = uc->uc_mcontext.regs[27];
regs[13] = uc->uc_mcontext.regs[28];
- regs[14] = uc->uc_mcontext.regs[30]; /* LR */
+ regs[14] = uc->uc_mcontext.regs[29]; /* FP */
+ regs[15] = uc->uc_mcontext.regs[30]; /* LR */
+ regs[16] = GET_FPCTX(uc)->vregs[8];
+ regs[17] = GET_FPCTX(uc)->vregs[9];
+ regs[18] = GET_FPCTX(uc)->vregs[10];
+ regs[19] = GET_FPCTX(uc)->vregs[11];
+ regs[20] = GET_FPCTX(uc)->vregs[12];
+ regs[21] = GET_FPCTX(uc)->vregs[13];
+ regs[22] = GET_FPCTX(uc)->vregs[14];
+ regs[23] = GET_FPCTX(uc)->vregs[15];
unsigned long sp = uc->uc_mcontext.sp;
struct regs_overlay {
"ldp x23, x24, [x4,64]\n"
"ldp x25, x26, [x4,80]\n"
"ldp x27, x28, [x4,96]\n"
- "ldr x30, [x4,112]\n"
+ "ldp x29, x30, [x4,112]\n"
+ "ldp d8, d9, [x4,128]\n"
+ "ldp d10, d11, [x4,144]\n"
+ "ldp d12, d13, [x4,160]\n"
+ "ldp d14, d15, [x4,176]\n"
"mov sp, x5\n"
"ret \n"
:
Debug (8, "copying out cursor state\n");
- for (reg = 0; reg <= UNW_AARCH64_PSTATE; ++reg)
+ for (reg = 0; reg <= UNW_AARCH64_V31; ++reg)
{
Debug (16, "copying %s %d\n", unw_regname (reg), reg);
if (unw_is_fpreg (reg))
}
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
" ra=0x%lx fp [where=%d val=%ld @0x%lx] lr [where=%d val=%ld @0x%lx] "
"sp [where=%d val=%ld @0x%lx]\n",
d->ip, d->cfa, f->frame_type,
- rs->reg[DWARF_CFA_REG_COLUMN].where,
- rs->reg[DWARF_CFA_REG_COLUMN].val,
- rs->reg[DWARF_CFA_OFF_COLUMN].val,
- DWARF_GET_LOC(d->loc[d->ret_addr_column]),
- rs->reg[FP].where, rs->reg[FP].val, DWARF_GET_LOC(d->loc[FP]),
- rs->reg[LR].where, rs->reg[LR].val, DWARF_GET_LOC(d->loc[LR]),
- rs->reg[SP].where, rs->reg[SP].val, DWARF_GET_LOC(d->loc[SP]));
+ rs->reg.where[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_OFF_COLUMN],
+ DWARF_GET_LOC(d->loc[rs->ret_addr_column]),
+ rs->reg.where[FP], rs->reg.val[FP], DWARF_GET_LOC(d->loc[FP]),
+ rs->reg.where[LR], rs->reg.val[LR], DWARF_GET_LOC(d->loc[LR]),
+ rs->reg.where[SP], rs->reg.val[SP], DWARF_GET_LOC(d->loc[SP]));
/* A standard frame is defined as:
- CFA is register-relative offset off FP or SP;
- LR is unsaved or saved at CFA+offset, offset != -1;
- SP is unsaved or saved at CFA+offset, offset != -1. */
if (f->frame_type == UNW_AARCH64_FRAME_OTHER
- && (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
- && (rs->reg[DWARF_CFA_REG_COLUMN].val == FP
- || rs->reg[DWARF_CFA_REG_COLUMN].val == SP)
- && labs(rs->reg[DWARF_CFA_OFF_COLUMN].val) < (1 << 29)
- && d->ret_addr_column == LR
- && (rs->reg[FP].where == DWARF_WHERE_UNDEF
- || rs->reg[FP].where == DWARF_WHERE_SAME
- || (rs->reg[FP].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[FP].val) < (1 << 29)
- && rs->reg[FP].val+1 != 0))
- && (rs->reg[LR].where == DWARF_WHERE_UNDEF
- || rs->reg[LR].where == DWARF_WHERE_SAME
- || (rs->reg[LR].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[LR].val) < (1 << 29)
- && rs->reg[LR].val+1 != 0))
- && (rs->reg[SP].where == DWARF_WHERE_UNDEF
- || rs->reg[SP].where == DWARF_WHERE_SAME
- || (rs->reg[SP].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[SP].val) < (1 << 29)
- && rs->reg[SP].val+1 != 0)))
+ && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
+ && (rs->reg.val[DWARF_CFA_REG_COLUMN] == FP
+ || rs->reg.val[DWARF_CFA_REG_COLUMN] == SP)
+ && labs(rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 29)
+ && rs->ret_addr_column == LR
+ && (rs->reg.where[FP] == DWARF_WHERE_UNDEF
+ || rs->reg.where[FP] == DWARF_WHERE_SAME
+ || (rs->reg.where[FP] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[FP]) < (1 << 29)
+ && rs->reg.val[FP]+1 != 0))
+ && (rs->reg.where[LR] == DWARF_WHERE_UNDEF
+ || rs->reg.where[LR] == DWARF_WHERE_SAME
+ || (rs->reg.where[LR] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[LR]) < (1 << 29)
+ && rs->reg.val[LR]+1 != 0))
+ && (rs->reg.where[SP] == DWARF_WHERE_UNDEF
+ || rs->reg.where[SP] == DWARF_WHERE_SAME
+ || (rs->reg.where[SP] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[SP]) < (1 << 29)
+ && rs->reg.val[SP]+1 != 0)))
{
/* Save information for a standard frame. */
f->frame_type = UNW_AARCH64_FRAME_STANDARD;
- f->cfa_reg_sp = (rs->reg[DWARF_CFA_REG_COLUMN].val == SP);
- f->cfa_reg_offset = rs->reg[DWARF_CFA_OFF_COLUMN].val;
- if (rs->reg[FP].where == DWARF_WHERE_CFAREL)
- f->fp_cfa_offset = rs->reg[FP].val;
- if (rs->reg[LR].where == DWARF_WHERE_CFAREL)
- f->lr_cfa_offset = rs->reg[LR].val;
- if (rs->reg[SP].where == DWARF_WHERE_CFAREL)
- f->sp_cfa_offset = rs->reg[SP].val;
+ f->cfa_reg_sp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == SP);
+ f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN];
+ if (rs->reg.where[FP] == DWARF_WHERE_CFAREL)
+ f->fp_cfa_offset = rs->reg.val[FP];
+ if (rs->reg.where[LR] == DWARF_WHERE_CFAREL)
+ f->lr_cfa_offset = rs->reg.val[LR];
+ if (rs->reg.where[SP] == DWARF_WHERE_CFAREL)
+ f->sp_cfa_offset = rs->reg.val[SP];
Debug (4, " standard frame\n");
}
else
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+/* Recognise PLT entries such as:
+ 40ddf0: b0000570 adrp x16, 4ba000 <_GLOBAL_OFFSET_TABLE_+0x2a8>
+ 40ddf4: f9433611 ldr x17, [x16,#1640]
+ 40ddf8: 9119a210 add x16, x16, #0x668
+ 40ddfc: d61f0220 br x17 */
+static int
+is_plt_entry (struct dwarf_cursor *c)
+{
+ unw_word_t w0, w1;
+ unw_accessors_t *a;
+ int ret;
+
+ a = unw_get_accessors_int (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 & 0xff0000009f000000) == 0xf900000090000000)
+ && ((w1 & 0xffffffffff000000) == 0xd61f022091000000));
+
+ Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
+ return ret;
+}
+
+static int
+aarch64_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
+ c->dwarf.use_prev_instr = 0;
return 1;
}
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
c, c->dwarf.ip, c->dwarf.cfa);
/* Check if this is a signal frame. */
- if (unw_is_signal_frame (cursor))
- return unw_handle_signal_frame (cursor);
+ if (unw_is_signal_frame (cursor) > 0)
+ return aarch64_handle_signal_frame (cursor);
ret = dwarf_step (&c->dwarf);
Debug(1, "dwarf_step()=%d\n", ret);
return ret;
if (unlikely (ret < 0))
- return 0;
+ {
+ /* DWARF failed. */
+ if (is_plt_entry (&c->dwarf))
+ {
+ Debug (2, "found plt entry\n");
+ c->frame_info.frame_type = UNW_AARCH64_FRAME_STANDARD;
+ }
+ else
+ {
+ Debug (2, "fallback\n");
+ c->frame_info.frame_type = UNW_AARCH64_FRAME_GUESSED;
+ }
+ /* Use link register (X30). */
+ c->frame_info.cfa_reg_offset = 0;
+ c->frame_info.cfa_reg_sp = 0;
+ c->frame_info.fp_cfa_offset = -1;
+ c->frame_info.lr_cfa_offset = -1;
+ c->frame_info.sp_cfa_offset = -1;
+ c->dwarf.loc[UNW_AARCH64_PC] = c->dwarf.loc[UNW_AARCH64_X30];
+ c->dwarf.loc[UNW_AARCH64_X30] = DWARF_NULL_LOC;
+ if (!DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_AARCH64_PC]))
+ {
+ ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
+ if (ret < 0)
+ {
+ Debug (2, "failed to get pc from link register: %d\n", ret);
+ return ret;
+ }
+ Debug (2, "link register (x30) = 0x%016lx\n", c->dwarf.ip);
+ ret = 1;
+ }
+ else
+ c->dwarf.ip = 0;
+ }
return (c->dwarf.ip == 0) ? 0 : 1;
}
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
c->sigcontext_pc = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return (regnum >= UNW_AARCH64_V0 && regnum <= UNW_AARCH64_V31);
[UNW_AARCH64_FPCR] = "fpcr",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname) && regname[reg] != NULL)
} while (0)
#endif
+#define GET_FPCTX(uc) ((struct fpsimd_context *)(&uc->uc_mcontext.__reserved))
+
#endif /* unwind_i_h */
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
return nbuf;
}
-PROTECTED int
-tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
- unw_dyn_info_t *di, unw_proc_info_t *pi,
- int need_unwind_info, void *arg)
+int
+arm_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
+ unw_dyn_info_t *di, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
{
- if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)
- && di->format == UNW_INFO_FORMAT_ARM_EXIDX)
- {
- /* The .ARM.exidx section contains a sorted list of key-value pairs -
- the unwind entries. The 'key' is a prel31 offset to the start of a
- function. We binary search this section in order to find the
- appropriate unwind entry. */
- unw_word_t first = di->u.rti.table_data;
- unw_word_t last = di->u.rti.table_data + di->u.rti.table_len - 8;
- unw_word_t entry, val;
-
- if (prel31_to_addr (as, arg, first, &val) < 0 || ip < val)
- return -UNW_ENOINFO;
-
- if (prel31_to_addr (as, arg, last, &val) < 0)
- return -UNW_EINVAL;
+ /* The .ARM.exidx section contains a sorted list of key-value pairs -
+ the unwind entries. The 'key' is a prel31 offset to the start of a
+ function. We binary search this section in order to find the
+ appropriate unwind entry. */
+ unw_word_t first = di->u.rti.table_data;
+ unw_word_t last = di->u.rti.table_data + di->u.rti.table_len - 8;
+ unw_word_t entry, val;
+
+ if (prel31_to_addr (as, arg, first, &val) < 0 || ip < val)
+ return -UNW_ENOINFO;
+
+ if (prel31_to_addr (as, arg, last, &val) < 0)
+ return -UNW_EINVAL;
- if (ip >= val)
- {
- entry = last;
+ if (ip >= val)
+ {
+ entry = last;
- if (prel31_to_addr (as, arg, last, &pi->start_ip) < 0)
- return -UNW_EINVAL;
+ if (prel31_to_addr (as, arg, last, &pi->start_ip) < 0)
+ return -UNW_EINVAL;
- pi->end_ip = di->end_ip -1;
- }
- else
- {
- while (first < last - 8)
- {
- entry = first + (((last - first) / 8 + 1) >> 1) * 8;
+ pi->end_ip = di->end_ip -1;
+ }
+ else
+ {
+ while (first < last - 8)
+ {
+ entry = first + (((last - first) / 8 + 1) >> 1) * 8;
- if (prel31_to_addr (as, arg, entry, &val) < 0)
- return -UNW_EINVAL;
+ if (prel31_to_addr (as, arg, entry, &val) < 0)
+ return -UNW_EINVAL;
- if (ip < val)
- last = entry;
- else
- first = entry;
- }
+ if (ip < val)
+ last = entry;
+ else
+ first = entry;
+ }
- entry = first;
+ entry = first;
- if (prel31_to_addr (as, arg, entry, &pi->start_ip) < 0)
- return -UNW_EINVAL;
+ if (prel31_to_addr (as, arg, entry, &pi->start_ip) < 0)
+ return -UNW_EINVAL;
- if (prel31_to_addr (as, arg, entry + 8, &pi->end_ip) < 0)
- return -UNW_EINVAL;
+ if (prel31_to_addr (as, arg, entry + 8, &pi->end_ip) < 0)
+ return -UNW_EINVAL;
- pi->end_ip--;
- }
+ pi->end_ip--;
+ }
- if (need_unwind_info)
- {
- pi->unwind_info_size = 8;
- pi->unwind_info = (void *) entry;
- pi->format = UNW_INFO_FORMAT_ARM_EXIDX;
- }
- return 0;
+ if (need_unwind_info)
+ {
+ pi->unwind_info_size = 8;
+ pi->unwind_info = (void *) entry;
+ pi->format = UNW_INFO_FORMAT_ARM_EXIDX;
}
+ return 0;
+}
+
+int
+tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
+ unw_dyn_info_t *di, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg)
+{
+ if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)
+ && di->format == UNW_INFO_FORMAT_ARM_EXIDX)
+ return arm_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
else if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)
&& di->format != UNW_INFO_FORMAT_ARM_EXIDX)
return dwarf_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
Debug (14, "looking for IP=0x%lx\n", (long) ip);
if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
- {
- struct dwarf_callback_data cb_data;
-
- memset (&cb_data, 0, sizeof (cb_data));
- cb_data.ip = ip;
- cb_data.pi = pi;
- cb_data.need_unwind_info = need_unwind_info;
- cb_data.di.format = -1;
- cb_data.di_debug.format = -1;
-
- SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
- ret = dl_iterate_phdr (dwarf_callback, &cb_data);
- SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
-
- if (cb_data.single_fde)
- /* already got the result in *pi */
- return 0;
-
- if (cb_data.di_debug.format != -1)
- ret = tdep_search_unwind_table (as, ip, &cb_data.di_debug, pi,
- need_unwind_info, arg);
- else
- ret = -UNW_ENOINFO;
- }
+ ret = dwarf_find_proc_info (as, ip, pi, need_unwind_info, arg);
if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
{
SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
if (cb_data.di.format != -1)
- ret = tdep_search_unwind_table (as, ip, &cb_data.di, pi,
- need_unwind_info, arg);
+ ret = arm_search_unwind_table (as, ip, &cb_data.di, pi,
+ need_unwind_info, arg);
else
ret = -UNW_ENOINFO;
}
- if (ret < 0)
- Debug (14, "IP=0x%lx not found\n", (long) ip);
-
return ret;
}
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (unw_tdep_context_t *uc, int reg)
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
void *arg)
{
+ /* validate address */
+ const struct cursor *c = (const struct cursor *) arg;
+ if (c && validate_mem(addr))
+ return -1;
+
if (write)
{
Debug (16, "mem[%x] <- %x\n", addr, *val);
}
else
{
- /* validate address */
- const struct cursor *c = (const struct cursor *) arg;
- if (c && validate_mem(addr))
- return -1;
-
*val = *(unw_word_t *) addr;
Debug (16, "mem[%x] -> %x\n", addr, *val);
}
arm_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = arm_find_proc_info;
local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+static int
+unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, unw_context_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
+++ /dev/null
-/* libunwind - a platform-independent unwind library
- Copyright (C) 2008 CodeSourcery
- Copyright 2011 Linaro Limited
-
-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 <stdio.h>
-#include "unwind_i.h"
-
-#ifdef __linux__
-#define ARM_NR_sigreturn 119
-#define ARM_NR_rt_sigreturn 173
-#define ARM_NR_OABI_SYSCALL_BASE 0x900000
-
-/* ARM EABI sigreturn (the syscall number is loaded into r7) */
-#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
-#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
-
-/* ARM OABI sigreturn (using SWI) */
-#define ARM_SIGRETURN \
- (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
-#define ARM_RT_SIGRETURN \
- (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
-
-/* Thumb sigreturn (two insns, syscall number is loaded into r7) */
-#define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn)
-#define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn)
-#endif /* __linux__ */
-
-/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal
- frame. */
-PROTECTED int
-unw_is_signal_frame (unw_cursor_t *cursor)
-{
-#ifdef __linux__
- struct cursor *c = (struct cursor *) cursor;
- unw_word_t w0, 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;
-
- ip = c->dwarf.ip;
-
- if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0)
- return ret;
-
- /* Return 1 if the IP points to a non-RT sigreturn sequence. */
- if (w0 == MOV_R7_SIGRETURN || w0 == ARM_SIGRETURN || w0 == THUMB_SIGRETURN)
- return 1;
- /* Return 2 if the IP points to a RT sigreturn sequence. */
- else if (w0 == MOV_R7_RT_SIGRETURN || w0 == ARM_RT_SIGRETURN
- || w0 == THUMB_RT_SIGRETURN)
- return 2;
-
- return 0;
-#elif defined(__QNX__)
- /* Not supported yet */
- return 0;
-#else
- printf ("%s: implement me\n", __FUNCTION__);
- return -UNW_ENOINFO;
-#endif
-}
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2008 CodeSourcery
+ Copyright 2011 Linaro Limited
+ Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
+ Copyright 2015 The FreeBSD Foundation
+
+ Portions of this software were developed by Konstantin Belousov
+ under sponsorship from the FreeBSD Foundation.
+
+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 <stdio.h>
+#include <signal.h>
+#include "unwind_i.h"
+#include "offsets.h"
+#include "ex_tables.h"
+
+HIDDEN int
+arm_handle_signal_frame (unw_cursor_t *cursor)
+{
+ struct cursor *c = (struct cursor *) cursor;
+ int ret, fmt;
+ unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
+ struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
+
+ if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
+ return -UNW_EUNSPEC;
+ fmt = unw_is_signal_frame(cursor);
+
+ c->dwarf.pi_valid = 0;
+
+ if (fmt == UNW_ARM_FRAME_SYSCALL)
+ {
+ c->sigcontext_format = ARM_SCF_FREEBSD_SYSCALL;
+ c->frame_info.frame_type = UNW_ARM_FRAME_SYSCALL;
+ c->frame_info.cfa_reg_offset = 0;
+ c->dwarf.loc[UNW_ARM_R7] = c->dwarf.loc[UNW_ARM_R12];
+ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &c->dwarf.ip);
+ return 1;
+ }
+
+ c->sigcontext_format = ARM_SCF_FREEBSD_SIGFRAME;
+ sc_addr = sp_addr;
+
+ /* Save the SP and PC to be able to return execution at this point
+ later in time (unw_resume). */
+ c->sigcontext_sp = c->dwarf.cfa;
+ c->sigcontext_pc = c->dwarf.ip;
+
+ c->sigcontext_addr = sc_addr;
+ c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
+ c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
+
+ /* Update the dwarf cursor.
+ Set the location of the registers to the corresponding addresses of the
+ uc_mcontext / sigcontext structure contents. */
+#define ROFF(n) (FREEBSD_SC_UCONTEXT_OFF + FREEBSD_UC_MCONTEXT_OFF + \
+ FREEBSD_MC_R0_OFF + (n) * 4)
+#define SL(n) \
+ c->dwarf.loc[UNW_ARM_R ## n] = DWARF_LOC (sc_addr + ROFF(n), 0);
+ SL(0); SL(1); SL(2); SL(3); SL(4); SL(5); SL(6); SL(7);
+ SL(8); SL(9); SL(10); SL(11); SL(12); SL(13); SL(14); SL(15);
+#undef SL
+#undef ROFF
+
+ /* Set SP/CFA and PC/IP. */
+ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
+ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
+
+ return 1;
+}
+
+/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal
+ frame. */
+int
+unw_is_signal_frame (unw_cursor_t *cursor)
+{
+ struct cursor *c = (struct cursor *) cursor;
+ unw_word_t w0, w1, w2, w3, ip;
+ unw_addr_space_t as;
+ unw_accessors_t *a;
+ void *arg;
+ int ret;
+
+ as = c->dwarf.as;
+ a = unw_get_accessors_int (as);
+ arg = c->dwarf.as_arg;
+
+ ip = c->dwarf.ip;
+
+ if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0)
+ return ret;
+ if ((ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
+ return ret;
+ if ((ret = (*a->access_mem) (as, ip + 8, &w2, 0, arg)) < 0)
+ return ret;
+ if ((ret = (*a->access_mem) (as, ip + 12, &w3, 0, arg)) < 0)
+ return ret;
+
+ if (w0 == 0xe1a0000d && w1 == 0xe2800040 && w2 == 0xe59f700c &&
+ w3 == 0xef0001a1)
+ return UNW_ARM_FRAME_SIGRETURN;
+
+ if ((ret = (*a->access_mem) (as, ip - 4, &w0, 0, arg)) < 0)
+ return ret;
+ if (w0 == 0xef000000)
+ return UNW_ARM_FRAME_SYSCALL;
+
+ return 0;
+}
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2008 CodeSourcery
+ Copyright 2011 Linaro Limited
+ Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include <stdio.h>
+#include <signal.h>
+#include "unwind_i.h"
+#include "offsets.h"
+
+HIDDEN int
+arm_handle_signal_frame (unw_cursor_t *cursor)
+{
+ struct cursor *c = (struct cursor *) cursor;
+ int ret;
+ unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
+ struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
+
+ if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
+ return -UNW_EUNSPEC;
+
+ /* Obtain signal frame type (non-RT or RT). */
+ ret = unw_is_signal_frame (cursor);
+
+ /* Save the SP and PC to be able to return execution at this point
+ later in time (unw_resume). */
+ c->sigcontext_sp = c->dwarf.cfa;
+ c->sigcontext_pc = c->dwarf.ip;
+
+ /* Since kernel version 2.6.18 the non-RT signal frame starts with a
+ ucontext while the RT signal frame starts with a siginfo, followed
+ by a sigframe whose first element is an ucontext.
+ Prior 2.6.18 the non-RT signal frame starts with a sigcontext while
+ the RT signal frame starts with two pointers followed by a siginfo
+ and an ucontext. The first pointer points to the start of the siginfo
+ structure and the second one to the ucontext structure. */
+
+ if (ret == 1)
+ {
+ /* Handle non-RT signal frames. Check if the first word on the stack
+ is the magic number. */
+ if (sp == 0x5ac3c35a)
+ {
+ c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME;
+ sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
+ }
+ else
+ {
+ c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME;
+ sc_addr = sp_addr;
+ }
+ }
+ else if (ret == 2)
+ {
+ /* Handle RT signal frames. Check if the first word on the stack is a
+ pointer to the siginfo structure. */
+ if (sp == sp_addr + 8)
+ {
+ c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME;
+ sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
+ }
+ else
+ {
+ c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME;
+ sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
+ }
+ }
+ else
+ return -UNW_EUNSPEC;
+
+ c->sigcontext_addr = sc_addr;
+ c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
+ c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
+
+ /* Update the dwarf cursor.
+ Set the location of the registers to the corresponding addresses of the
+ uc_mcontext / sigcontext structure contents. */
+ c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0);
+ c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
+
+ /* Set SP/CFA and PC/IP. */
+ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
+ dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
+
+ c->dwarf.pi_valid = 0;
+
+ return 1;
+}
+
+#define ARM_NR_sigreturn 119
+#define ARM_NR_rt_sigreturn 173
+#define ARM_NR_OABI_SYSCALL_BASE 0x900000
+
+/* ARM EABI sigreturn (the syscall number is loaded into r7) */
+#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
+#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
+
+/* ARM OABI sigreturn (using SWI) */
+#define ARM_SIGRETURN \
+ (0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
+#define ARM_RT_SIGRETURN \
+ (0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
+
+/* Thumb sigreturn (two insns, syscall number is loaded into r7) */
+#define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn)
+#define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn)
+
+/* Thumb2 sigreturn (mov.w r7, $SYS_ify(rt_sigreturn/sigreturn)) */
+#define THUMB2_SIGRETURN (((0x0700 | ARM_NR_sigreturn) << 16) | \
+ 0xf04f)
+#define THUMB2_RT_SIGRETURN (((0x0700 | ARM_NR_rt_sigreturn) << 16) | \
+ 0xf04f)
+/* TODO: with different toolchains, there are a lot more possibilities */
+
+/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal
+ frame. */
+int
+unw_is_signal_frame (unw_cursor_t *cursor)
+{
+ struct cursor *c = (struct cursor *) cursor;
+ unw_word_t w0, ip;
+ unw_addr_space_t as;
+ unw_accessors_t *a;
+ void *arg;
+ int ret;
+
+ as = c->dwarf.as;
+ a = unw_get_accessors_int (as);
+ arg = c->dwarf.as_arg;
+
+ /* The least bit denotes thumb/arm mode. Do not read there. */
+ ip = c->dwarf.ip & ~0x1;
+
+ if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0)
+ return ret;
+
+ /* Return 1 if the IP points to a non-RT sigreturn sequence. */
+ if (w0 == MOV_R7_SIGRETURN || w0 == ARM_SIGRETURN || w0 == THUMB_SIGRETURN
+ || w0 == THUMB2_SIGRETURN)
+ return 1;
+ /* Return 2 if the IP points to a RT sigreturn sequence. */
+ else if (w0 == MOV_R7_RT_SIGRETURN || w0 == ARM_RT_SIGRETURN
+ || w0 == THUMB_RT_SIGRETURN || w0 == THUMB2_RT_SIGRETURN)
+ return 2;
+
+ return 0;
+}
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2008 CodeSourcery
+ Copyright 2011 Linaro Limited
+ Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include <stdio.h>
+#include <signal.h>
+#include "unwind_i.h"
+#include "offsets.h"
+
+HIDDEN int
+arm_handle_signal_frame (unw_cursor_t *cursor)
+{
+ return -UNW_EUNSPEC;
+}
+
+int
+unw_is_signal_frame (unw_cursor_t *cursor)
+{
+#if defined(__QNX__)
+ /* Not supported yet */
+ return 0;
+#else
+ printf ("%s: implement me\n", __FUNCTION__);
+ return -UNW_ENOINFO;
+#endif
+}
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
switch (reg)
{
+ case UNW_ARM_R15:
+ if (write)
+ c->dwarf.ip = *valp; /* update the IP cache */
case UNW_ARM_R0:
case UNW_ARM_R1:
case UNW_ARM_R2:
case UNW_ARM_R11:
case UNW_ARM_R12:
case UNW_ARM_R14:
- case UNW_ARM_R15:
loc = c->dwarf.loc[reg - UNW_ARM_R0];
break;
}
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
" ra=0x%x r7 [where=%d val=%d @0x%x] lr [where=%d val=%d @0x%x] "
"sp [where=%d val=%d @0x%x]\n",
d->ip, d->cfa, f->frame_type,
- rs->reg[DWARF_CFA_REG_COLUMN].where,
- rs->reg[DWARF_CFA_REG_COLUMN].val,
- rs->reg[DWARF_CFA_OFF_COLUMN].val,
- DWARF_GET_LOC(d->loc[d->ret_addr_column]),
- rs->reg[R7].where, rs->reg[R7].val, DWARF_GET_LOC(d->loc[R7]),
- rs->reg[LR].where, rs->reg[LR].val, DWARF_GET_LOC(d->loc[LR]),
- rs->reg[SP].where, rs->reg[SP].val, DWARF_GET_LOC(d->loc[SP]));
+ rs->reg.where[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_OFF_COLUMN],
+ DWARF_GET_LOC(d->loc[rs->ret_addr_column]),
+ rs->reg.where[R7], rs->reg.val[R7], DWARF_GET_LOC(d->loc[R7]),
+ rs->reg.where[LR], rs->reg.val[LR], DWARF_GET_LOC(d->loc[LR]),
+ rs->reg.where[SP], rs->reg.val[SP], DWARF_GET_LOC(d->loc[SP]));
/* A standard frame is defined as:
- CFA is register-relative offset off R7 or SP;
- LR is unsaved or saved at CFA+offset, offset != -1;
- SP is unsaved or saved at CFA+offset, offset != -1. */
if (f->frame_type == UNW_ARM_FRAME_OTHER
- && (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
- && (rs->reg[DWARF_CFA_REG_COLUMN].val == R7
- || rs->reg[DWARF_CFA_REG_COLUMN].val == SP)
- && labs(rs->reg[DWARF_CFA_OFF_COLUMN].val) < (1 << 29)
- && d->ret_addr_column == LR
- && (rs->reg[R7].where == DWARF_WHERE_UNDEF
- || rs->reg[R7].where == DWARF_WHERE_SAME
- || (rs->reg[R7].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[R7].val) < (1 << 29)
- && rs->reg[R7].val+1 != 0))
- && (rs->reg[LR].where == DWARF_WHERE_UNDEF
- || rs->reg[LR].where == DWARF_WHERE_SAME
- || (rs->reg[LR].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[LR].val) < (1 << 29)
- && rs->reg[LR].val+1 != 0))
- && (rs->reg[SP].where == DWARF_WHERE_UNDEF
- || rs->reg[SP].where == DWARF_WHERE_SAME
- || (rs->reg[SP].where == DWARF_WHERE_CFAREL
- && labs(rs->reg[SP].val) < (1 << 29)
- && rs->reg[SP].val+1 != 0)))
+ && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
+ && (rs->reg.val[DWARF_CFA_REG_COLUMN] == R7
+ || rs->reg.val[DWARF_CFA_REG_COLUMN] == SP)
+ && labs(rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 29)
+ && rs->ret_addr_column == LR
+ && (rs->reg.where[R7] == DWARF_WHERE_UNDEF
+ || rs->reg.where[R7] == DWARF_WHERE_SAME
+ || (rs->reg.where[R7] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[R7]) < (1 << 29)
+ && rs->reg.val[R7]+1 != 0))
+ && (rs->reg.where[LR] == DWARF_WHERE_UNDEF
+ || rs->reg.where[LR] == DWARF_WHERE_SAME
+ || (rs->reg.where[LR] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[LR]) < (1 << 29)
+ && rs->reg.val[LR]+1 != 0))
+ && (rs->reg.where[SP] == DWARF_WHERE_UNDEF
+ || rs->reg.where[SP] == DWARF_WHERE_SAME
+ || (rs->reg.where[SP] == DWARF_WHERE_CFAREL
+ && labs(rs->reg.val[SP]) < (1 << 29)
+ && rs->reg.val[SP]+1 != 0)))
{
/* Save information for a standard frame. */
f->frame_type = UNW_ARM_FRAME_STANDARD;
- f->cfa_reg_sp = (rs->reg[DWARF_CFA_REG_COLUMN].val == SP);
- f->cfa_reg_offset = rs->reg[DWARF_CFA_OFF_COLUMN].val;
- if (rs->reg[R7].where == DWARF_WHERE_CFAREL)
- f->r7_cfa_offset = rs->reg[R7].val;
- if (rs->reg[LR].where == DWARF_WHERE_CFAREL)
- f->lr_cfa_offset = rs->reg[LR].val;
- if (rs->reg[SP].where == DWARF_WHERE_CFAREL)
- f->sp_cfa_offset = rs->reg[SP].val;
+ f->cfa_reg_sp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == SP);
+ f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN];
+ if (rs->reg.where[R7] == DWARF_WHERE_CFAREL)
+ f->r7_cfa_offset = rs->reg.val[R7];
+ if (rs->reg.where[LR] == DWARF_WHERE_CFAREL)
+ f->lr_cfa_offset = rs->reg.val[LR];
+ if (rs->reg.where[SP] == DWARF_WHERE_CFAREL)
+ f->sp_cfa_offset = rs->reg.val[SP];
Debug (4, " standard frame\n");
}
else
/* mark PC unsaved */
c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
-
- if ((ret = tdep_find_proc_info (&c->dwarf, c->dwarf.ip, 1)) < 0)
- return ret;
+ unw_word_t ip = c->dwarf.ip;
+ if (c->dwarf.use_prev_instr)
+ --ip;
+
+ /* check dynamic info first --- it overrides everything else */
+ ret = unwi_find_dynamic_proc_info (c->dwarf.as, ip, &c->dwarf.pi, 1,
+ c->dwarf.as_arg);
+ if (ret == -UNW_ENOINFO)
+ {
+ if ((ret = tdep_find_proc_info (&c->dwarf, ip, 1)) < 0)
+ return ret;
+ }
if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
return -UNW_ENOINFO;
return (c->dwarf.ip == 0) ? 0 : 1;
}
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
-{
- struct cursor *c = (struct cursor *) cursor;
- int ret;
- unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
- struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
-
- if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
- return -UNW_EUNSPEC;
-
- /* Obtain signal frame type (non-RT or RT). */
- ret = unw_is_signal_frame (cursor);
-
- /* Save the SP and PC to be able to return execution at this point
- later in time (unw_resume). */
- c->sigcontext_sp = c->dwarf.cfa;
- c->sigcontext_pc = c->dwarf.ip;
-
- /* Since kernel version 2.6.18 the non-RT signal frame starts with a
- ucontext while the RT signal frame starts with a siginfo, followed
- by a sigframe whose first element is an ucontext.
- Prior 2.6.18 the non-RT signal frame starts with a sigcontext while
- the RT signal frame starts with two pointers followed by a siginfo
- and an ucontext. The first pointer points to the start of the siginfo
- structure and the second one to the ucontext structure. */
-
- if (ret == 1)
- {
- /* Handle non-RT signal frames. Check if the first word on the stack
- is the magic number. */
- if (sp == 0x5ac3c35a)
- {
- c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME;
- sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
- }
- else
- {
- c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME;
- sc_addr = sp_addr;
- }
- }
- else if (ret == 2)
- {
- /* Handle RT signal frames. Check if the first word on the stack is a
- pointer to the siginfo structure. */
- if (sp == sp_addr + 8)
- {
- c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME;
- sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
- }
- else
- {
- c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME;
- sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
- }
- }
- else
- return -UNW_EUNSPEC;
-
- c->sigcontext_addr = sc_addr;
- c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
- c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
-
- /* Update the dwarf cursor.
- Set the location of the registers to the corresponding addresses of the
- uc_mcontext / sigcontext structure contents. */
- c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
- c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
- c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
- c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
- c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
- c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
- c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
- c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
- c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
- c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
- c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
- c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0);
- c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0);
- c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
- c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0);
- c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
-
- /* Set SP/CFA and PC/IP. */
- dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
- dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
-
- c->dwarf.pi_valid = 0;
-
- return 1;
-}
-
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
Debug (1, "(cursor=%p)\n", c);
/* Check if this is a signal frame. */
- if (unw_is_signal_frame (cursor))
- return unw_handle_signal_frame (cursor);
+ if (unw_is_signal_frame (cursor) > 0)
+ return arm_handle_signal_frame (cursor);
#ifdef CONFIG_DEBUG_FRAME
/* First, try DWARF-based unwinding. */
/* Fall back on APCS frame parsing.
Note: This won't work in case the ARM EABI is used. */
+#ifdef __FreeBSD__
+ if (0)
+#else
if (unlikely (ret < 0))
+#endif
{
if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
{
+ Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
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
c->dwarf.loc[UNW_ARM_R12] = ip_loc;
c->dwarf.loc[UNW_ARM_R11] = fp_loc;
c->dwarf.pi_valid = 0;
- Debug(15, "ip=%lx\n", c->dwarf.ip);
+ Debug(15, "ip=%x\n", c->dwarf.ip);
}
else
{
}
}
}
- return ret == -UNW_ENOINFO ? 0 : 1;
+ return ret == -UNW_ENOINFO ? 0 : ret;
}
case UNW_ARM_FRAME_SIGRETURN:
cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */
-
+#if defined(__linux__)
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_PC_OFF, pc);
if (likely(ret >= 0))
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_R7_OFF, r7);
doesn't save the link register in the prologue, e.g. kill. */
if (likely(ret >= 0))
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_LR_OFF, lr);
+#elif defined(__FreeBSD__)
+ printf("XXX\n");
+#endif
/* Resume stack at signal restoration point. The stack is not
necessarily continuous here, especially with sigaltstack(). */
d->use_prev_instr = 0;
break;
+ case UNW_ARM_FRAME_SYSCALL:
+ printf("XXX1\n");
+ break;
+
default:
/* We cannot trace through this frame, give up and tell the
caller we had to stop. Data collected so far may still be
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gos-freebsd.c"
+#endif
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
-#include "Gstep.c"
+#include "Gos-linux.c"
#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gos-freebsd.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
_Uarm_getcontext:
stmfd sp!, {r0, r1}
@ store r0
+#if defined(__linux__)
str r0, [r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF]
add r0, r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF
+#elif defined(__FreeBSD__)
+ str r0, [r0, #FREEBSD_UC_MCONTEXT_OFF + FREEBSD_MC_R0_OFF]
+ add r0, r0, #FREEBSD_UC_MCONTEXT_OFF + FREEBSD_MC_R0_OFF
+#else
+#error Fix me
+#endif
@ store r1 to r12
stmib r0, {r1-r12}
@ reconstruct r13 at call site, then store
str r1, [r0, #15 * 4]
ldmfd sp!, {r0, r1}
bx lr
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
/* We do not need executable stack. */
.section .note.GNU-stack,"",%progbits
#endif
/* FIXME: Initialisation for other registers. */
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful
on ARM. Count all the FP or coprocessor registers we know about for now. */
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return ((regnum >= UNW_ARM_S0 && regnum <= UNW_ARM_S31)
#define LINUX_SC_PC_OFF 0x48
#define LINUX_SC_CPSR_OFF 0x4C
#define LINUX_SC_FAULTADDR_OFF 0x50
+
+/* FreeBSD-specific definitions: */
+
+#define FREEBSD_SC_UCONTEXT_OFF 0x40
+#define FREEBSD_UC_MCONTEXT_OFF 0x10
+#define FREEBSD_MC_R0_OFF 0
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
extern void arm_local_addr_space_init (void);
extern int arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
void *arg);
+#define arm_handle_signal_frame UNW_OBJ(handle_signal_frame)
+extern int arm_handle_signal_frame(unw_cursor_t *cursor);
+
/* By-pass calls to access_mem() when known to be safe. */
#ifdef UNW_LOCAL_ONLY
# undef ACCESS_MEM_FAST
default:
Debug(0, "bad regnum:%d\n", regnum);
return -UNW_EINVAL;
- };
+ }
#elif defined(UNW_TARGET_X86_64)
switch (regnum) {
case UNW_X86_64_RAX:
default:
Debug(0, "bad regnum:%d\n", regnum);
return -UNW_EINVAL;
- };
+ }
+#elif defined(UNW_TARGET_ARM)
+ if (regnum >= UNW_ARM_R0 && regnum <= UNW_ARM_R12) {
+ *valp = ui->prstatus->pr_reg.r[regnum];
+ } else {
+ switch (regnum) {
+ case UNW_ARM_R13:
+ *valp = ui->prstatus->pr_reg.r_sp;
+ break;
+ case UNW_ARM_R14:
+ *valp = ui->prstatus->pr_reg.r_lr;
+ break;
+ case UNW_ARM_R15:
+ *valp = ui->prstatus->pr_reg.r_pc;
+ break;
+ default:
+ Debug(0, "bad regnum:%d\n", regnum);
+ return -UNW_EINVAL;
+ }
+ }
#else
#error Port me
#endif
return -UNW_EINVAL;
}
+ if (regnum < 0)
+ goto badreg;
+
#if defined(UNW_TARGET_AARCH64)
- if (regnum < 0 || regnum >= UNW_AARCH64_FPCR)
+ if (regnum >= UNW_AARCH64_FPCR)
goto badreg;
#elif defined(UNW_TARGET_ARM)
- if (regnum < 0 || regnum >= 16)
+ if (regnum >= 16)
goto badreg;
#elif defined(UNW_TARGET_SH)
- if (regnum < 0 || regnum > UNW_SH_PR)
+ if (regnum > UNW_SH_PR)
goto badreg;
#elif defined(UNW_TARGET_TILEGX)
- if (regnum < 0 || regnum > UNW_TILEGX_CFA)
+ if (regnum > UNW_TILEGX_CFA)
goto badreg;
#else
#if defined(UNW_TARGET_MIPS)
#error Port me
#endif
- if (regnum < 0 || regnum >= (unw_regnum_t)ARRAY_SIZE(remap_regs))
+ if (regnum >= (unw_regnum_t)ARRAY_SIZE(remap_regs))
goto badreg;
regnum = remap_regs[regnum];
#include "_UCD_internal.h"
-PROTECTED unw_accessors_t _UCD_accessors =
+unw_accessors_t _UCD_accessors =
{
.find_proc_info = _UCD_find_proc_info,
.put_unwind_info = _UCD_put_unwind_info,
#include "_UCD_internal.h"
#define NOTE_DATA(_hdr) STRUCT_MEMBER_P((_hdr), sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4))
-#define NOTE_SIZE(_hdr) (sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4) + (_hdr)->n_descsz)
+#define NOTE_SIZE(_hdr) (sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4) + UNW_ALIGN((_hdr)->n_descsz, 4))
#define NOTE_NEXT(_hdr) STRUCT_MEMBER_P((_hdr), NOTE_SIZE(_hdr))
#define NOTE_FITS_IN(_hdr, _size) ((_size) >= sizeof (Elf32_Nhdr) && (_size) >= NOTE_SIZE (_hdr))
#define NOTE_FITS(_hdr, _end) NOTE_FITS_IN((_hdr), (unsigned long)((char *)(_end) - (char *)(_hdr)))
close(phdr->backing_fd);
}
+ free(ui->phdrs);
free(ui->note_phdr);
+ free(ui->threads);
free(ui);
}
}
HIDDEN int
+dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr,
+ unw_word_t rbp_addr, unw_word_t *cfa_offset) {
+ unw_accessors_t *a;
+ int ret;
+ void *arg;
+ unw_word_t len;
+ uint8_t opcode;
+ unw_word_t operand1;
+
+ a = unw_get_accessors_int (c->as);
+ arg = c->as_arg;
+
+ ret = dwarf_read_uleb128(c->as, a, &rbp_addr, &len, arg);
+ if (len != 2 || ret < 0)
+ return 0;
+
+ ret = dwarf_readu8(c->as, a, &rbp_addr, &opcode, arg);
+ if (ret < 0 || opcode != DW_OP_breg6)
+ return 0;
+
+ ret = read_operand(c->as, a, &rbp_addr,
+ OPND1_TYPE(operands[opcode]), &operand1, arg);
+
+ if (ret < 0 || operand1 != 0)
+ return 0;
+
+ ret = dwarf_read_uleb128(c->as, a, &cfa_addr, &len, arg);
+ if (ret < 0 || len != 3)
+ return 0;
+
+ ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg);
+ if (ret < 0 || opcode != DW_OP_breg6)
+ return 0;
+
+ ret = read_operand(c->as, a, &cfa_addr,
+ OPND1_TYPE(operands[opcode]), &operand1, arg);
+ if (ret < 0)
+ return 0;
+
+ ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg);
+ if (ret < 0 || opcode != DW_OP_deref)
+ return 0;
+
+ *cfa_offset = operand1;
+ return 1;
+}
+
+HIDDEN int
dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
unw_word_t *valp, int *is_register)
{
- unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2, tmp3, end_addr;
+ unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr;
uint8_t opcode, operands_signature, u8;
unw_addr_space_t as;
unw_accessors_t *a;
as = c->as;
arg = c->as_arg;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
end_addr = *addr + len;
*is_register = 0;
0xffffffffffffffff (for 64-bit ELF). However, .eh_frame
uses 0. */
if (is_debug_frame)
- return (val == - (uint32_t) 1 || val == - (uint64_t) 1);
+ return (val == (uint32_t)(-1) || val == (uint64_t)(-1));
else
return (val == 0);
}
if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0)
return ret;
- if (version != 1 && version != DWARF_CIE_VERSION)
+ /* GCC emits version 1??? */
+ if (version != 1 && (version < DWARF_CIE_VERSION || version > DWARF_CIE_VERSION_MAX))
{
- Debug (1, "Got CIE version %u, expected version 1 or "
- STR (DWARF_CIE_VERSION) "\n", version);
+ Debug (1, "Got CIE version %u, expected version 1 or between "
+ STR (DWARF_CIE_VERSION) " and " STR (DWARF_CIE_VERSION_MAX) "\n", version);
return -UNW_EBADVERSION;
}
if (u32val != 0xffffffff)
{
- int32_t cie_offset;
+ int32_t cie_offset = 0;
/* In some configurations, an FDE with a 0 length indicates the
end of the FDE-table. */
}
else
{
- int64_t cie_offset;
+ int64_t cie_offset = 0;
/* the FDE is in the 64-bit DWARF format */
#include "os-linux.h"
#endif
+#ifndef __clang__
+static ALIAS(dwarf_search_unwind_table) int
+dwarf_search_unwind_table_int (unw_addr_space_t as,
+ unw_word_t ip,
+ unw_dyn_info_t *di,
+ unw_proc_info_t *pi,
+ int need_unwind_info, void *arg);
+#else
+#define dwarf_search_unwind_table_int dwarf_search_unwind_table
+#endif
+
static int
linear_search (unw_addr_space_t as, unw_word_t ip,
unw_word_t eh_frame_start, unw_word_t eh_frame_end,
unw_word_t fde_count,
unw_proc_info_t *pi, int need_unwind_info, void *arg)
{
- unw_accessors_t *a = unw_get_accessors (unw_local_addr_space);
+ unw_accessors_t *a = unw_get_accessors_int (unw_local_addr_space);
unw_word_t i = 0, fde_addr, addr = eh_frame_start;
int ret;
/* Load .debug_frame section from FILE. Allocates and returns space
in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the
local process, in which case we can search the system debug file
- directory; 0 for other address spaces, in which case we do not; or
- -1 for recursive calls following .gnu_debuglink. Returns 0 on
- success, 1 on error. Succeeds even if the file contains no
- .debug_frame. */
+ directory; 0 for other address spaces, in which case we do
+ not. Returns 0 on success, 1 on error. Succeeds even if the file
+ contains no .debug_frame. */
/* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */
static int
load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
{
- FILE *f;
- Elf_W (Ehdr) ehdr;
- Elf_W (Half) shstrndx;
- Elf_W (Shdr) *sec_hdrs = NULL;
- char *stringtab = NULL;
- unsigned int i;
- size_t linksize = 0;
- char *linkbuf = NULL;
-
- *buf = NULL;
- *bufsize = 0;
-
- f = fopen (file, "r");
-
- if (!f)
- return 1;
-
- if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
- goto file_error;
-
- shstrndx = ehdr.e_shstrndx;
-
- Debug (4, "opened file '%s'. Section header at offset %d\n",
- file, (int) ehdr.e_shoff);
-
- fseek (f, ehdr.e_shoff, SEEK_SET);
- sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
- 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",
- sec_hdrs[shstrndx].sh_size);
- stringtab = malloc (sec_hdrs[shstrndx].sh_size);
- fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
- 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++)
- {
- char *secname = &stringtab[sec_hdrs[i].sh_name];
-
- if (strcmp (secname, ".debug_frame") == 0)
- {
- *bufsize = sec_hdrs[i].sh_size;
- *buf = malloc (*bufsize);
-
- fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
- if (fread (*buf, 1, *bufsize, f) != *bufsize)
- goto file_error;
-
- Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
- *bufsize, sec_hdrs[i].sh_offset);
- }
- else if (strcmp (secname, ".gnu_debuglink") == 0)
- {
- linksize = sec_hdrs[i].sh_size;
- linkbuf = malloc (linksize);
-
- fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
- if (fread (linkbuf, 1, linksize, f) != linksize)
- goto file_error;
-
- Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n",
- linksize, sec_hdrs[i].sh_offset);
- }
- }
+ struct elf_image ei;
+ Elf_W (Shdr) *shdr;
+ int ret;
- free (stringtab);
- free (sec_hdrs);
+ ei.image = NULL;
- fclose (f);
+ ret = elf_w (load_debuglink) (file, &ei, is_local);
+ if (ret != 0)
+ return ret;
- /* Ignore separate debug files which contain a .gnu_debuglink section. */
- if (linkbuf && is_local == -1)
+ shdr = elf_w (find_section) (&ei, ".debug_frame");
+ if (!shdr ||
+ (shdr->sh_offset + shdr->sh_size > ei.size))
{
- free (linkbuf);
+ munmap(ei.image, ei.size);
return 1;
}
- if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
- {
- char *newname, *basedir, *p;
- static const char *debugdir = "/usr/lib/debug";
- int ret;
+ *bufsize = shdr->sh_size;
+ *buf = malloc (*bufsize);
- /* XXX: Don't bother with the checksum; just search for the file. */
- basedir = malloc (strlen (file) + 1);
- newname = malloc (strlen (linkbuf) + strlen (debugdir)
- + strlen (file) + 9);
+ memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
- p = strrchr (file, '/');
- if (p != NULL)
- {
- memcpy (basedir, file, p - file);
- basedir[p - file] = '\0';
- }
- else
- basedir[0] = 0;
-
- strcpy (newname, basedir);
- strcat (newname, "/");
- strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
-
- if (ret == 1)
- {
- strcpy (newname, basedir);
- strcat (newname, "/.debug/");
- strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
- }
-
- if (ret == 1 && is_local == 1)
- {
- strcpy (newname, debugdir);
- strcat (newname, basedir);
- strcat (newname, "/");
- strcat (newname, linkbuf);
- ret = load_debug_frame (newname, buf, bufsize, -1);
- }
-
- free (basedir);
- free (newname);
- }
- free (linkbuf);
+ Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
+ *bufsize, shdr->sh_offset);
+ munmap(ei.image, ei.size);
return 0;
-
-/* An error reading image file. Release resources and return error code */
-file_error:
- free(stringtab);
- free(sec_hdrs);
- free(linkbuf);
- fclose(f);
-
- return 1;
}
/* Locate the binary which originated the contents of address ADDR. Return
int pid = getpid ();
unsigned long segbase, mapoff, hi;
- maps_init (&mi, pid);
+ if (maps_init (&mi, pid) != 0)
+ return 1;
+
while (maps_next (&mi, &segbase, &hi, &mapoff))
if (ip >= segbase && ip < hi)
{
name = (char*) dlname;
err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
-
+
if (!err)
{
fdesc = malloc (sizeof (struct unw_debug_frame_list));
fdesc->debug_frame_size = bufsize;
fdesc->index = NULL;
fdesc->next = as->debug_frames;
-
+
as->debug_frames = fdesc;
}
-
+
return fdesc;
}
tab->size *= 2;
tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
}
-
+
tab->tab[length].fde_offset = fde_offset;
tab->tab[length].start_ip_offset = start_ip;
-
+
tab->length = length + 1;
}
debug_frame_tab_compare (const void *a, const void *b)
{
const struct table_entry *fa = a, *fb = b;
-
+
if (fa->start_ip_offset > fb->start_ip_offset)
return 1;
else if (fa->start_ip_offset < fb->start_ip_offset)
return 0;
}
-PROTECTED int
+int
dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
unw_word_t segbase, const char* obj_name,
unw_word_t start, unw_word_t end)
{
addr = (unw_word_t) (uintptr_t) buf;
- a = unw_get_accessors (unw_local_addr_space);
+ a = unw_get_accessors_int (unw_local_addr_space);
/* Find all FDE entries in debug_frame, and make into a sorted
index. */
#ifndef UNW_REMOTE_ONLY
+static Elf_W (Addr)
+dwarf_find_eh_frame_section(struct dl_phdr_info *info)
+{
+ int rc;
+ struct elf_image ei;
+ Elf_W (Addr) eh_frame = 0;
+ Elf_W (Shdr)* shdr;
+ const char *file = info->dlpi_name;
+ char exepath[PATH_MAX];
+
+ if (strlen(file) == 0)
+ {
+ tdep_get_exe_image_path(exepath);
+ file = exepath;
+ }
+
+ Debug (1, "looking for .eh_frame section in %s\n",
+ file);
+
+ rc = elf_map_image (&ei, file);
+ if (rc != 0)
+ return 0;
+
+ shdr = elf_w (find_section) (&ei, ".eh_frame");
+ if (!shdr)
+ goto out;
+
+ eh_frame = shdr->sh_addr + info->dlpi_addr;
+ Debug (4, "found .eh_frame at address %lx\n",
+ eh_frame);
+
+out:
+ munmap (ei.image, ei.size);
+
+ return eh_frame;
+}
+
+struct dwarf_callback_data
+ {
+ /* in: */
+ unw_word_t ip; /* instruction-pointer we're looking for */
+ unw_proc_info_t *pi; /* proc-info pointer */
+ int need_unwind_info;
+ /* out: */
+ int single_fde; /* did we find a single FDE? (vs. a table) */
+ unw_dyn_info_t di; /* table info (if single_fde is false) */
+ unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
+ };
+
/* ptr is a pointer to a dwarf_callback_data structure and, on entry,
member ip contains the instruction-pointer we're looking
for. */
Elf_W(Addr) load_base, max_load_addr = 0;
int ret, need_unwind_info = cb_data->need_unwind_info;
unw_proc_info_t *pi = cb_data->pi;
- struct dwarf_eh_frame_hdr *hdr;
+ struct dwarf_eh_frame_hdr *hdr = NULL;
unw_accessors_t *a;
long n;
int found = 0;
+ struct dwarf_eh_frame_hdr synth_eh_frame_hdr;
#ifdef CONFIG_DEBUG_FRAME
unw_word_t start, end;
#endif /* CONFIG_DEBUG_FRAME*/
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
-
+
if (!p_text)
return 0;
if (p_eh_hdr)
{
+ hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
+ }
+ else
+ {
+ Elf_W (Addr) eh_frame;
+ Debug (1, "no .eh_frame_hdr section found\n");
+ eh_frame = dwarf_find_eh_frame_section (info);
+ if (eh_frame)
+ {
+ Debug (1, "using synthetic .eh_frame_hdr section for %s\n",
+ info->dlpi_name);
+ synth_eh_frame_hdr.version = DW_EH_VERSION;
+ synth_eh_frame_hdr.eh_frame_ptr_enc = DW_EH_PE_absptr |
+ ((sizeof(Elf_W (Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8);
+ synth_eh_frame_hdr.fde_count_enc = DW_EH_PE_omit;
+ synth_eh_frame_hdr.table_enc = DW_EH_PE_omit;
+ synth_eh_frame_hdr.eh_frame = eh_frame;
+ hdr = &synth_eh_frame_hdr;
+ }
+ }
+
+ if (hdr)
+ {
if (p_dynamic)
{
/* For dynamicly linked executables and shared libraries,
di->gp = 0;
pi->gp = di->gp;
- hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
if (hdr->version != DW_EH_VERSION)
{
Debug (1, "table `%s' has unexpected version %d\n",
return 0;
}
- a = unw_get_accessors (unw_local_addr_space);
- addr = (unw_word_t) (uintptr_t) (hdr + 1);
+ a = unw_get_accessors_int (unw_local_addr_space);
+ addr = (unw_word_t) (uintptr_t) (&hdr->eh_frame);
/* (Optionally) read eh_frame_ptr: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
abort ();
+ Debug (1, "eh_frame_start = %lx eh_frame_end = %lx\n",
+ eh_frame_start, eh_frame_end);
+
/* XXX we know how to build a local binary search table for
.debug_frame, so we could do that here too. */
- cb_data->single_fde = 1;
found = linear_search (unw_local_addr_space, ip,
eh_frame_start, eh_frame_end, fde_count,
pi, need_unwind_info, NULL);
if (found != 1)
found = 0;
+ else
+ cb_data->single_fde = 1;
}
else
{
ret = dl_iterate_phdr (dwarf_callback, &cb_data);
SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
- if (ret <= 0)
+ if (ret > 0)
{
- Debug (14, "IP=0x%lx not found\n", (long) ip);
- return -UNW_ENOINFO;
- }
-
- if (cb_data.single_fde)
- /* already got the result in *pi */
- return 0;
+ if (cb_data.single_fde)
+ /* already got the result in *pi */
+ return 0;
+
+ /* search the table: */
+ if (cb_data.di.format != -1)
+ ret = dwarf_search_unwind_table_int (as, ip, &cb_data.di,
+ pi, need_unwind_info, arg);
+ else
+ ret = -UNW_ENOINFO;
- /* search the table: */
- if (cb_data.di.format != -1)
- ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
- pi, need_unwind_info, arg);
+ if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
+ ret = dwarf_search_unwind_table_int (as, ip, &cb_data.di_debug, pi,
+ need_unwind_info, arg);
+ }
else
ret = -UNW_ENOINFO;
- if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
- ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi,
- need_unwind_info, arg);
return ret;
}
static int
remote_lookup (unw_addr_space_t as,
unw_word_t table, size_t table_size, int32_t rel_ip,
- struct table_entry *e, void *arg)
+ struct table_entry *e, int32_t *last_ip_offset, void *arg)
{
unsigned long table_len = table_size / sizeof (struct table_entry);
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
unsigned long lo, hi, mid;
unw_word_t e_addr = 0;
- int32_t start;
+ int32_t start = 0;
int ret;
/* do a binary search for right entry: */
return 0;
e_addr = table + (hi - 1) * sizeof (struct table_entry);
if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0
- || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0)
+ || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0
+ || (hi < table_len &&
+ (ret = dwarf_reads32 (as, a, &e_addr, last_ip_offset, arg)) < 0))
return ret;
return 1;
}
format == UNW_INFO_FORMAT_IP_OFFSET);
}
-PROTECTED int
+int
dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
unw_dyn_info_t *di, unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
const struct table_entry *e = NULL, *table;
- unw_word_t ip_base = 0, segbase = 0, fde_addr;
+ unw_word_t ip_base = 0, segbase = 0, last_ip, fde_addr;
unw_accessors_t *a;
#ifndef UNW_LOCAL_ONLY
struct table_entry ent;
#endif
}
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
segbase = di->u.rti.segbase;
if (di->format == UNW_INFO_FORMAT_IP_OFFSET) {
if (as == unw_local_addr_space)
{
e = lookup (table, table_len, ip - ip_base);
+ if (e && &e[1] < &table[table_len])
+ last_ip = e[1].start_ip_offset + ip_base;
+ else
+ last_ip = di->end_ip;
}
else
#endif
{
#ifndef UNW_LOCAL_ONLY
+ int32_t last_ip_offset = di->end_ip - ip_base;
segbase = di->u.rti.segbase;
if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
- ip - ip_base, &ent, arg)) < 0)
+ ip - ip_base, &ent, &last_ip_offset, arg)) < 0)
return ret;
if (ret)
- e = &ent;
+ {
+ e = &ent;
+ last_ip = last_ip_offset + ip_base;
+ }
else
e = NULL; /* no info found */
#endif
pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
}
+#if defined(NEED_LAST_IP)
+ pi->last_ip = last_ip;
+#else
+ (void)last_ip;
+#endif
if (ip < pi->start_ip || ip >= pi->end_ip)
return -UNW_ENOINFO;
#include "dwarf-eh.h"
#include "dwarf_i.h"
+#define to_unw_word(p) ((unw_word_t) (uintptr_t) (p))
+
int
dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as,
char *path, unw_word_t segbase, unw_word_t mapoff,
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 max_load_addr = 0;
- unw_word_t start_ip = (unw_word_t) -1;
+ unw_word_t start_ip = to_unw_word (-1);
unw_word_t end_ip = 0;
struct dwarf_eh_frame_hdr *hdr;
unw_proc_info_t pi;
return -UNW_ENOINFO;
}
- a = unw_get_accessors (unw_local_addr_space);
- addr = (unw_word_t) (hdr + 1);
+ a = unw_get_accessors_int (unw_local_addr_space);
+ addr = to_unw_word (&hdr->eh_frame);
/* Fill in a dummy proc_info structure. We just need to fill in
enough to ensure that dwarf_read_encoded_pointer() can do it's
/* two 32-bit values (ip_offset/fde_offset) per table-entry: */
edi->di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t);
edi->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr)
- + (addr - (unw_word_t) edi->ei.image
+ + (addr - to_unw_word (edi->ei.image)
- peh_hdr->p_offset));
/* For the binary-search table in the eh_frame_hdr, data-relative
means relative to the start of that section... */
edi->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr)
- + ((unw_word_t) hdr - (unw_word_t) edi->ei.image
+ + (to_unw_word (hdr) -
+ to_unw_word (edi->ei.image)
- peh_hdr->p_offset));
found = 1;
}
edi->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX;
edi->di_arm.start_ip = start_ip;
edi->di_arm.end_ip = end_ip;
- edi->di_arm.u.rti.name_ptr = (unw_word_t) path;
+ edi->di_arm.u.rti.name_ptr = to_unw_word (path);
edi->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr;
edi->di_arm.u.rti.table_len = parm_exidx->p_memsz;
found = 1;
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 <stddef.h>
#include "dwarf_i.h"
#include "libunwind_i.h"
+#include <stddef.h>
+#include <limits.h>
#define alloc_reg_state() (mempool_alloc (&dwarf_reg_state_pool))
#define free_reg_state(rs) (mempool_free (&dwarf_reg_state_pool, rs))
+#define DWARF_UNW_CACHE_SIZE(log_size) (1 << log_size)
+#define DWARF_UNW_HASH_SIZE(log_size) (1 << (log_size + 1))
+
static inline int
read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *valp, void *arg)
set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
unw_word_t val)
{
- sr->rs_current.reg[regnum].where = where;
- sr->rs_current.reg[regnum].val = val;
+ sr->rs_current.reg.where[regnum] = where;
+ sr->rs_current.reg.val[regnum] = val;
+}
+
+static inline int
+push_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
+{
+ dwarf_stackable_reg_state_t *old_rs = *rs_stack;
+ if (NULL == (*rs_stack = alloc_reg_state ()))
+ {
+ *rs_stack = old_rs;
+ return -1;
+ }
+ (*rs_stack)->next = old_rs;
+ return 0;
+}
+
+static inline void
+pop_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
+{
+ dwarf_stackable_reg_state_t *old_rs = *rs_stack;
+ *rs_stack = old_rs->next;
+ free_reg_state (old_rs);
+}
+
+static inline void
+empty_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
+{
+ while (*rs_stack)
+ pop_rstate_stack(rs_stack);
}
/* Run a CFI program to update the register state. */
static int
run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
- unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
+ unw_word_t *ip, unw_word_t end_ip,
+ unw_word_t *addr, unw_word_t end_addr,
+ dwarf_stackable_reg_state_t **rs_stack,
struct dwarf_cie_info *dci)
{
- unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
- dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
unw_addr_space_t as;
- unw_accessors_t *a;
- uint8_t u8, op;
- uint16_t u16;
- uint32_t u32;
void *arg;
- int ret;
- as = c->as;
- 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);
- curr_ip = c->pi.start_ip;
+ else
+ {
+ as = c->as;
+ arg = c->as_arg;
+ }
+ unw_accessors_t *a = unw_get_accessors_int (as);
+ int ret = 0;
- /* 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)
+ while (*ip <= end_ip && *addr < end_addr && ret >= 0)
{
+ unw_word_t operand = 0, regnum, val, len;
+ uint8_t u8, op;
+ uint16_t u16;
+ uint32_t u32;
+
if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
- return ret;
+ break;
if (op & DWARF_CFA_OPCODE_MASK)
{
switch ((dwarf_cfa_t) op)
{
case DW_CFA_advance_loc:
- curr_ip += operand * dci->code_align;
- Debug (15, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
+ *ip += operand * dci->code_align;
+ Debug (15, "CFA_advance_loc to 0x%lx\n", (long) *ip);
break;
case DW_CFA_advance_loc1:
if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
- goto fail;
- curr_ip += u8 * dci->code_align;
- Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
+ break;
+ *ip += u8 * dci->code_align;
+ Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) *ip);
break;
case DW_CFA_advance_loc2:
if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
- goto fail;
- curr_ip += u16 * dci->code_align;
- Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
+ break;
+ *ip += u16 * dci->code_align;
+ Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) *ip);
break;
case DW_CFA_advance_loc4:
if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
- goto fail;
- curr_ip += u32 * dci->code_align;
- Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
+ break;
+ *ip += u32 * dci->code_align;
+ Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) *ip);
break;
case DW_CFA_MIPS_advance_loc8:
#ifdef UNW_TARGET_MIPS
{
- uint64_t u64;
+ uint64_t u64 = 0;
if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
- goto fail;
- curr_ip += u64 * dci->code_align;
+ break;
+ *ip += u64 * dci->code_align;
Debug (15, "CFA_MIPS_advance_loc8\n");
break;
}
#else
Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
ret = -UNW_EINVAL;
- goto fail;
+ break;
#endif
case DW_CFA_offset:
Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
(unsigned int) regnum);
ret = -UNW_EBADREG;
- goto fail;
+ break;
}
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
Debug (15, "CFA_offset r%lu at cfa+0x%lx\n",
(long) regnum, (long) (val * dci->data_align));
case DW_CFA_offset_extended:
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n",
(long) regnum, (long) (val * dci->data_align));
case DW_CFA_offset_extended_sf:
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
(long) regnum, (long) (val * dci->data_align));
Debug (1, "Invalid register number %u in DW_CFA_restore\n",
(unsigned int) regnum);
ret = -UNW_EINVAL;
- goto fail;
+ break;
}
- sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
+ sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum];
+ sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum];
Debug (15, "CFA_restore r%lu\n", (long) regnum);
break;
case DW_CFA_restore_extended:
if ((ret = dwarf_read_uleb128 (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
if (regnum >= DWARF_NUM_PRESERVED_REGS)
{
Debug (1, "Invalid register number %u in "
"DW_CFA_restore_extended\n", (unsigned int) regnum);
ret = -UNW_EINVAL;
- goto fail;
+ break;
}
- sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
+ sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum];
+ sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum];
Debug (15, "CFA_restore_extended r%lu\n", (long) regnum);
break;
break;
case DW_CFA_set_loc:
- fde_encoding = dci->fde_encoding;
- if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
- &c->pi, &curr_ip,
+ if ((ret = dwarf_read_encoded_pointer (as, a, addr, dci->fde_encoding,
+ &c->pi, ip,
arg)) < 0)
- goto fail;
- Debug (15, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
+ break;
+ Debug (15, "CFA_set_loc to 0x%lx\n", (long) *ip);
break;
case DW_CFA_undefined:
if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
Debug (15, "CFA_undefined r%lu\n", (long) regnum);
break;
case DW_CFA_same_value:
if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
Debug (15, "CFA_same_value r%lu\n", (long) regnum);
break;
case DW_CFA_register:
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_REG, val);
Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
break;
case DW_CFA_remember_state:
- new_rs = alloc_reg_state ();
- if (!new_rs)
- {
+ if (push_rstate_stack(rs_stack) < 0)
+ {
Debug (1, "Out of memory in DW_CFA_remember_state\n");
ret = -UNW_ENOMEM;
- goto fail;
- }
-
- memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
- new_rs->next = rs_stack;
- rs_stack = new_rs;
+ break;
+ }
+ (*rs_stack)->state = sr->rs_current;
Debug (15, "CFA_remember_state\n");
break;
case DW_CFA_restore_state:
- if (!rs_stack)
+ if (!*rs_stack)
{
Debug (1, "register-state stack underflow\n");
ret = -UNW_EINVAL;
- goto fail;
+ break;
}
- memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
- old_rs = rs_stack;
- rs_stack = rs_stack->next;
- free_reg_state (old_rs);
+ sr->rs_current = (*rs_stack)->state;
+ pop_rstate_stack(rs_stack);
Debug (15, "CFA_restore_state\n");
break;
case DW_CFA_def_cfa:
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
case DW_CFA_def_cfa_sf:
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
val * dci->data_align); /* factored! */
case DW_CFA_def_cfa_register:
if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum);
break;
case DW_CFA_def_cfa_offset:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val); /* NOT factored! */
Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val);
break;
case DW_CFA_def_cfa_offset_sf:
if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
- goto fail;
+ break;
set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
val * dci->data_align); /* factored! */
Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n",
set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
- goto fail;
+ break;
Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
(long) *addr, (long) len);
case DW_CFA_expression:
if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
/* Save the address of the DW_FORM_block for later evaluation. */
set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
- goto fail;
+ break;
Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
(long) regnum, (long) addr, (long) len);
case DW_CFA_val_expression:
if ((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
- goto fail;
+ break;
/* Save the address of the DW_FORM_block for later evaluation. */
set_reg (sr, regnum, DWARF_WHERE_VAL_EXPR, *addr);
if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
- goto fail;
+ break;
Debug (15, "CFA_val_expression r%lu @ 0x%lx [%lu bytes]\n",
(long) regnum, (long) addr, (long) len);
case DW_CFA_GNU_args_size:
if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
- goto fail;
+ break;
sr->args_size = val;
Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
break;
PowerPC code. */
if (((ret = read_regnum (as, a, addr, ®num, arg)) < 0)
|| ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
- goto fail;
+ break;
set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align));
Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n",
(long) -(val * dci->data_align));
case DW_CFA_hi_user:
Debug (1, "Unexpected CFA opcode 0x%x\n", op);
ret = -UNW_EINVAL;
- goto fail;
+ break;
}
}
- ret = 0;
- fail:
- /* Free the register-state stack, if not empty already. */
- while (rs_stack)
- {
- old_rs = rs_stack;
- rs_stack = rs_stack->next;
- free_reg_state (old_rs);
- }
+ if (ret > 0)
+ ret = 0;
return ret;
}
static int
-fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
+fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip)
{
int ret, dynamic = 1;
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
+ For signal frame, 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
if (c->use_prev_instr)
--ip;
- if (c->pi_valid && !need_unwind_info)
- return 0;
-
memset (&c->pi, 0, sizeof (c->pi));
/* check dynamic info first --- it overrides everything else */
- ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
+ ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, 1,
c->as_arg);
if (ret == -UNW_ENOINFO)
{
dynamic = 0;
- if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 0)
+ if ((ret = tdep_find_proc_info (c, ip, 1)) < 0)
return ret;
}
/* 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;
- }
+ tdep_fetch_frame (c, ip, 1);
return ret;
}
parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
{
Debug (1, "Not yet implemented\n");
-#if 0
- /* Don't forget to set the ret_addr_column! */
- c->ret_addr_column = XXX;
-#endif
return -UNW_ENOINFO;
}
mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
pi->unwind_info = NULL;
}
+ c->pi_valid = 0;
}
static inline int
-parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
+setup_fde (struct dwarf_cursor *c, dwarf_state_record_t *sr)
{
- struct dwarf_cie_info *dci;
- unw_word_t addr;
- int ret;
+ int i, ret;
+
+ assert (c->pi_valid);
- dci = c->pi.unwind_info;
- c->ret_addr_column = dci->ret_addr_column;
+ memset (sr, 0, sizeof (*sr));
+ for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
+ set_reg (sr, i, DWARF_WHERE_SAME, 0);
- addr = dci->cie_instr_start;
- if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
- dci->cie_instr_end, dci)) < 0)
+ struct dwarf_cie_info *dci = c->pi.unwind_info;
+ sr->rs_current.ret_addr_column = dci->ret_addr_column;
+ unw_word_t addr = dci->cie_instr_start;
+ unw_word_t curr_ip = 0;
+ dwarf_stackable_reg_state_t *rs_stack = NULL;
+ ret = run_cfi_program (c, sr, &curr_ip, ~(unw_word_t) 0, &addr,
+ dci->cie_instr_end,
+ &rs_stack, dci);
+ empty_rstate_stack(&rs_stack);
+ if (ret < 0)
return ret;
memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
+ return 0;
+}
- addr = dci->fde_instr_start;
- if ((ret = run_cfi_program (c, sr, ip, &addr, dci->fde_instr_end, dci)) < 0)
+static inline int
+parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
+{
+ int ret;
+ struct dwarf_cie_info *dci = c->pi.unwind_info;
+ unw_word_t addr = dci->fde_instr_start;
+ unw_word_t curr_ip = c->pi.start_ip;
+ dwarf_stackable_reg_state_t *rs_stack = NULL;
+ /* Process up to current `ip` for signal frame and `ip - 1` for normal call frame
+ See `c->use_prev_instr` use in `fetch_proc_info` for details. */
+ ret = run_cfi_program (c, sr, &curr_ip, ip - c->use_prev_instr, &addr, dci->fde_instr_end,
+ &rs_stack, dci);
+ empty_rstate_stack(&rs_stack);
+ if (ret < 0)
return ret;
return 0;
}
-static inline void
-flush_rs_cache (struct dwarf_rs_cache *cache)
+HIDDEN int
+dwarf_flush_rs_cache (struct dwarf_rs_cache *cache)
{
int i;
- cache->lru_head = DWARF_UNW_CACHE_SIZE - 1;
- cache->lru_tail = 0;
+ if (cache->log_size == DWARF_DEFAULT_LOG_UNW_CACHE_SIZE
+ || !cache->hash) {
+ cache->hash = cache->default_hash;
+ cache->buckets = cache->default_buckets;
+ cache->links = cache->default_links;
+ cache->log_size = DWARF_DEFAULT_LOG_UNW_CACHE_SIZE;
+ } else {
+ if (cache->hash && cache->hash != cache->default_hash)
+ munmap(cache->hash, DWARF_UNW_HASH_SIZE(cache->prev_log_size)
+ * sizeof (cache->hash[0]));
+ if (cache->buckets && cache->buckets != cache->default_buckets)
+ munmap(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->prev_log_size)
+ * sizeof (cache->buckets[0]));
+ if (cache->links && cache->links != cache->default_links)
+ munmap(cache->links, DWARF_UNW_CACHE_SIZE(cache->prev_log_size)
+ * sizeof (cache->links[0]));
+ GET_MEMORY(cache->hash, DWARF_UNW_HASH_SIZE(cache->log_size)
+ * sizeof (cache->hash[0]));
+ GET_MEMORY(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->log_size)
+ * sizeof (cache->buckets[0]));
+ GET_MEMORY(cache->links, DWARF_UNW_CACHE_SIZE(cache->log_size)
+ * sizeof (cache->links[0]));
+ if (!cache->hash || !cache->buckets || !cache->links)
+ {
+ Debug (1, "Unable to allocate cache memory");
+ return -UNW_ENOMEM;
+ }
+ cache->prev_log_size = cache->log_size;
+ }
+
+ cache->rr_head = 0;
- for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i)
+ for (i = 0; i < DWARF_UNW_CACHE_SIZE(cache->log_size); ++i)
{
- if (i > 0)
- cache->buckets[i].lru_chain = (i - 1);
- cache->buckets[i].coll_chain = -1;
- cache->buckets[i].ip = 0;
- cache->buckets[i].valid = 0;
+ cache->links[i].coll_chain = -1;
+ cache->links[i].ip = 0;
+ cache->links[i].valid = 0;
}
- for (i = 0; i<DWARF_UNW_HASH_SIZE; ++i)
+ for (i = 0; i< DWARF_UNW_HASH_SIZE(cache->log_size); ++i)
cache->hash[i] = -1;
+
+ return 0;
}
static inline struct dwarf_rs_cache *
if (caching == UNW_CACHE_NONE)
return NULL;
+#if defined(HAVE___THREAD) && HAVE___THREAD
+ if (likely (caching == UNW_CACHE_PER_THREAD))
+ {
+ static __thread struct dwarf_rs_cache tls_cache __attribute__((tls_model("initial-exec")));
+ Debug (16, "using TLS cache\n");
+ cache = &tls_cache;
+ }
+ else
+#else
if (likely (caching == UNW_CACHE_GLOBAL))
+#endif
{
Debug (16, "acquiring lock\n");
lock_acquire (&cache->lock, *saved_maskp);
}
- if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
+ if ((atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
+ || !cache->hash)
{
- flush_rs_cache (cache);
+ /* cache_size is only set in the global_cache, copy it over before flushing */
+ cache->log_size = as->global_cache.log_size;
+ if (dwarf_flush_rs_cache (cache) < 0)
+ return NULL;
cache->generation = as->cache_generation;
}
}
static inline unw_hash_index_t CONST_ATTR
-hash (unw_word_t ip)
+hash (unw_word_t ip, unsigned short log_size)
{
/* based on (sqrt(5)/2-1)*2^64 */
# define magic ((unw_word_t) 0x9e3779b97f4a7c16ULL)
- return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE);
+ return ip * magic >> ((sizeof(unw_word_t) * 8) - (log_size + 1));
}
static inline long
-cache_match (dwarf_reg_state_t *rs, unw_word_t ip)
+cache_match (struct dwarf_rs_cache *cache, unsigned short index, unw_word_t ip)
{
- if (rs->valid && (ip == rs->ip))
- return 1;
- return 0;
+ return (cache->links[index].valid && (ip == cache->links[index].ip));
}
static dwarf_reg_state_t *
rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c)
{
- dwarf_reg_state_t *rs = cache->buckets + c->hint;
unsigned short index;
- unw_word_t ip;
+ unw_word_t ip = c->ip;
- ip = c->ip;
-
- if (cache_match (rs, ip))
- return rs;
-
- index = cache->hash[hash (ip)];
- if (index >= DWARF_UNW_CACHE_SIZE)
- return NULL;
+ if (c->hint > 0)
+ {
+ index = c->hint - 1;
+ if (cache_match (cache, index, ip))
+ return &cache->buckets[index];
+ }
- rs = cache->buckets + index;
- while (1)
+ for (index = cache->hash[hash (ip, cache->log_size)];
+ index < DWARF_UNW_CACHE_SIZE(cache->log_size);
+ index = cache->links[index].coll_chain)
{
- if (cache_match (rs, ip))
- {
- /* update hint; no locking needed: single-word writes are atomic */
- c->hint = cache->buckets[c->prev_rs].hint =
- (rs - cache->buckets);
- return rs;
- }
- if (rs->coll_chain >= DWARF_UNW_HASH_SIZE)
- return NULL;
- rs = cache->buckets + rs->coll_chain;
+ if (cache_match (cache, index, ip))
+ return &cache->buckets[index];
}
+ return NULL;
}
static inline dwarf_reg_state_t *
rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
{
- dwarf_reg_state_t *rs, *prev, *tmp;
unw_hash_index_t index;
unsigned short head;
- head = cache->lru_head;
- rs = cache->buckets + head;
- cache->lru_head = rs->lru_chain;
-
- /* re-insert rs at the tail of the LRU chain: */
- cache->buckets[cache->lru_tail].lru_chain = head;
- cache->lru_tail = head;
+ head = cache->rr_head;
+ cache->rr_head = (head + 1) & (DWARF_UNW_CACHE_SIZE(cache->log_size) - 1);
/* remove the old rs from the hash table (if it's there): */
- if (rs->ip)
+ if (cache->links[head].ip)
{
- index = hash (rs->ip);
- tmp = cache->buckets + cache->hash[index];
- prev = NULL;
- while (1)
- {
- if (tmp == rs)
- {
- if (prev)
- prev->coll_chain = tmp->coll_chain;
- else
- cache->hash[index] = tmp->coll_chain;
- break;
- }
- else
- prev = tmp;
- if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE)
- /* old rs wasn't in the hash-table */
- break;
- tmp = cache->buckets + tmp->coll_chain;
- }
+ unsigned short *pindex;
+ for (pindex = &cache->hash[hash (cache->links[head].ip, cache->log_size)];
+ *pindex < DWARF_UNW_CACHE_SIZE(cache->log_size);
+ pindex = &cache->links[*pindex].coll_chain)
+ {
+ if (*pindex == head)
+ {
+ *pindex = cache->links[*pindex].coll_chain;
+ break;
+ }
+ }
}
/* enter new rs in the hash table */
- index = hash (c->ip);
- rs->coll_chain = cache->hash[index];
- cache->hash[index] = rs - cache->buckets;
-
- rs->hint = 0;
- rs->ip = c->ip;
- rs->valid = 1;
- rs->ret_addr_column = c->ret_addr_column;
- rs->signal_frame = 0;
- tdep_cache_frame (c, rs);
-
- return rs;
+ index = hash (c->ip, cache->log_size);
+ cache->links[head].coll_chain = cache->hash[index];
+ cache->hash[index] = head;
+
+ cache->links[head].ip = c->ip;
+ cache->links[head].valid = 1;
+ cache->links[head].signal_frame = tdep_cache_frame(c);
+ return cache->buckets + head;
}
static int
create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
unw_word_t ip)
{
- int i, ret;
-
- assert (c->pi_valid);
-
- memset (sr, 0, sizeof (*sr));
- for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
- set_reg (sr, i, DWARF_WHERE_SAME, 0);
-
+ int ret;
switch (c->pi.format)
{
case UNW_INFO_FORMAT_TABLE:
case UNW_INFO_FORMAT_REMOTE_TABLE:
+ if ((ret = setup_fde(c, sr)) < 0)
+ return ret;
ret = parse_fde (c, ip, sr);
break;
as = c->as;
arg = c->as_arg;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
/* Evaluate the CFA first, because it may be referred to by other
expressions. */
- if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
+ if (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
{
/* CFA is equal to [reg] + offset: */
/* As a special-case, if the stack-pointer is the CFA and the
stack-pointer wasn't saved, popping the CFA implicitly pops
the stack-pointer as well. */
- 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))
+ if ((rs->reg.val[DWARF_CFA_REG_COLUMN] == UNW_TDEP_SP)
+ && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg.val))
+ && (rs->reg.where[UNW_TDEP_SP] == DWARF_WHERE_SAME))
cfa = c->cfa;
else
{
- regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
+ regnum = dwarf_to_unw_regnum (rs->reg.val[DWARF_CFA_REG_COLUMN]);
if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
return ret;
}
- cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
+ cfa += rs->reg.val[DWARF_CFA_OFF_COLUMN];
}
else
{
/* CFA is equal to EXPR: */
- assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
+ assert (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR);
- addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
+ addr = rs->reg.val[DWARF_CFA_REG_COLUMN];
if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
return ret;
/* the returned location better be a memory location... */
cfa = DWARF_GET_LOC (cfa_loc);
}
+ dwarf_loc_t new_loc[DWARF_NUM_PRESERVED_REGS];
+ memcpy(new_loc, c->loc, sizeof(new_loc));
+
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
{
- switch ((dwarf_where_t) rs->reg[i].where)
+ switch ((dwarf_where_t) rs->reg.where[i])
{
case DWARF_WHERE_UNDEF:
- c->loc[i] = DWARF_NULL_LOC;
+ new_loc[i] = DWARF_NULL_LOC;
break;
case DWARF_WHERE_SAME:
break;
case DWARF_WHERE_CFAREL:
- c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
+ new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]);
break;
case DWARF_WHERE_REG:
- c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
+ new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
break;
case DWARF_WHERE_EXPR:
- addr = rs->reg[i].val;
- if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+ addr = rs->reg.val[i];
+ if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
return ret;
break;
case DWARF_WHERE_VAL_EXPR:
- addr = rs->reg[i].val;
- if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+ addr = rs->reg.val[i];
+ if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
return ret;
- c->loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (c->loc[i]));
+ new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
break;
}
}
+ memcpy(c->loc, new_loc, sizeof(new_loc));
+
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;
+ if (DWARF_IS_NULL_LOC (c->loc[rs->ret_addr_column]))
+ {
+ c->ip = 0;
+ ret = 0;
+ }
else
{
- ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
+ ret = dwarf_get (c, c->loc[rs->ret_addr_column], &ip);
if (ret < 0)
return ret;
c->ip = ip;
+ ret = 1;
}
/* XXX: check for ip to be code_aligned */
if (c->stash_frames)
tdep_stash_frame (c, rs);
- return 0;
+ return ret;
}
+/* Find the saved locations. */
static int
-uncached_dwarf_find_save_locs (struct dwarf_cursor *c)
+find_reg_state (struct dwarf_cursor *c, dwarf_state_record_t *sr)
{
- dwarf_state_record_t sr;
- int ret;
+ dwarf_reg_state_t *rs;
+ struct dwarf_rs_cache *cache;
+ int ret = 0;
+ intrmask_t saved_mask;
- if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
+ if ((cache = get_rs_cache(c->as, &saved_mask)) &&
+ (rs = rs_lookup(cache, c)))
{
+ /* update hint; no locking needed: single-word writes are atomic */
+ unsigned short index = rs - cache->buckets;
+ c->use_prev_instr = ! cache->links[index].signal_frame;
+ memcpy (&sr->rs_current, rs, sizeof (*rs));
+ }
+ else
+ {
+ ret = fetch_proc_info (c, c->ip);
+ int next_use_prev_instr = c->use_prev_instr;
+ if (ret >= 0)
+ {
+ /* Update use_prev_instr for the next frame. */
+ assert(c->pi.unwind_info);
+ struct dwarf_cie_info *dci = c->pi.unwind_info;
+ next_use_prev_instr = ! dci->signal_frame;
+ ret = create_state_record_for (c, sr, c->ip);
+ }
put_unwind_info (c, &c->pi);
- return ret;
+ c->use_prev_instr = next_use_prev_instr;
+
+ if (cache && ret >= 0)
+ {
+ rs = rs_new (cache, c);
+ cache->links[rs - cache->buckets].hint = 0;
+ memcpy(rs, &sr->rs_current, sizeof(*rs));
+ }
}
- if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
- return ret;
-
- if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
- return ret;
-
- put_unwind_info (c, &c->pi);
+ unsigned short index = -1;
+ if (cache)
+ {
+ put_rs_cache (c->as, cache, &saved_mask);
+ if (rs)
+ {
+ index = rs - cache->buckets;
+ c->hint = cache->links[index].hint;
+ cache->links[c->prev_rs].hint = index + 1;
+ c->prev_rs = index;
+ }
+ }
+ if (ret < 0)
+ return ret;
+ if (cache)
+ tdep_reuse_frame (c, cache->links[index].signal_frame);
return 0;
}
/* The function finds the saved locations and applies the register
state as well. */
HIDDEN int
-dwarf_find_save_locs (struct dwarf_cursor *c)
+dwarf_step (struct dwarf_cursor *c)
{
+ int ret;
dwarf_state_record_t sr;
- dwarf_reg_state_t *rs, rs_copy;
- struct dwarf_rs_cache *cache;
- int ret = 0;
- intrmask_t saved_mask;
-
- if (c->as->caching_policy == UNW_CACHE_NONE)
- return uncached_dwarf_find_save_locs (c);
+ if ((ret = find_reg_state (c, &sr)) < 0)
+ return ret;
+ return apply_reg_state (c, &sr.rs_current);
+}
- cache = get_rs_cache(c->as, &saved_mask);
- rs = rs_lookup(cache, c);
+HIDDEN int
+dwarf_make_proc_info (struct dwarf_cursor *c)
+{
+#if 0
+ if (c->as->caching_policy == UNW_CACHE_NONE
+ || get_cached_proc_info (c) < 0)
+#endif
+ /* Need to check if current frame contains
+ args_size, and set cursor appropriately. Only
+ needed for unw_resume */
+ dwarf_state_record_t sr;
+ int ret;
- if (rs)
- {
- c->ret_addr_column = rs->ret_addr_column;
- c->use_prev_instr = ! rs->signal_frame;
- }
- else
- {
- 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);
- put_unwind_info (c, &c->pi);
- return ret;
- }
+ /* Lookup it up the slow way... */
+ ret = fetch_proc_info (c, c->ip);
+ if (ret >= 0)
+ ret = create_state_record_for (c, &sr, c->ip);
+ put_unwind_info (c, &c->pi);
+ if (ret < 0)
+ return ret;
+ c->args_size = sr.args_size;
- rs = rs_new (cache, c);
- memcpy(rs, &sr.rs_current, offsetof(struct dwarf_reg_state, ip));
- cache->buckets[c->prev_rs].hint = rs - cache->buckets;
+ return 0;
+}
- c->hint = rs->hint;
- c->prev_rs = rs - cache->buckets;
+static int
+dwarf_reg_states_dynamic_iterate(struct dwarf_cursor *c,
+ unw_reg_states_callback cb,
+ void *token)
+{
+ Debug (1, "Not yet implemented\n");
+ return -UNW_ENOINFO;
+}
- put_unwind_info (c, &c->pi);
+static int
+dwarf_reg_states_table_iterate(struct dwarf_cursor *c,
+ unw_reg_states_callback cb,
+ void *token)
+{
+ dwarf_state_record_t sr;
+ int ret = setup_fde(c, &sr);
+ struct dwarf_cie_info *dci = c->pi.unwind_info;
+ unw_word_t addr = dci->fde_instr_start;
+ unw_word_t curr_ip = c->pi.start_ip;
+ dwarf_stackable_reg_state_t *rs_stack = NULL;
+ while (ret >= 0 && curr_ip < c->pi.end_ip && addr < dci->fde_instr_end)
+ {
+ unw_word_t prev_ip = curr_ip;
+ ret = run_cfi_program (c, &sr, &curr_ip, prev_ip, &addr, dci->fde_instr_end,
+ &rs_stack, dci);
+ if (ret >= 0 && prev_ip < curr_ip)
+ ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), prev_ip, curr_ip);
}
-
- memcpy (&rs_copy, rs, sizeof (rs_copy));
- put_rs_cache (c->as, cache, &saved_mask);
-
- tdep_reuse_frame (c, &rs_copy);
- if ((ret = apply_reg_state (c, &rs_copy)) < 0)
- return ret;
-
- return 0;
+ empty_rstate_stack(&rs_stack);
+#if defined(NEED_LAST_IP)
+ if (ret >= 0 && curr_ip < c->pi.last_ip)
+ /* report the dead zone after the procedure ends */
+ ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.last_ip);
+#else
+ if (ret >= 0 && curr_ip < c->pi.end_ip)
+ /* report for whatever is left before procedure end */
+ ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.end_ip);
+#endif
+ return ret;
}
-/* The proc-info must be valid for IP before this routine can be
- called. */
HIDDEN int
-dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr)
+dwarf_reg_states_iterate(struct dwarf_cursor *c,
+ unw_reg_states_callback cb,
+ void *token)
{
- return create_state_record_for (c, sr, c->ip);
+ int ret = fetch_proc_info (c, c->ip);
+ int next_use_prev_instr = c->use_prev_instr;
+ if (ret >= 0)
+ {
+ /* Update use_prev_instr for the next frame. */
+ assert(c->pi.unwind_info);
+ struct dwarf_cie_info *dci = c->pi.unwind_info;
+ next_use_prev_instr = ! dci->signal_frame;
+ switch (c->pi.format)
+ {
+ case UNW_INFO_FORMAT_TABLE:
+ case UNW_INFO_FORMAT_REMOTE_TABLE:
+ ret = dwarf_reg_states_table_iterate(c, cb, token);
+ break;
+
+ case UNW_INFO_FORMAT_DYNAMIC:
+ ret = dwarf_reg_states_dynamic_iterate (c, cb, token);
+ break;
+
+ default:
+ Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
+ ret = -UNW_EINVAL;
+ }
+ }
+ put_unwind_info (c, &c->pi);
+ c->use_prev_instr = next_use_prev_instr;
+ return ret;
}
HIDDEN int
-dwarf_make_proc_info (struct dwarf_cursor *c)
+dwarf_apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
{
-#if 0
- if (c->as->caching_policy == UNW_CACHE_NONE
- || get_cached_proc_info (c) < 0)
-#endif
- /* Lookup it up the slow way... */
- return fetch_proc_info (c, c->ip, 0);
- return 0;
+ return apply_reg_state(c, rs);
}
HIDDEN int
dwarf_init (void)
{
- mempool_init (&dwarf_reg_state_pool, sizeof (dwarf_reg_state_t), 0);
+ mempool_init (&dwarf_reg_state_pool, sizeof (dwarf_stackable_reg_state_t), 0);
mempool_init (&dwarf_cie_info_pool, sizeof (struct dwarf_cie_info), 0);
return 0;
}
static int
elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi)
{
- Elf_W (Ehdr) *ehdr = ei->image;
Elf_W (Shdr) *shdr;
- char *strtab;
- int i;
uint8_t *compressed = NULL;
uint64_t memlimit = UINT64_MAX; /* no memory limit */
size_t compressed_len, uncompressed_len;
- if (!elf_w (valid_object) (ei))
- return 0;
-
- shdr = elf_w (section_table) (ei);
+ shdr = elf_w (find_section) (ei, ".gnu_debugdata");
if (!shdr)
return 0;
- strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
- if (!strtab)
- return 0;
-
- for (i = 0; i < ehdr->e_shnum; ++i)
- {
- if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0)
- {
- if (shdr->sh_offset + shdr->sh_size > ei->size)
- {
- Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n",
- (unsigned long) shdr->sh_offset + shdr->sh_size,
- (unsigned long) ei->size);
- return 0;
- }
-
- Debug (16, "found .gnu_debugdata at 0x%lx\n",
- (unsigned long) shdr->sh_offset);
- compressed = ((uint8_t *) ei->image) + shdr->sh_offset;
- compressed_len = shdr->sh_size;
- break;
- }
-
- shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
- }
-
- /* not found */
- if (!compressed)
- return 0;
+ compressed = ((uint8_t *) ei->image) + shdr->sh_offset;
+ compressed_len = shdr->sh_size;
uncompressed_len = xz_uncompressed_size (compressed, compressed_len);
if (uncompressed_len == 0)
unsigned long segbase, mapoff;
struct elf_image ei;
int ret;
+ char file[PATH_MAX];
+
+ ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff, file, PATH_MAX);
+ if (ret < 0)
+ return ret;
- ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff, NULL, 0);
+ ret = elf_w (load_debuglink) (file, &ei, 1);
if (ret < 0)
return ret;
return ret;
}
+
+HIDDEN Elf_W (Shdr)*
+elf_w (find_section) (struct elf_image *ei, const char* secname)
+{
+ Elf_W (Ehdr) *ehdr = ei->image;
+ Elf_W (Shdr) *shdr;
+ char *strtab;
+ int i;
+
+ if (!elf_w (valid_object) (ei))
+ return 0;
+
+ shdr = elf_w (section_table) (ei);
+ if (!shdr)
+ return 0;
+
+ strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
+ if (!strtab)
+ return 0;
+
+ for (i = 0; i < ehdr->e_shnum; ++i)
+ {
+ if (strcmp (strtab + shdr->sh_name, secname) == 0)
+ {
+ if (shdr->sh_offset + shdr->sh_size > ei->size)
+ {
+ Debug (1, "section \"%s\" outside image? (0x%lu > 0x%lu)\n",
+ secname,
+ (unsigned long) shdr->sh_offset + shdr->sh_size,
+ (unsigned long) ei->size);
+ return 0;
+ }
+
+ Debug (16, "found section \"%s\" at 0x%lx\n",
+ secname, (unsigned long) shdr->sh_offset);
+ return shdr;
+ }
+
+ shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
+ }
+
+ /* section not found */
+ return 0;
+}
+
+/* Load a debug section, following .gnu_debuglink if appropriate
+ * Loads ei from file if not already mapped.
+ * If is_local, will also search sys directories /usr/local/dbg
+ *
+ * Returns 0 on success, failure otherwise.
+ * ei will be mapped to file or the located .gnu_debuglink from file
+ */
+HIDDEN int
+elf_w (load_debuglink) (const char* file, struct elf_image *ei, int is_local)
+{
+ int ret;
+ Elf_W (Shdr) *shdr;
+ Elf_W (Ehdr) *prev_image;
+ off_t prev_size;
+
+ if (!ei->image)
+ {
+ ret = elf_map_image(ei, file);
+ if (ret)
+ return ret;
+ }
+
+ prev_image = ei->image;
+ prev_size = ei->size;
+
+ /* Ignore separate debug files which contain a .gnu_debuglink section. */
+ if (is_local == -1) {
+ return 0;
+ }
+
+ shdr = elf_w (find_section) (ei, ".gnu_debuglink");
+ if (shdr) {
+ if (shdr->sh_size >= PATH_MAX ||
+ (shdr->sh_offset + shdr->sh_size > ei->size))
+ {
+ return 0;
+ }
+
+ {
+ char linkbuf[shdr->sh_size];
+ char *link = ((char *) ei->image) + shdr->sh_offset;
+ char *p;
+ static const char *debugdir = "/usr/lib/debug";
+ char basedir[strlen(file) + 1];
+ char newname[shdr->sh_size + strlen (debugdir) + strlen (file) + 9];
+
+ memcpy(linkbuf, link, shdr->sh_size);
+
+ if (memchr (linkbuf, 0, shdr->sh_size) == NULL)
+ return 0;
+
+ ei->image = NULL;
+
+ Debug(1, "Found debuglink section, following %s\n", linkbuf);
+
+ p = strrchr (file, '/');
+ if (p != NULL)
+ {
+ memcpy (basedir, file, p - file);
+ basedir[p - file] = '\0';
+ }
+ else
+ basedir[0] = 0;
+
+ strcpy (newname, basedir);
+ strcat (newname, "/");
+ strcat (newname, linkbuf);
+ ret = elf_w (load_debuglink) (newname, ei, -1);
+
+ if (ret == -1)
+ {
+ strcpy (newname, basedir);
+ strcat (newname, "/.debug/");
+ strcat (newname, linkbuf);
+ ret = elf_w (load_debuglink) (newname, ei, -1);
+ }
+
+ if (ret == -1 && is_local == 1)
+ {
+ strcpy (newname, debugdir);
+ strcat (newname, basedir);
+ strcat (newname, "/");
+ strcat (newname, linkbuf);
+ ret = elf_w (load_debuglink) (newname, ei, -1);
+ }
+
+ if (ret == -1)
+ {
+ /* No debuglink file found even though .gnu_debuglink existed */
+ ei->image = prev_image;
+ ei->size = prev_size;
+
+ return 0;
+ }
+ else
+ {
+ munmap (prev_image, prev_size);
+ }
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp);
+extern Elf_W (Shdr)* elf_w (find_section) (struct elf_image *ei, const char* secname);
+extern int elf_w (load_debuglink) (const char* file, struct elf_image *ei, int is_local);
+
static inline int
elf_w (valid_object) (struct elf_image *ei)
{
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
/* struct cursor *c = (struct cursor *) cursor; */
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
hppa_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
/* Check if IP points at sigreturn() sequence. On Linux, this normally is:
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
return 0;
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
c->sigcontext_format = HPPA_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = sc_addr;
- c->dwarf.ret_addr_column = UNW_HPPA_RP;
if ((ret = dwarf_get (&c->dwarf, iaoq_loc, &ip)) < 0)
{
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
"cfa"
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ // Needs dwarf support on ia64
+ // return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+ return -UNW_EINVAL;
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "offsets.h"
#include "regs.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
#ifdef HAVE_SYS_UC_ACCESS_H
#elif defined(__hpux)
local_addr_space.abi = ABI_HPUX;
#endif
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = tdep_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
return -UNW_EINVAL;
return 0;
}
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
struct cursor *c = (struct cursor *) cursor;
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ // Needs dwarf support on ia64
+ // return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+ return -UNW_EINVAL;
+}
#endif /* !UNW_LOCAL_ONLY */
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
IA64_INSN_MOVE_SCRATCH_NO_NAT /* like above, but clear NaT info */
};
-#ifdef HAVE___THREAD
+#if defined(HAVE___THREAD) && HAVE___THREAD
static __thread struct ia64_script_cache ia64_per_thread_cache =
{
#ifdef HAVE_ATOMIC_OPS_H
if (!spin_trylock_irqsave (&cache->busy, *saved_maskp))
return NULL;
#else
-# ifdef HAVE___THREAD
+# if defined(HAVE___THREAD) && HAVE___THREAD
if (as->caching_policy == UNW_CACHE_PER_THREAD)
cache = &ia64_per_thread_cache;
# endif
}
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
static inline int
read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg)
{
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
return (*a->access_mem) (as, addr, valp, 0, arg);
}
struct ia64_table_entry *e, void *arg)
{
unw_word_t e_addr = 0, start_offset, end_offset, info_offset;
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
unsigned long lo, hi, mid;
int ret;
}
}
-PROTECTED unw_word_t
+unw_word_t
_Uia64_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
{
unw_word_t hdr_addr, info_addr, hdr, directives, pers, cookie, off;
case UNW_INFO_FORMAT_REMOTE_TABLE:
{
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
unw_word_t e_addr = di->u.rti.table_data;
table_size = di->u.rti.table_len * sizeof (unw_word_t);
return e;
}
-PROTECTED int
+int
unw_search_ia64_unwind_table (unw_addr_space_t as, unw_word_t ip,
unw_dyn_info_t *di, unw_proc_info_t *pi,
int need_unwind_info, void *arg)
# ifndef UNW_LOCAL_ONLY
/* This is exported for the benefit of libunwind-ptrace.a. */
-PROTECTED int
+int
_Uia64_get_kernel_table (unw_dyn_info_t *di)
{
int ret;
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
#define NREGS ((int) (sizeof (regname_str) - 1) / regname_len)
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < NREGS)
#include "libunwind_i.h"
-PROTECTED void
+void
unw_destroy_addr_space (unw_addr_space_t as)
{
#ifndef UNW_LOCAL_ONLY
case UNW_INFO_FORMAT_TABLE:
case UNW_INFO_FORMAT_REMOTE_TABLE:
+ case UNW_INFO_FORMAT_ARM_EXIDX:
case UNW_INFO_FORMAT_IP_OFFSET:
#ifdef tdep_search_unwind_table
/* call platform-specific search routine: */
unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
unw_word_t dyn_list_addr, addr, next_addr, gen1, gen2, start_ip, end_ip;
unw_dyn_info_t *di = NULL;
int ret;
in the cache. */
return 0;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
addr = as->dyn_info_list_addr;
if (fetchw (as, a, &addr, &gen, arg) < 0)
#include "libunwind_i.h"
-PROTECTED unw_accessors_t *
+HIDDEN ALIAS(unw_get_accessors) unw_accessors_t *
+unw_get_accessors_int (unw_addr_space_t as);
+
+unw_accessors_t *
unw_get_accessors (unw_addr_space_t as)
{
if (!tdep_init_done)
#include "libunwind_i.h"
-PROTECTED int
+int
unw_get_fpreg (unw_cursor_t *cursor, int regnum, unw_fpreg_t *valp)
{
struct cursor *c = (struct cursor *) cursor;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_get_proc_info_by_ip (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, void *as_arg)
{
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
int ret;
ret = unwi_find_dynamic_proc_info (as, ip, pi, 0, as_arg);
get_proc_name (unw_addr_space_t as, unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp, void *arg)
{
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
unw_proc_info_t pi;
int ret;
return -UNW_ENOINFO;
}
-PROTECTED int
+int
unw_get_proc_name (unw_cursor_t *cursor, char *buf, size_t buf_len,
unw_word_t *offp)
{
int error;
ip = tdep_get_ip (c);
+#if !defined(__ia64__)
if (c->dwarf.use_prev_instr)
--ip;
+#endif
error = get_proc_name (tdep_get_as (c), ip, buf, buf_len, offp,
tdep_get_as_arg (c));
+#if !defined(__ia64__)
if (c->dwarf.use_prev_instr && offp != NULL && error == 0)
*offp += 1;
+#endif
return error;
}
#include "libunwind_i.h"
-PROTECTED int
+int
unw_get_reg (unw_cursor_t *cursor, int regnum, unw_word_t *valp)
{
struct cursor *c = (struct cursor *) cursor;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2014
+ Contributed by Milian Wolff <address@hidden>
+ and Dave Watson <dade.watson@gmail.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "libunwind_i.h"
+
+int
+unw_set_cache_size (unw_addr_space_t as, size_t size, int flag)
+{
+ size_t power = 1;
+ unsigned short log_size = 0;
+
+ if (!tdep_init_done)
+ tdep_init ();
+
+ if (flag != 0)
+ return -1;
+
+ /* Currently not supported for per-thread cache due to memory leak */
+ /* A pthread-key destructor would work, but is not signal safe */
+#if defined(HAVE___THREAD) && HAVE___THREAD
+ return -1;
+#endif
+
+ /* Round up to next power of two, slowly but portably */
+ while(power < size)
+ {
+ power *= 2;
+ log_size++;
+ /* Largest size currently supported by rs_cache */
+ if (log_size >= 15)
+ break;
+ }
+
+#if !defined(__ia64__)
+ if (log_size == as->global_cache.log_size)
+ return 0; /* no change */
+
+ as->global_cache.log_size = log_size;
+#endif
+
+ /* Ensure caches are empty (and initialized). */
+ unw_flush_cache (as, 0, 0);
+#ifdef __ia64__
+ return 0;
+#else
+ /* Synchronously purge cache, to ensure memory is allocated */
+ return dwarf_flush_rs_cache(&as->global_cache);
+#endif
+}
#include "libunwind_i.h"
-PROTECTED int
+int
unw_set_caching_policy (unw_addr_space_t as, unw_caching_policy_t policy)
{
if (!tdep_init_done)
tdep_init ();
-#ifndef HAVE___THREAD
+#if !(defined(HAVE___THREAD) && HAVE___THREAD)
if (policy == UNW_CACHE_PER_THREAD)
policy = UNW_CACHE_GLOBAL;
#endif
#include "libunwind_i.h"
-PROTECTED int
+int
unw_set_fpreg (unw_cursor_t *cursor, int regnum, unw_fpreg_t val)
{
struct cursor *c = (struct cursor *) cursor;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_set_reg (unw_cursor_t *cursor, int regnum, unw_word_t valp)
{
struct cursor *c = (struct cursor *) cursor;
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gdyn-remote.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gset_cache_size.c"
+#endif
HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
-PROTECTED unw_word_t
+unw_word_t
_U_dyn_info_list_addr (void)
{
return (unw_word_t) (uintptr_t) &_U_dyn_info_list;
#include "libunwind_i.h"
-PROTECTED void
+void
unw_flush_cache (unw_addr_space_t as, unw_word_t lo, unw_word_t hi)
{
#if !UNW_TARGET_IA64
#if UNW_DEBUG
-/* Must not be declared HIDDEN/PROTECTED because libunwind.so and
+/* Must not be declared HIDDEN because libunwind.so and
libunwind-PLATFORM.so will both define their own copies of this
variable and we want to use only one or the other when both
libraries are loaded. */
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
/* FIXME for MIPS. */
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
/* Return the address of the 64-bit slot in UC for REG (even for o32,
where registers are 32-bit, the slots are still 64-bit). */
{
char *addr = uc_addr (uc, reg);
- if (reg >= UNW_MIPS_R0 && reg <= UNW_MIPS_R31
+ if (((reg >= UNW_MIPS_R0 && reg <= UNW_MIPS_R31) || reg == UNW_MIPS_PC)
&& tdep_big_endian (unw_local_addr_space)
&& unw_local_addr_space->abi == UNW_MIPS_ABI_O32)
addr += 4;
# error Unsupported ABI
#endif
local_addr_space.addr_size = sizeof (void *);
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local(unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
#include <stdio.h>
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
ip = c->dwarf.ip;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
break;
case UNW_MIPS_PC:
+ if (write)
+ c->dwarf.ip = *valp; /* update the IP cache */
loc = c->dwarf.loc[reg];
break;
#endif /* !UNW_REMOTE_ONLY */
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
return -UNW_EINVAL;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+static int
+mips_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
- unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
+ unw_word_t sc_addr, sp_addr = c->dwarf.cfa;
unw_word_t ra, fp;
int ret;
return 1;
}
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
- ret = unw_handle_signal_frame (cursor);
+ ret = mips_handle_signal_frame (cursor);
if (ret < 0)
/* Not a signal frame, try DWARF-based unwinding. */
ret = dwarf_step (&c->dwarf);
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
/* FIXME: Initialisation for other registers. */
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful
on MIPS. */
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
/* FIXME: Support FP. */
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
size_t len, len1;
char *buf;
struct kinfo_proc *kv;
- int i, pid;
+ unsigned i, pid;
len = 0;
mib[0] = CTL_KERN;
return (pid);
}
-PROTECTED int
+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)
{
free_mem(buf, len1);
return (ret);
}
+
+#ifndef UNW_REMOTE_ONLY
+
+void
+tdep_get_exe_image_path (char *path)
+{
+ int mib[4], error;
+ size_t len;
+
+ len = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = getpid();
+
+ error = sysctl(mib, 4, path, &len, NULL, 0);
+ if (error == -1)
+ path[0] = 0;
+}
+
+#endif
return elf_map_image (ei, path);
}
+
+#ifndef UNW_REMOTE_ONLY
+
+void
+tdep_get_exe_image_path (char *path)
+{
+ path[0] = 0; /* XXX */
+}
+
+#endif
+
#include "libunwind_i.h"
#include "os-linux.h"
-PROTECTED int
+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)
maps_close (&mi);
return rc;
}
+
+#ifndef UNW_REMOTE_ONLY
+
+void
+tdep_get_exe_image_path (char *path)
+{
+ strcpy(path, "/proc/self/exe");
+}
+
+#endif /* !UNW_REMOTE_ONLY */
return 0;
}
-PROTECTED int
+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)
return ret;
}
+
+#ifndef UNW_REMOTE_ONLY
+
+void
+tdep_get_exe_image_path (char *path)
+{
+ path[0] = 0; /* XXX */
+}
+
+#endif
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include <libunwind_i.h>
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include <libunwind_i.h>
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
/* XXX: empty stub. */
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
/* XXX: empty stub. */
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
#ifdef UNW_TARGET_PPC64
- return common_init_ppc64 (c, 1);
+ return common_init_ppc64 (c, use_prev_instr);
#else
- return common_init_ppc32 (c, 1);
+ return common_init_ppc32 (c, use_prev_instr);
#endif
}
+int
+unw_init_local(unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
+}
+
#endif /* !UNW_REMOTE_ONLY */
#include "../ppc32/init.h"
#endif
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include <libunwind_i.h>
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t * cursor)
{
struct cursor *c = (struct cursor *) cursor;
consecutive 32-bit words, so the second 8-byte word needs to be
shifted right by 32 bits (think big-endian) */
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0)
return 0;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include <libunwind_i.h>
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static void *
uc_addr (ucontext_t *uc, int reg)
ppc32_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
return 0;
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
} stack_frame_t;
-PROTECTED int
+int
unw_step (unw_cursor_t * cursor)
{
struct cursor *c = (struct cursor *) cursor;
if (unlikely (ret < 0))
{
- if (likely (!unw_is_signal_frame (cursor)))
+ if (likely (unw_is_signal_frame (cursor) <= 0))
{
/* DWARF unwinding failed. As of 09/26/2006, gcc in 64-bit mode
produces the mandatory level of traceback record in the code, but
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
c->sigcontext_addr = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return (regnum >= UNW_PPC32_F0 && regnum <= UNW_PPC32_F31);
[UNW_PPC32_F31]="FPR31"
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
--- /dev/null
+ .global _UI_setcontext
+
+_UI_setcontext:
+ retq
+
+#ifdef __linux__
+ /* We do not need executable stack. */
+ .section .note.GNU-stack,"",@progbits
+#endif
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include <libunwind_i.h>
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static void *
uc_addr (ucontext_t *uc, int reg)
ucontext_t *uc = arg;
unw_fpreg_t *addr;
- if ((reg - UNW_PPC64_F0) < 0)
+ /* Allow only 32 fregs and 32 vregs */
+ if (!(((unsigned) (reg - UNW_PPC64_F0) < 32)
+ ||((unsigned) (reg - UNW_PPC64_V0) < 32)))
goto badreg;
- if ((unsigned) (reg - UNW_PPC64_V0) >= 32)
- goto badreg;
-
-
addr = uc_addr (uc, reg);
if (!addr)
goto badreg;
#else
local_addr_space.abi = UNW_PPC64_ABI_ELFv1;
#endif
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
return 0;
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
} stack_frame_t;
-PROTECTED int
+int
unw_step (unw_cursor_t * cursor)
{
struct cursor *c = (struct cursor *) cursor;
if (unlikely (ret < 0))
{
- if (likely (!unw_is_signal_frame (cursor)))
+ if (likely (unw_is_signal_frame (cursor) <= 0))
{
/* DWARF unwinding failed. As of 09/26/2006, gcc in 64-bit mode
produces the mandatory level of traceback record in the code, but
{
unw_word_t ip = c->dwarf.ip;
unw_addr_space_t as = c->dwarf.as;
- unw_accessors_t *a = unw_get_accessors (as);
+ unw_accessors_t *a = unw_get_accessors_int (as);
void *arg = c->dwarf.as_arg;
uint32_t toc_save = (as->abi == UNW_PPC64_ABI_ELFv2)? 24 : 40;
int32_t inst;
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
unw_accessors_t *a;
int ret;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
/* Entry-point is stored in the 1st word of the function descriptor.
In case that changes in the future, we'd have to update the line
below and read the word at addr + offset: */
c->sigcontext_addr = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return (regnum >= UNW_PPC64_F0 && regnum <= UNW_PPC64_F31);
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
pid_t pid = ui->pid;
fpregset_t fpreg;
+#if defined(__amd64__)
+ if (1) /* XXXKIB */
+ return -UNW_EBADREG;
+#elif defined(__i386__)
+ if ((unsigned) reg < UNW_X86_ST0 || (unsigned) reg > UNW_X86_ST7)
+ return -UNW_EBADREG;
+#elif defined(__arm__)
+ if ((unsigned) reg < UNW_ARM_F0 || (unsigned) reg > UNW_ARM_F7)
+ return -UNW_EBADREG;
+#else
+#error Fix me
+#endif
if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
return -UNW_EBADREG;
memcpy(&fpreg.fpr_xacc[reg], val, sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t));
+#elif defined(__arm__)
+ memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t));
#else
#error Fix me
#endif
memcpy(val, &fpreg.fpr_xacc[reg], sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t));
+#elif defined(__arm__)
+ memcpy(val, &fpreg.fpr[reg], sizeof(unw_fpreg_t));
#else
#error Fix me
#endif
int write, void *arg)
{
struct UPT_info *ui = arg;
+ int i, end;
+ unw_word_t tmp_val;
+
if (!ui)
return -UNW_EINVAL;
pid_t pid = ui->pid;
- errno = 0;
- if (write)
+ // Some 32-bit archs have to define a 64-bit unw_word_t.
+ // Callers of this function therefore expect a 64-bit
+ // return value, but ptrace only returns a 32-bit value
+ // in such cases.
+ if (sizeof(long) == 4 && sizeof(unw_word_t) == 8)
+ end = 2;
+ else
+ end = 1;
+
+ for (i = 0; i < end; i++)
{
- Debug (16, "mem[%lx] <- %lx\n", (long) addr, (long) *val);
+ unw_word_t tmp_addr = i == 0 ? addr : addr + 4;
+
+ errno = 0;
+ if (write)
+ {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ tmp_val = i == 0 ? *val : *val >> 32;
+#else
+ tmp_val = i == 0 && end == 2 ? *val >> 32 : *val;
+#endif
+
+ Debug (16, "mem[%lx] <- %lx\n", (long) tmp_addr, (long) tmp_val);
#ifdef HAVE_TTRACE
-# warning No support for ttrace() yet.
+# warning No support for ttrace() yet.
#else
- ptrace (PTRACE_POKEDATA, pid, addr, *val);
- if (errno)
- return -UNW_EINVAL;
+ ptrace (PTRACE_POKEDATA, pid, tmp_addr, tmp_val);
+ if (errno)
+ return -UNW_EINVAL;
#endif
- }
- else
- {
+ }
+ else
+ {
#ifdef HAVE_TTRACE
-# warning No support for ttrace() yet.
+# warning No support for ttrace() yet.
#else
- *val = ptrace (PTRACE_PEEKDATA, pid, addr, 0);
- if (errno)
- return -UNW_EINVAL;
+ tmp_val = (unsigned long) ptrace (PTRACE_PEEKDATA, pid, tmp_addr, 0);
+
+ if (i == 0)
+ *val = 0;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ *val |= tmp_val << (i * 32);
+#else
+ *val |= i == 0 && end == 2 ? tmp_val << 32 : tmp_val;
+#endif
+
+ if (errno)
+ return -UNW_EINVAL;
#endif
- Debug (16, "mem[%lx] -> %lx\n", (long) addr, (long) *val);
+ Debug (16, "mem[%lx] -> %lx\n", (long) tmp_addr, (long) tmp_val);
+ }
}
return 0;
}
# include "tdep-ia64/rse.h"
#endif
-#if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
+#if HAVE_DECL_PTRACE_SETREGSET
+#include <sys/uio.h>
+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;
+ struct iovec loc;
+
+#if UNW_DEBUG
+ Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n",
+ unw_regname(reg), (unsigned) reg, (long) val, write);
+
+ if (write)
+ Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val);
+#endif
+ if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
+ {
+ errno = EINVAL;
+ goto badreg;
+ }
+
+ loc.iov_base = ®s;
+ loc.iov_len = sizeof(regs);
+
+ r = (char *)®s + _UPT_reg_offset[reg];
+ if (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &loc) == -1)
+ goto badreg;
+ if (write) {
+ memcpy(r, val, sizeof(unw_word_t));
+ if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &loc) == -1)
+ goto badreg;
+ } else
+ memcpy(val, r, sizeof(unw_word_t));
+ return 0;
+
+badreg:
+ Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno));
+ return -UNW_EBADREG;
+}
+#elif HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE
int
_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val,
int write, void *arg)
#include "_UPT_internal.h"
-PROTECTED unw_accessors_t _UPT_accessors =
+unw_accessors_t _UPT_accessors =
{
.find_proc_info = _UPT_find_proc_info,
.put_unwind_info = _UPT_put_unwind_info,
ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache,
pi, need_unwind_info, arg);
+ if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1)
+ ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi,
+ need_unwind_info, arg);
+
#if UNW_TARGET_ARM
if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1)
ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi,
need_unwind_info, arg);
#endif
- if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1)
- ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi,
- need_unwind_info, arg);
-
return ret;
}
#endif
#elif defined(UNW_TARGET_ARM)
+#if defined(__linux__) || defined(__FreeBSD__)
[UNW_ARM_R0] = 0x00,
[UNW_ARM_R1] = 0x04,
[UNW_ARM_R2] = 0x08,
[UNW_ARM_R13] = 0x34,
[UNW_ARM_R14] = 0x38,
[UNW_ARM_R15] = 0x3c,
+#else
+#error Fix me
+#endif
#elif defined(UNW_TARGET_MIPS)
+ [UNW_MIPS_R0] = 0,
+ [UNW_MIPS_R1] = 1,
+ [UNW_MIPS_R2] = 2,
+ [UNW_MIPS_R3] = 3,
+ [UNW_MIPS_R4] = 4,
+ [UNW_MIPS_R5] = 5,
+ [UNW_MIPS_R6] = 6,
+ [UNW_MIPS_R7] = 7,
+ [UNW_MIPS_R8] = 8,
+ [UNW_MIPS_R9] = 9,
+ [UNW_MIPS_R10] = 10,
+ [UNW_MIPS_R11] = 11,
+ [UNW_MIPS_R12] = 12,
+ [UNW_MIPS_R13] = 13,
+ [UNW_MIPS_R14] = 14,
+ [UNW_MIPS_R15] = 15,
+ [UNW_MIPS_R16] = 16,
+ [UNW_MIPS_R17] = 17,
+ [UNW_MIPS_R18] = 18,
+ [UNW_MIPS_R19] = 19,
+ [UNW_MIPS_R20] = 20,
+ [UNW_MIPS_R21] = 21,
+ [UNW_MIPS_R22] = 22,
+ [UNW_MIPS_R23] = 23,
+ [UNW_MIPS_R24] = 24,
+ [UNW_MIPS_R25] = 25,
+ [UNW_MIPS_R26] = 26,
+ [UNW_MIPS_R27] = 27,
+ [UNW_MIPS_R28] = 28,
+ [UNW_MIPS_R29] = 29,
+ [UNW_MIPS_R30] = 30,
+ [UNW_MIPS_R31] = 31,
+ [UNW_MIPS_PC] = 64,
#elif defined(UNW_TARGET_SH)
#elif defined(UNW_TARGET_AARCH64)
[UNW_AARCH64_X0] = 0x00,
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
sh_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+static int
+unw_init_local (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, unw_context_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
3e: 09 00 nop
*/
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
ip = c->dwarf.ip;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
switch (reg)
{
+ case UNW_SH_PC:
+ if (write)
+ c->dwarf.ip = *valp; /* update the IP cache */
case UNW_SH_R0:
case UNW_SH_R1:
case UNW_SH_R2:
case UNW_SH_R12:
case UNW_SH_R13:
case UNW_SH_R14:
- case UNW_SH_PC:
case UNW_SH_PR:
loc = c->dwarf.loc[reg];
break;
}
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+static int
+sh_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
return 1;
}
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
Debug (1, "(cursor=%p)\n", c);
- if (unw_is_signal_frame (cursor))
- return unw_handle_signal_frame (cursor);
+ if (unw_is_signal_frame (cursor) > 0)
+ return sh_handle_signal_frame (cursor);
ret = dwarf_step (&c->dwarf);
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
c->sigcontext_pc = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
/* FIXME: Support FP. */
[UNW_SH_PR] = "pr",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname) && regname[reg] != NULL)
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#include "unwind_i.h"
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
/* Return the address of the 64-bit slot in UC for REG (even for o32,
where registers are 32-bit, the slots are still 64-bit). */
local_addr_space.abi = UNW_TILEGX_ABI_N64;
local_addr_space.addr_size = sizeof (void *);
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
((unsigned long)TREG_SYSCALL_NR << 31) )
#define SWINT1 0x286b180051485000ULL
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor*) cursor;
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
ip = c->dwarf.ip;
}
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+HIDDEN int
+tilegx_handle_signal_frame (unw_cursor_t *cursor)
{
int i;
struct cursor *c = (struct cursor *) cursor;
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
}
if (write)
- return dwarf_put (&c->dwarf, loc, *valp);
+ {
+ if (ci->dwarf.use_prev_instr == 0) {
+ if (reg == UNW_TILEGX_PC)
+ c->dwarf.ip = *valp; /* update the IP cache */
+ }
+ else {
+ if (reg == UNW_TILEGX_R55)
+ c->dwarf.ip = *valp; /* update the IP cache */
+ }
+ return dwarf_put (&c->dwarf, loc, *valp);
+ }
else
return dwarf_get (&c->dwarf, loc, valp);
}
}
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
c, c->dwarf.ip, c->dwarf.cfa);
/* Special handling the singal frame. */
- if (unw_is_signal_frame (cursor))
- return unw_handle_signal_frame (cursor);
+ if (unw_is_signal_frame (cursor) > 0)
+ return tilegx_handle_signal_frame (cursor);
/* Try DWARF-based unwinding... */
ret = dwarf_step (&c->dwarf);
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
return ret;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
/* TILEGX has no FP. */
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return 0;
"pc", "cfa"
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
#include "unwind-internal.h"
-PROTECTED _Unwind_Reason_Code
+_Unwind_Reason_Code
_Unwind_Backtrace (_Unwind_Trace_Fn trace, void *trace_parameter)
{
struct _Unwind_Context context;
#include "unwind-internal.h"
-PROTECTED void
+void
_Unwind_DeleteException (struct _Unwind_Exception *exception_object)
{
_Unwind_Exception_Cleanup_Fn cleanup = exception_object->exception_cleanup;
#include "unwind-internal.h"
-PROTECTED void *
+void *
_Unwind_FindEnclosingFunction (void *ip)
{
unw_proc_info_t pi;
#include "unwind-internal.h"
-PROTECTED _Unwind_Reason_Code
+_Unwind_Reason_Code
_Unwind_ForcedUnwind (struct _Unwind_Exception *exception_object,
_Unwind_Stop_Fn stop, void *stop_parameter)
{
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetBSP (struct _Unwind_Context *context)
{
#ifdef UNW_TARGET_IA64
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetCFA (struct _Unwind_Context *context)
{
unw_word_t val;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetDataRelBase (struct _Unwind_Context *context)
{
unw_proc_info_t pi;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetGR (struct _Unwind_Context *context, int index)
{
unw_word_t val;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetIP (struct _Unwind_Context *context)
{
unw_word_t val;
/* gcc/unwind-dw2.c: Retrieve the return address and flag whether that IP is
before or after first not yet fully executed instruction. */
-PROTECTED unsigned long
+unsigned long
_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
{
unw_word_t val;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
{
unw_proc_info_t pi;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetRegionStart (struct _Unwind_Context *context)
{
unw_proc_info_t pi;
#include "unwind-internal.h"
-PROTECTED unsigned long
+unsigned long
_Unwind_GetTextRelBase (struct _Unwind_Context *context)
{
return 0;
#include "unwind-internal.h"
-PROTECTED _Unwind_Reason_Code
+_Unwind_Reason_Code
_Unwind_RaiseException (struct _Unwind_Exception *exception_object)
{
uint64_t exception_class = exception_object->exception_class;
#include "unwind-internal.h"
-PROTECTED void
+void
_Unwind_Resume (struct _Unwind_Exception *exception_object)
{
struct _Unwind_Context context;
#include "unwind-internal.h"
-PROTECTED _Unwind_Reason_Code
+_Unwind_Reason_Code
_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exception_object)
{
struct _Unwind_Context context;
#include "dwarf_i.h"
#endif
-PROTECTED void
+void
_Unwind_SetGR (struct _Unwind_Context *context, int index,
unsigned long new_value)
{
#include "unwind-internal.h"
-PROTECTED void
+void
_Unwind_SetIP (struct _Unwind_Context *context, unsigned long new_value)
{
unw_set_reg (&context->cursor, UNW_REG_IP, new_value);
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#endif
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
# ifdef UNW_LOCAL_ONLY
x86_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as_arg = c;
c->uc = uc;
c->validate = 0;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
/* Check if EIP points at sigreturn() sequence. It can be:
return (ret);
}
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+HIDDEN int
+x86_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
+#include <sys/syscall.h>
+
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
/* Check if EIP points at sigreturn() sequence. On Linux, this is:
__restore_rt:
0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
0xcd 0x80 int 0x80
- 0x00
+ 0x00
if SA_SIGINFO is specified.
*/
return ret;
}
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+HIDDEN int
+x86_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
- sigreturn (sc);
+ x86_sigreturn (sc);
}
else
{
}
return -UNW_EINVAL;
}
+
+/* sigreturn() is a no-op on x86 glibc. */
+HIDDEN void
+x86_sigreturn (unw_cursor_t *cursor)
+{
+ struct cursor *c = (struct cursor *) cursor;
+ struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
+ mcontext_t *sc_mcontext = &((ucontext_t*)sc)->uc_mcontext;
+ /* Copy in saved uc - all preserved regs are at the start of sigcontext */
+ memcpy(sc_mcontext, &c->uc->uc_mcontext,
+ DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t));
+
+ Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
+ (unsigned long long) c->dwarf.ip, sc);
+ __asm__ __volatile__ ("mov %0, %%esp;"
+ "mov %1, %%eax;"
+ "syscall"
+ :: "r"(sc), "i"(SYS_rt_sigreturn)
+ : "memory");
+ abort();
+}
#endif
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
(*access_reg) (as, reg, &val, 1, arg);
}
}
+
+ if (c->dwarf.args_size)
+ {
+ if (tdep_access_reg (c, UNW_X86_ESP, &val, 0) >= 0)
+ {
+ val += c->dwarf.args_size;
+ (*access_reg) (as, UNW_X86_ESP, &val, 1, arg);
+ }
+ }
return 0;
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
#include "offsets.h"
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
- if (unw_is_signal_frame (cursor))
+ if (unw_is_signal_frame (cursor) > 0)
{
- ret = unw_handle_signal_frame(cursor);
+ ret = x86_handle_signal_frame(cursor);
if (ret < 0)
{
Debug (2, "returning 0\n");
c->dwarf.loc[EIP] = eip_loc;
c->dwarf.use_prev_instr = 1;
}
- c->dwarf.ret_addr_column = EIP;
if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP]))
{
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
c->sigcontext_addr = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = 0;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
return ((regnum >= UNW_X86_ST0 && regnum <= UNW_X86_ST7)
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
#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)
+#define x86_sigreturn UNW_OBJ(sigreturn)
extern void x86_local_addr_space_init (void);
extern int x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
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);
+extern void x86_sigreturn (unw_cursor_t *cursor);
+#define x86_handle_signal_frame UNW_OBJ(handle_signal_frame)
+extern int x86_handle_signal_frame(unw_cursor_t *cursor);
+
#endif /* unwind_i_h */
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_apply_reg_state (unw_cursor_t *cursor,
+ void *reg_states_data)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_apply_reg_state (&c->dwarf, (dwarf_reg_state_t *)reg_states_data);
+}
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#endif
-PROTECTED unw_addr_space_t
+unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
#include "unwind_i.h"
-PROTECTED int
+int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
#include <config.h>
#endif
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include "unwind_i.h"
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
-PROTECTED unw_addr_space_t unw_local_addr_space;
+unw_addr_space_t unw_local_addr_space;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
-PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
+unw_addr_space_t unw_local_addr_space = &local_addr_space;
HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
#define PAGE_SIZE 4096
#define PAGE_START(a) ((a) & ~(PAGE_SIZE-1))
+static int mem_validate_pipe[2] = {-1, -1};
+
+static inline void
+open_pipe (void)
+{
+ /* ignore errors for closing invalid fd's */
+ close (mem_validate_pipe[0]);
+ close (mem_validate_pipe[1]);
+
+ pipe2 (mem_validate_pipe, O_CLOEXEC | O_NONBLOCK);
+}
+
+ALWAYS_INLINE
+static int
+write_validate (void *addr)
+{
+ int ret = -1;
+ ssize_t bytes = 0;
+
+ do
+ {
+ char buf;
+ bytes = read (mem_validate_pipe[0], &buf, 1);
+ }
+ while ( errno == EINTR );
+
+ int valid_read = (bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK);
+ if (!valid_read)
+ {
+ // re-open closed pipe
+ open_pipe ();
+ }
+
+ do
+ {
+ /* use syscall insteadof write() so that ASAN does not complain */
+ ret = syscall (SYS_write, mem_validate_pipe[1], addr, 1);
+ }
+ while ( errno == EINTR );
+
+ return ret;
+}
+
static int (*mem_validate_func) (void *addr, size_t len);
static int msync_validate (void *addr, size_t len)
{
- return msync (addr, len, MS_ASYNC);
+ if (msync (addr, len, MS_ASYNC) != 0)
+ {
+ return -1;
+ }
+
+ return write_validate (addr);
}
#ifdef HAVE_MINCORE
static int mincore_validate (void *addr, size_t len)
{
unsigned char mvec[2]; /* Unaligned access may cross page boundary */
- return mincore (addr, len, mvec);
+ size_t i;
+
+ /* mincore could fail with EAGAIN but we conservatively return -1
+ instead of looping. */
+ if (mincore (addr, len, mvec) != 0)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < (len + PAGE_SIZE - 1) / PAGE_SIZE; i++)
+ {
+ if (!(mvec[i] & 1)) return -1;
+ }
+
+ return write_validate (addr);
}
#endif
HIDDEN void
tdep_init_mem_validate (void)
{
+ open_pipe ();
+
#ifdef HAVE_MINCORE
unsigned char present = 1;
- if (mincore (&present, 1, &present) == 0)
+ unw_word_t addr = PAGE_START((unw_word_t)&present);
+ unsigned char mvec[1];
+ int ret;
+ while ((ret = mincore ((void*)addr, PAGE_SIZE, mvec)) == -1 &&
+ errno == EAGAIN) {}
+ if (ret == 0 && (mvec[0] & 1))
{
Debug(1, "using mincore to validate memory\n");
mem_validate_func = mincore_validate;
x86_64_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
- local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+ local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY;
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
#ifdef UNW_REMOTE_ONLY
-PROTECTED int
+int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
return -UNW_EINVAL;
#else /* !UNW_REMOTE_ONLY */
-PROTECTED int
-unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+static int
+unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr)
{
struct cursor *c = (struct cursor *) cursor;
c->dwarf.as_arg = c;
c->uc = uc;
c->validate = 0;
- return common_init (c, 1);
+ return common_init (c, use_prev_instr);
+}
+
+int
+unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
+{
+ return unw_init_local_common(cursor, uc, 1);
+}
+
+int
+unw_init_local2 (unw_cursor_t *cursor, ucontext_t *uc, int flag)
+{
+ if (!flag)
+ {
+ return unw_init_local_common(cursor, uc, 1);
+ }
+ else if (flag == UNW_INIT_SIGNAL_FRAME)
+ {
+ return unw_init_local_common(cursor, uc, 0);
+ }
+ else
+ {
+ return -UNW_EINVAL;
+ }
}
#endif /* !UNW_REMOTE_ONLY */
#include "init.h"
#include "unwind_i.h"
-PROTECTED int
+int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
#include "unwind_i.h"
#include "ucontext_i.h"
-PROTECTED int
+int
unw_is_signal_frame (unw_cursor_t *cursor)
{
/* XXXKIB */
int ret;
as = c->dwarf.as;
- a = unw_get_accessors (as);
+ a = unw_get_accessors_int (as);
arg = c->dwarf.as_arg;
/* Check if RIP points at sigreturn sequence.
return (X86_64_SCF_NONE);
}
-PROTECTED int
-unw_handle_signal_frame (unw_cursor_t *cursor)
+HIDDEN int
+x86_64_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t ucontext;
ucontext_t *uc = (ucontext_t *)(c->sigcontext_addr +
offsetof(struct sigframe, sf_uc));
+ uc->uc_mcontext.mc_r8 = c->uc->uc_mcontext.mc_r8;
+ uc->uc_mcontext.mc_r9 = c->uc->uc_mcontext.mc_r9;
+ uc->uc_mcontext.mc_r10 = c->uc->uc_mcontext.mc_r10;
+ uc->uc_mcontext.mc_r11 = c->uc->uc_mcontext.mc_r11;
+ uc->uc_mcontext.mc_r12 = c->uc->uc_mcontext.mc_r12;
+ uc->uc_mcontext.mc_r13 = c->uc->uc_mcontext.mc_r13;
+ uc->uc_mcontext.mc_r14 = c->uc->uc_mcontext.mc_r14;
+ uc->uc_mcontext.mc_r15 = c->uc->uc_mcontext.mc_r15;
+ uc->uc_mcontext.mc_rdi = c->uc->uc_mcontext.mc_rdi;
+ uc->uc_mcontext.mc_rsi = c->uc->uc_mcontext.mc_rsi;
+ uc->uc_mcontext.mc_rbp = c->uc->uc_mcontext.mc_rbp;
+ uc->uc_mcontext.mc_rbx = c->uc->uc_mcontext.mc_rbx;
+ uc->uc_mcontext.mc_rdx = c->uc->uc_mcontext.mc_rdx;
+ uc->uc_mcontext.mc_rax = c->uc->uc_mcontext.mc_rax;
+ uc->uc_mcontext.mc_rcx = c->uc->uc_mcontext.mc_rcx;
+ uc->uc_mcontext.mc_rsp = c->uc->uc_mcontext.mc_rsp;
+ uc->uc_mcontext.mc_rip = c->uc->uc_mcontext.mc_rip;
+
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, uc);
sigreturn(uc);
dw->ip, dw->cfa, c->sigcontext_format);
}
-HIDDEN void
-tdep_cache_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
+HIDDEN int
+tdep_cache_frame (struct dwarf_cursor *dw)
{
struct cursor *c = (struct cursor *) dw;
- rs->signal_frame = c->sigcontext_format;
Debug(5, "cache frame ip=0x%lx cfa=0x%lx format=%d\n",
dw->ip, dw->cfa, c->sigcontext_format);
+ return c->sigcontext_format;
}
HIDDEN void
-tdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
+tdep_reuse_frame (struct dwarf_cursor *dw, int frame)
{
struct cursor *c = (struct cursor *) dw;
- c->sigcontext_format = rs->signal_frame;
+ c->sigcontext_format = frame;
if (c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME)
{
c->frame_info.frame_type = UNW_X86_64_FRAME_SIGRETURN;
c->frame_info.cfa_reg_offset = 0;
c->sigcontext_addr = dw->cfa;
}
- else
- c->sigcontext_addr = 0;
Debug(5, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx offset=%+d\n",
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr,
? c->frame_info.cfa_reg_offset : 0));
}
-PROTECTED int
+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)
+HIDDEN int
+x86_64_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
{
struct cursor *c = (struct cursor *) cursor;
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
+ mcontext_t *sc_mcontext = &((ucontext_t*)sc)->uc_mcontext;
+ /* Copy in saved uc - all preserved regs are at the start of sigcontext */
+ memcpy(sc_mcontext, &c->uc->uc_mcontext,
+ DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t));
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
(unsigned long long) c->dwarf.ip, sc);
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (c) 2002-2003 Hewlett-Packard Development Company, L.P.
+ 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"
+
+int
+unw_reg_states_iterate (unw_cursor_t *cursor,
+ unw_reg_states_callback cb, void *token)
+{
+ struct cursor *c = (struct cursor *) cursor;
+
+ return dwarf_reg_states_iterate (&c->dwarf, cb, token);
+}
at least. */
dwarf_make_proc_info (&c->dwarf);
- if (unlikely (c->sigcontext_format != X86_64_SCF_NONE))
+ if (unlikely (c->sigcontext_addr != X86_64_SCF_NONE))
{
x86_64_sigreturn(cursor);
abort();
(*access_reg) (as, reg, &val, 1, arg);
}
}
+
+ if (c->dwarf.args_size)
+ {
+ if (tdep_access_reg (c, UNW_X86_64_RSP, &val, 0) >= 0)
+ {
+ val += c->dwarf.args_size;
+ (*access_reg) (as, UNW_X86_64_RSP, &val, 1, arg);
+ }
+ }
return 0;
}
-PROTECTED int
+int
unw_resume (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
Debug (4, "ip=0x%lx cfa=0x%lx type %d cfa [where=%d val=%ld] cfaoff=%ld"
" ra=0x%lx rbp [where=%d val=%ld @0x%lx] rsp [where=%d val=%ld @0x%lx]\n",
d->ip, d->cfa, f->frame_type,
- rs->reg[DWARF_CFA_REG_COLUMN].where,
- rs->reg[DWARF_CFA_REG_COLUMN].val,
- rs->reg[DWARF_CFA_OFF_COLUMN].val,
- DWARF_GET_LOC(d->loc[d->ret_addr_column]),
- rs->reg[RBP].where, rs->reg[RBP].val, DWARF_GET_LOC(d->loc[RBP]),
- rs->reg[RSP].where, rs->reg[RSP].val, DWARF_GET_LOC(d->loc[RSP]));
+ rs->reg.where[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_REG_COLUMN],
+ rs->reg.val[DWARF_CFA_OFF_COLUMN],
+ DWARF_GET_LOC(d->loc[rs->ret_addr_column]),
+ rs->reg.where[RBP], rs->reg.val[RBP], DWARF_GET_LOC(d->loc[RBP]),
+ rs->reg.where[RSP], rs->reg.val[RSP], DWARF_GET_LOC(d->loc[RSP]));
+
+ if (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR &&
+ rs->reg.where[RBP] == DWARF_WHERE_EXPR) {
+ /* Check for GCC generated alignment frame for rsp. A simple
+ * def_cfa_expr that loads a constant offset from rbp, where the
+ * addres of the rip was pushed on the stack */
+ unw_word_t cfa_addr = rs->reg.val[DWARF_CFA_REG_COLUMN];
+ unw_word_t rbp_addr = rs->reg.val[RBP];
+ unw_word_t cfa_offset;
+
+ int ret = dwarf_stack_aligned(d, cfa_addr, rbp_addr, &cfa_offset);
+ if (ret) {
+ f->frame_type = UNW_X86_64_FRAME_ALIGNED;
+ f->cfa_reg_offset = cfa_offset;
+ f->cfa_reg_rsp = 0;
+ }
+ }
/* A standard frame is defined as:
- CFA is register-relative offset off RBP or RSP;
- RBP is unsaved or saved at CFA+offset, offset != -1;
- RSP is unsaved or saved at CFA+offset, offset != -1. */
if (f->frame_type == UNW_X86_64_FRAME_OTHER
- && (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
- && (rs->reg[DWARF_CFA_REG_COLUMN].val == RBP
- || rs->reg[DWARF_CFA_REG_COLUMN].val == RSP)
- && labs((long) rs->reg[DWARF_CFA_OFF_COLUMN].val) < (1 << 29)
- && DWARF_GET_LOC(d->loc[d->ret_addr_column]) == d->cfa-8
- && (rs->reg[RBP].where == DWARF_WHERE_UNDEF
- || rs->reg[RBP].where == DWARF_WHERE_SAME
- || (rs->reg[RBP].where == DWARF_WHERE_CFAREL
- && labs((long) rs->reg[RBP].val) < (1 << 14)
- && rs->reg[RBP].val+1 != 0))
- && (rs->reg[RSP].where == DWARF_WHERE_UNDEF
- || rs->reg[RSP].where == DWARF_WHERE_SAME
- || (rs->reg[RSP].where == DWARF_WHERE_CFAREL
- && labs((long) rs->reg[RSP].val) < (1 << 14)
- && rs->reg[RSP].val+1 != 0)))
+ && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
+ && (rs->reg.val[DWARF_CFA_REG_COLUMN] == RBP
+ || rs->reg.val[DWARF_CFA_REG_COLUMN] == RSP)
+ && labs((long) rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 28)
+ && DWARF_GET_LOC(d->loc[rs->ret_addr_column]) == d->cfa-8
+ && (rs->reg.where[RBP] == DWARF_WHERE_UNDEF
+ || rs->reg.where[RBP] == DWARF_WHERE_SAME
+ || (rs->reg.where[RBP] == DWARF_WHERE_CFAREL
+ && labs((long) rs->reg.val[RBP]) < (1 << 14)
+ && rs->reg.val[RBP]+1 != 0))
+ && (rs->reg.where[RSP] == DWARF_WHERE_UNDEF
+ || rs->reg.where[RSP] == DWARF_WHERE_SAME
+ || (rs->reg.where[RSP] == DWARF_WHERE_CFAREL
+ && labs((long) rs->reg.val[RSP]) < (1 << 14)
+ && rs->reg.val[RSP]+1 != 0)))
{
/* Save information for a standard frame. */
f->frame_type = UNW_X86_64_FRAME_STANDARD;
- f->cfa_reg_rsp = (rs->reg[DWARF_CFA_REG_COLUMN].val == RSP);
- f->cfa_reg_offset = rs->reg[DWARF_CFA_OFF_COLUMN].val;
- if (rs->reg[RBP].where == DWARF_WHERE_CFAREL)
- f->rbp_cfa_offset = rs->reg[RBP].val;
- if (rs->reg[RSP].where == DWARF_WHERE_CFAREL)
- f->rsp_cfa_offset = rs->reg[RSP].val;
+ f->cfa_reg_rsp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == RSP);
+ f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN];
+ if (rs->reg.where[RBP] == DWARF_WHERE_CFAREL)
+ f->rbp_cfa_offset = rs->reg.val[RBP];
+ if (rs->reg.where[RSP] == DWARF_WHERE_CFAREL)
+ f->rsp_cfa_offset = rs->reg.val[RSP];
Debug (4, " standard frame\n");
}
Debug (4, " sigreturn frame\n");
}
+ else if (f->frame_type == UNW_X86_64_FRAME_ALIGNED) {
+ Debug (4, " aligned frame, offset %li\n", f->cfa_reg_offset);
+ }
+
/* PLT and guessed RBP-walked frames are handled in unw_step(). */
else
Debug (4, " unusual frame\n");
unw_accessors_t *a;
int ret;
- a = unw_get_accessors (c->as);
+ a = unw_get_accessors_int (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;
return ret;
}
-PROTECTED int
+int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
{
/* x86_64 ABI specifies that end of call-chain is marked with a
NULL RBP or undefined return address */
- if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP])
- || DWARF_IS_NULL_LOC(c->dwarf.loc[c->dwarf.ret_addr_column]))
+ if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
c->dwarf.ip = 0;
ret = 0;
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
- if (unw_is_signal_frame (cursor))
+ if (unw_is_signal_frame (cursor) > 0)
{
- ret = unw_handle_signal_frame(cursor);
+ ret = x86_64_handle_signal_frame(cursor);
if (ret < 0)
{
Debug (2, "returning 0\n");
c->dwarf.use_prev_instr = 1;
}
- c->dwarf.ret_addr_column = RIP;
-
if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
ret = 0;
d->use_prev_instr = 0;
break;
+ case UNW_X86_64_FRAME_ALIGNED:
+ /* Address of RIP was pushed on the stack via a simple
+ * def_cfa_expr - result stack offset stored in cfa_reg_offset */
+ cfa = (f->cfa_reg_rsp ? rsp : rbp) + f->cfa_reg_offset;
+ ACCESS_MEM_FAST(ret, c->validate, d, cfa, cfa);
+ if (likely(ret >= 0))
+ ACCESS_MEM_FAST(ret, c->validate, d, cfa - 8, rip);
+ if (likely(ret >= 0))
+ ACCESS_MEM_FAST(ret, c->validate, d, rbp, rbp);
+
+ /* Don't bother reading RSP from DWARF, CFA becomes new RSP. */
+ rsp = cfa;
+
+ /* Next frame needs to back up for unwind info lookup. */
+ d->use_prev_instr = 1;
+
+ break;
+
default:
/* We cannot trace through this frame, give up and tell the
caller we had to stop. Data collected so far may still be
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gapply_reg_state.c"
+#endif
--- /dev/null
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Greg_states_iterate.c"
+#endif
c->sigcontext_addr = 0;
c->dwarf.args_size = 0;
- c->dwarf.ret_addr_column = RIP;
c->dwarf.stash_frames = 0;
c->dwarf.use_prev_instr = use_prev_instr;
c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0;
c->dwarf.prev_rs = 0;
+ c->dwarf.eh_valid_mask = 0;
return 0;
}
#include "libunwind_i.h"
-PROTECTED int
+int
unw_is_fpreg (int regnum)
{
#if 0
"RIP",
};
-PROTECTED const char *
+const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "ucontext_i.h"
-#if defined __linux__
-#include <asm/unistd.h>
-#define SIG_SETMASK 2
-#define SIGSET_BYTE_SIZE (64/8)
-#elif defined __FreeBSD__
-#include <sys/syscall.h>
-#endif
/* int _Ux86_64_setcontext (const ucontext_t *ucp)
Restores the machine context provided.
Unlike the libc implementation, doesn't clobber %rax
-
+
*/
.global _Ux86_64_setcontext
.type _Ux86_64_setcontext, @function
_Ux86_64_setcontext:
#if defined __linux__
- /* restore signal mask
- sigprocmask(SIG_SETMASK, ucp->uc_sigmask, NULL, sizeof(sigset_t)) */
- push %rdi
- mov $__NR_rt_sigprocmask, %rax
- lea UC_SIGMASK(%rdi), %rsi
- mov $SIG_SETMASK, %rdi
- xor %rdx, %rdx
- mov $SIGSET_BYTE_SIZE, %r10
- syscall
- pop %rdi
-
/* restore fp state */
mov UC_MCONTEXT_FPREGS_PTR(%rdi),%r8
fldenv (%r8)
ldmxcsr FPREGS_OFFSET_MXCSR(%r8)
#elif defined __FreeBSD__
- /* restore signal mask */
- pushq %rdi
- xorl %edx,%edx
- leaq UC_SIGMASK(%rdi),%rsi
- movl $3,%edi/* SIG_SETMASK */
- movl $SYS_sigprocmask,%eax
- movq %rcx,%r10
- syscall
- popq %rdi
-
/* restore fp state */
cmpq $UC_MCONTEXT_FPOWNED_FPU,UC_MCONTEXT_OWNEDFP(%rdi)
jne 1f
extern void *x86_64_r_uc_addr (ucontext_t *uc, int reg);
extern NORETURN void x86_64_sigreturn (unw_cursor_t *cursor);
+#define x86_64_handle_signal_frame UNW_OBJ(handle_signal_frame)
+extern int x86_64_handle_signal_frame(unw_cursor_t *cursor);
#endif /* unwind_i_h */
measure_init ();
+ doit ("default ");
+
unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
doit ("no cache ");
measure_init ();
+ doit ("default ");
+
unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
doit ("no cache ");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ucontext.h>
#include <unistd.h>
#include <libunwind.h>
#endif
{
unw_word_t ip;
- sigset_t mask, oldmask;
+ sigset_t mask;
unw_context_t uc;
unw_cursor_t c;
char foo;
int ret;
+ // The test rely on SIGUSR2 mask to be cleared when the handler returns.
+ // For local context from the signal handler, there doesn't seem to be a way
+ // currently to set it so just clear the whole struct to make sure the signal mask is cleared.
+ // This should probably be fixed to avoid signal mask being set to random values
+ // by `unw_resume` if the context was not pre-zeroed.,
+ // Using the signal ucontext direction should also work automatically but currently doesn't
+ // on ARM/AArch64 (or any other archs that doesn't have a proper sigreturn implementation)
+ memset(&uc, 0x0, sizeof(uc));
#if UNW_TARGET_IA64
if (verbose)
sigemptyset (&mask);
sigaddset (&mask, SIGUSR2);
- sigprocmask (SIG_BLOCK, &mask, &oldmask);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
kill (getpid (), SIGUSR2); /* pend SIGUSR2 */
signal (SIGUSR1, SIG_IGN);
if ((ret = unw_getcontext (&uc)) < 0)
panic ("unw_getcontext() failed: ret=%d\n", ret);
-#if UNW_TARGET_X86_64
- /* unw_getcontext() doesn't save signal mask to avoid a syscall */
- uc.uc_sigmask = oldmask;
-#endif
if ((ret = unw_init_local (&c, &uc)) < 0)
panic ("unw_init_local() failed: ret=%d\n", ret);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ucontext.h>
#include <unistd.h>
#include <libunwind.h>
printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
#endif
#elif defined UNW_TARGET_ARM
+#if defined __linux__
printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_pc);
+#elif defined __FreeBSD__
+ printf (" @ %lx", (unsigned long) uc->uc_mcontext.__gregs[_REG_PC]);
+#endif
#endif
printf ("\n");
}
--- /dev/null
+#include <stdio.h>
+
+/* To prevent inlining and optimizing away */
+int foo(volatile int* f) {
+ return *f;
+}
--- /dev/null
+#include "libunwind.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <assert.h>
+
+int stepper(unw_cursor_t* c) {
+ int steps = 0;
+ int ret = 1;
+ while (ret) {
+
+ ret = unw_step(c);
+ if (!ret) {
+ break;
+ }
+ steps++;
+ }
+ return steps;
+}
+
+/* Verify that we can step from both ucontext, and from getcontext()
+ * roughly the same. This tests that the IP from ucontext is used
+ * correctly (see impl of unw_init_local2) */
+void handler(int num, siginfo_t* info, void* ucontext) {
+ unw_cursor_t c;
+ unw_context_t context;
+ unw_getcontext(&context);
+ int ret = unw_init_local2(&c, ucontext, UNW_INIT_SIGNAL_FRAME);
+ assert(!ret);
+ int ucontext_steps = stepper(&c);
+
+ ret = unw_init_local(&c, &context);
+ (void)ret;
+ assert(!ret);
+ int getcontext_steps = stepper(&c);
+ if (ucontext_steps == getcontext_steps - 2) {
+ exit(0);
+ }
+ printf("unw_getcontext steps was %i, ucontext steps was %i, should be %i\n",
+ getcontext_steps, ucontext_steps, getcontext_steps - 2);
+ exit(-1);
+}
+
+int foo(volatile int* f);
+
+int main(){
+ struct sigaction a;
+ memset(&a, 0, sizeof(struct sigaction));
+ a.sa_sigaction = &handler;
+ a.sa_flags = SA_SIGINFO;
+ sigaction(SIGSEGV, &a, NULL);
+
+ foo(NULL);
+ return 0;
+}
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003-2004 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Copyright (c) 2003 Hewlett-Packard Co.
+
+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 "compiler.h"
+
+#include <libunwind.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/resource.h>
+#include <sys/mman.h>
+
+#define panic(args...) \
+ { fprintf (stderr, args); exit (-1); }
+
+void * stack_start;
+
+#define PAGE_SIZE 4096
+
+void do_backtrace (void)
+{
+ void* buffer[1024];
+ int size = 1024;
+ mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)),
+ PAGE_SIZE, PROT_NONE);
+
+ unw_cursor_t cursor;
+ unw_word_t ip, sp;
+ unw_context_t uc;
+ int ret;
+ int steps = 0;
+
+ unw_getcontext (&uc);
+ if (unw_init_local (&cursor, &uc) < 0)
+ panic ("unw_init_local failed!\n");
+
+ do
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ unw_get_reg (&cursor, UNW_REG_SP, &sp);
+
+ ret = unw_step (&cursor);
+ if (ret < 0)
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ }
+ steps ++;
+ }
+ while (ret > 0);
+
+ if (steps < 5)
+ {
+ exit(-1);
+ }
+
+ mprotect((void*)((uintptr_t)stack_start & ~(PAGE_SIZE - 1)),
+ PAGE_SIZE, PROT_READ|PROT_WRITE);
+}
+
+void consume_and_run (int depth)
+{
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ char string[1024];
+
+ sprintf (string, "hello %p %p\n", &cursor, &uc);
+ if (depth == 0) {
+ do_backtrace();
+ } else {
+ consume_and_run(depth - 1);
+ }
+}
+
+int
+main (int argc, char **argv UNUSED)
+{
+ int start;
+ unw_context_t uc;
+ unw_cursor_t cursor;
+
+ stack_start = &start;
+
+ // Initialize pipe mem validate check, opens file descriptors
+ unw_getcontext(&uc);
+ if (unw_init_local (&cursor, &uc) < 0)
+ panic ("unw_init_local failed!\n");
+
+ int i;
+ for (i = 3; i < 10; i++)
+ {
+
+ pid_t childpid = fork();
+ if (!childpid)
+ {
+ /* Close fds and make sure we still work */
+ int ret = close(i);
+ }
+
+ int status;
+ if (childpid)
+ {
+ wait(&status);
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return -1;
+ }
+ else
+ {
+ consume_and_run (10);
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
MAINTAINERCLEANFILES = Makefile.in
+noinst_PROGRAMS_arch =
+noinst_PROGRAMS_cdep =
noinst_PROGRAMS_common =
+check_PROGRAMS_arch =
+check_PROGRAMS_cdep =
check_PROGRAMS_common = test-proc-info test-static-link \
test-strerror
+check_SCRIPTS_arch =
+check_SCRIPTS_cdep =
check_SCRIPTS_common = run-check-namespace
if REMOTE_ONLY
- check_SCRIPTS_cdep =
- check_PROGRAMS_cdep =
- noinst_PROGRAMS_cdep = $(noinst_PROGRAMS_common)
perf:
else
LIBUNWIND_local = $(top_builddir)/src/libunwind.la
if ARCH_IA64
- noinst_PROGRAMS_arch = ia64-test-dyn1
- check_SCRIPTS_arch = run-ia64-test-dyn1
- check_PROGRAMS_arch = Gia64-test-stack Lia64-test-stack \
+ noinst_PROGRAMS_arch += ia64-test-dyn1
+ check_SCRIPTS_arch += run-ia64-test-dyn1
+ check_PROGRAMS_arch += Gia64-test-stack Lia64-test-stack \
Gia64-test-nat Lia64-test-nat \
Gia64-test-rbs Lia64-test-rbs \
Gia64-test-readonly Lia64-test-readonly \
else #!ARCH_IA64
if ARCH_PPC64
if USE_ALTIVEC
- noinst_PROGRAMS_arch = ppc64-test-altivec
+ noinst_PROGRAMS_arch += ppc64-test-altivec
endif #USE_ALTIVEC
endif #ARCH_PPC64
endif #!ARCH_IA64
- check_SCRIPTS_cdep =
- check_PROGRAMS_cdep = Gtest-bt Ltest-bt Gtest-exc Ltest-exc \
+ check_PROGRAMS_cdep += Gtest-bt Ltest-bt Gtest-exc Ltest-exc \
Gtest-init Ltest-init \
Gtest-concurrent Ltest-concurrent \
Gtest-resume-sig Ltest-resume-sig \
Gtest-resume-sig-rt Ltest-resume-sig-rt \
- Gtest-dyn1 Ltest-dyn1 \
Gtest-trace Ltest-trace \
+ Ltest-init-local-signal \
+ Ltest-mem-validate \
test-async-sig test-flush-cache test-init-remote \
- test-mem Ltest-varargs Ltest-nomalloc \
- Ltest-nocalloc Lrs-race
- noinst_PROGRAMS_cdep = forker Gperf-simple Lperf-simple \
+ test-mem test-reg-state Ltest-varargs \
+ Ltest-nomalloc Ltest-nocalloc Lrs-race
+ noinst_PROGRAMS_cdep += forker Gperf-simple Lperf-simple \
Gperf-trace Lperf-trace
if BUILD_PTRACE
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
XFAIL_TESTS =
-if !ARCH_IA64
-XFAIL_TESTS += Gtest-dyn1 Ltest-dyn1
+if ARCH_IA64
+ check_PROGRAMS_cdep += Gtest-dyn1 Ltest-dyn1
endif
# Use if arch defines but does not support PTRACE_SINGLESTEP
XFAIL_TESTS += $(XFAIL_TESTS_PTRACE_SINGLESTEP)
endif
+# This is meant for multilib binaries, -m32.
+# ptrace gives EBADREG when testing,
+# but generally everything else works.
+if NO_PTRACE_TEST
+ XFAIL_TESTS += run-ptrace-mapper test-ptrace Ltest-init-local-signal
+endif
+
noinst_PROGRAMS = $(noinst_PROGRAMS_common) $(noinst_PROGRAMS_cdep) \
$(noinst_PROGRAMS_arch)
Ltest_init_SOURCES = Ltest-init.cxx
Ltest_cxx_exceptions_SOURCES = Ltest-cxx-exceptions.cxx
+Ltest_init_local_signal_SOURCES = Ltest-init-local-signal.c Ltest-init-local-signal-lib.c
+
Gtest_dyn1_SOURCES = Gtest-dyn1.c flush-cache.S flush-cache.h
Ltest_dyn1_SOURCES = Ltest-dyn1.c flush-cache.S flush-cache.h
test_static_link_SOURCES = test-static-link-loc.c test-static-link-gen.c
Ltest_nocalloc_SOURCES = Ltest-nocalloc.c
Gtest_trace_SOURCES = Gtest-trace.c ident.c
Ltest_trace_SOURCES = Ltest-trace.c ident.c
+Ltest_mem_validate_SOURCES = Ltest-mem-validate.c
LIBUNWIND = $(top_builddir)/src/libunwind-$(arch).la
LIBUNWIND_ptrace = $(top_builddir)/src/libunwind-ptrace.la
test_flush_cache_LDADD = $(LIBUNWIND_local)
test_init_remote_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
test_mem_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
+test_reg_state_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
test_ptrace_LDADD = $(LIBUNWIND_ptrace) $(LIBUNWIND)
test_proc_info_LDADD = $(LIBUNWIND)
test_static_link_LDADD = $(LIBUNWIND)
test_strerror_LDADD = $(LIBUNWIND)
Lrs_race_LDADD = $(LIBUNWIND_local) -lpthread
Ltest_varargs_LDADD = $(LIBUNWIND_local)
+Ltest_init_local_signal_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Gtest_bt_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Gtest_concurrent_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) -lpthread
Gtest_dyn1_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Gtest_exc_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
-Gtest_init_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
+Gtest_init_LDADD = $(LIBUNWIND) $(LIBUNWIND_local) @BACKTRACELIB@
Gtest_resume_sig_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Gtest_resume_sig_rt_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Gperf_simple_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Lperf_simple_LDADD = $(LIBUNWIND_local)
Ltest_trace_LDADD = $(LIBUNWIND_local)
Lperf_trace_LDADD = $(LIBUNWIND_local)
+Ltest_mem_validate_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
test_setjmp_LDADD = $(LIBUNWIND_setjmp)
ia64_test_setjmp_LDADD = $(LIBUNWIND_setjmp)
if BUILD_COREDUMP
-test_coredump_unwind_LDADD = $(LIBUNWIND_coredump) $(LIBUNWIND)
+test_coredump_unwind_LDADD = $(LIBUNWIND_coredump) $(LIBUNWIND) @BACKTRACELIB@
endif
Gia64_test_nat_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
}
check_local_unw_abi () {
+ match _UL${plat}_apply_reg_state
+ match _UL${plat}_reg_states_iterate
match _UL${plat}_create_addr_space
match _UL${plat}_destroy_addr_space
match _UL${plat}_get_fpreg
match _UL${plat}_get_reg
match _UL${plat}_get_save_loc
match _UL${plat}_init_local
+ match _UL${plat}_init_local2
match _UL${plat}_init_remote
match _UL${plat}_is_signal_frame
- match _UL${plat}_handle_signal_frame
match _UL${plat}_local_addr_space
match _UL${plat}_resume
match _UL${plat}_set_caching_policy
+ match _UL${plat}_set_cache_size
match _UL${plat}_set_reg
match _UL${plat}_set_fpreg
match _UL${plat}_step
case ${plat} in
arm)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _UL${plat}_search_unwind_table
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_find_unwind_table
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_setcontext
;;
ia64)
match _UL${plat}_search_unwind_table
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
;;
x86)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_find_unwind_table
;;
x86_64)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_find_unwind_table
ppc*)
match _U${plat}_get_func_addr
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _UL${plat}_dwarf_search_unwind_table
match _UL${plat}_dwarf_find_unwind_table
match _UL${plat}_dwarf_find_unwind_table
match _UL${plat}_local_addr_space_init
match _U${plat}_get_elf_image
- match ${plat}_lock
+ match _U${plat}_get_exe_image_path
+ match ${plat}_lock
;;
*)
}
check_generic_unw_abi () {
+ match _U${plat}_apply_reg_state
+ match _U${plat}_reg_states_iterate
match _U${plat}_create_addr_space
match _U${plat}_destroy_addr_space
match _U${plat}_flush_cache
match _U${plat}_get_reg
match _U${plat}_get_save_loc
match _U${plat}_init_local
+ match _U${plat}_init_local2
match _U${plat}_init_remote
match _U${plat}_is_signal_frame
- match _U${plat}_handle_signal_frame
match _U${plat}_local_addr_space
match _U${plat}_regname
match _U${plat}_resume
match _U${plat}_set_caching_policy
+ match _U${plat}_set_cache_size
match _U${plat}_set_fpreg
match _U${plat}_set_reg
match _U${plat}_step
arm)
match _U${plat}_is_fpreg
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_search_unwind_table
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
;;
ia64)
match _U${plat}_search_unwind_table
match _U${plat}_find_dyn_list
if [ $plat = $build_plat ]; then
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
case $os in
linux*)
match _U${plat}_get_kernel_table
;;
x86)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
;;
x86_64)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
;;
ppc*)
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_get_func_addr
match _U${plat}_is_fpreg
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_search_unwind_table
match _U${plat}_dwarf_find_unwind_table
match _U${plat}_get_elf_image
+ match _U${plat}_get_exe_image_path
match _U${plat}_is_fpreg
match _U${plat}_local_addr_space_init
match ${plat}_lock
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
# define MAP_ANONYMOUS MAP_ANON
#endif
+#if !defined(MAP_NORESERVE)
+# define MAP_NORESERVE 0
+#endif
int
main (void)
for (n = 0; n < 30000; ++n)
{
if (mmap (NULL, 1, (n & 1) ? PROT_READ : PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
+ MAP_PRIVATE | MAP_ANONYMOUS
+#ifdef MAP_NORESERVE
+ | MAP_NORESERVE
+#endif
+ ,
-1, 0) == MAP_FAILED)
{
printf ("Failed after %ld successful maps\n", n - 1);
# it is tested using the coredump accessors. For more info about MiniDebugInfo
# see e.g. http://fedoraproject.org/wiki/Features/MiniDebugInfo
-./run-coredump-unwind -minidebuginfo
+${0%/*}/run-coredump-unwind -minidebuginfo
if (flags & LOGMODE_STDIO)
{
fflush(stdout);
- used += write(STDERR_FILENO, msg, used + msgeol_len);
+ write(STDERR_FILENO, msg, used + msgeol_len);
}
msg[used] = '\0'; /* remove msg_eol (usually "\n") */
if (flags & LOGMODE_SYSLOG)
while (*argv)
{
char *colon;
- long vaddr = strtol(*argv, &colon, 16);
+ unsigned long vaddr = strtoul(*argv, &colon, 16);
if (*colon != ':')
error_msg_and_die("Bad format: '%s'", *argv);
if (_UCD_add_backing_file_at_vaddr(ui, vaddr, colon + 1) < 0)
for (i = 0; i < n; ++i)
printf ("[%d] ip=%p\n", i, buffer[i]);
+ unw_set_cache_size (unw_local_addr_space, 1023, 0);
unw_flush_cache (unw_local_addr_space, 0, 0);
if (verbose)
/* automated test case */
argv = args;
+
+ /* Unless the args array is 'walked' the child
+ process is unable to access it and dies with a segfault */
+ fprintf(stderr, "Automated test (%s,%s,%s,%s)\n",
+ args[0],args[1],args[2],args[3]);
}
else if (argc > 1)
while (argv[optind][0] == '-')
--- /dev/null
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003-2004 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Copyright (c) 2003 Hewlett-Packard Co.
+
+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 "compiler.h"
+
+#include <libunwind.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+#define panic(args...) \
+ { fprintf (stderr, args); exit (-1); }
+
+int verbose;
+
+struct cb_data
+{
+ unw_word_t ip;
+ void* reg_state;
+ size_t len;
+};
+
+static int
+dwarf_reg_states_callback(void *token,
+ void *rs,
+ size_t size,
+ unw_word_t start_ip, unw_word_t end_ip)
+{
+ struct cb_data *data = token;
+ if (start_ip <= data->ip && data->ip < end_ip)
+ {
+ data->reg_state = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ memcpy(data->reg_state, rs, size);
+ data->len = size;
+ }
+ return 0;
+}
+
+static void
+do_backtrace (void)
+{
+ unw_cursor_t cursor;
+ unw_word_t ip, sp;
+ unw_context_t uc;
+ int ret;
+
+ unw_getcontext (&uc);
+ if (unw_init_local (&cursor, &uc) < 0)
+ panic ("unw_init_local failed!\n");
+
+ do
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ unw_get_reg (&cursor, UNW_REG_SP, &sp);
+
+ if (verbose)
+ printf ("%016lx (sp=%016lx)\n", (long) ip, (long) sp);
+
+ struct cb_data data = {.ip = ip, .reg_state = NULL};
+ ret = unw_reg_states_iterate(&cursor, dwarf_reg_states_callback, &data);
+ if (ret > 0)
+ {
+ ret = unw_apply_reg_state (&cursor, data.reg_state);
+ munmap(data.reg_state, data.len);
+ }
+ if (ret < 0)
+ {
+ unw_get_reg (&cursor, UNW_REG_IP, &ip);
+ panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
+ ret, (long) ip);
+ }
+ }
+ while (ret > 0);
+}
+
+int
+consume_some_stack_space (void)
+{
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ char string[1024];
+
+ memset (&cursor, 0, sizeof (cursor));
+ memset (&uc, 0, sizeof (uc));
+ return sprintf (string, "hello %p %p\n", &cursor, &uc);
+}
+
+int
+main (int argc, char **argv UNUSED)
+{
+ struct rlimit rlim;
+
+ verbose = argc > 1;
+
+ if (consume_some_stack_space () > 9999)
+ exit (-1); /* can't happen, but don't let the compiler know... */
+
+ rlim.rlim_cur = 0;
+ rlim.rlim_max = RLIM_INFINITY;
+ setrlimit (RLIMIT_DATA, &rlim);
+
+ do_backtrace ();
+ return 0;
+}
(void *) &unw_get_accessors,
(void *) &unw_flush_cache,
(void *) &unw_set_caching_policy,
+ (void *) &unw_set_cache_size,
(void *) &unw_regname,
(void *) &unw_get_proc_info,
(void *) &unw_get_save_loc,
(void *) &unw_get_accessors,
(void *) &unw_flush_cache,
(void *) &unw_set_caching_policy,
+ (void *) &unw_set_cache_size,
(void *) &unw_regname,
(void *) &unw_get_proc_info,
(void *) &unw_get_save_loc,