1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-05-17 02:35:17 +02:00

Add initial ARM and MIPS support. To support this, also enable the

reading of .debug_frame sections (used in lieu of .eh_frame sections
when they're not available).
This commit is contained in:
Daniel Jacobowitz 2008-02-04 17:16:37 -07:00 committed by David Mosberger-Tang
parent 5ed2da2a40
commit 3842dac733
100 changed files with 6270 additions and 920 deletions

View file

@ -1,9 +1,15 @@
if ARCH_ARM
include_HEADERS_tdep = include/libunwind-arm.h
else
if ARCH_IA64
include_HEADERS_tdep = include/libunwind-ia64.h
else
if ARCH_HPPA
include_HEADERS_tdep = include/libunwind-hppa.h
else
if ARCH_MIPS
include_HEADERS_tdep = include/libunwind-mips.h
else
if ARCH_X86
include_HEADERS_tdep = include/libunwind-x86.h
else
@ -19,8 +25,10 @@ endif # ARCH_PPC64
endif # ARCH_PPC32
endif # ARCH_X86_64
endif # ARCH_X86
endif # ARCH_MIPS
endif # ARCH_HPPA
endif # ARCH_IA64
endif # ARCH_ARM
include_HEADERS_common = $(include_HEADERS_tdep) \
include/libunwind-dynamic.h include/libunwind-ptrace.h

View file

@ -66,8 +66,9 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
uninstall-recursive
am__include_HEADERS_DIST = include/libunwind-ppc64.h \
include/libunwind-ppc32.h include/libunwind-x86_64.h \
include/libunwind-x86.h include/libunwind-hppa.h \
include/libunwind-ia64.h include/libunwind-dynamic.h \
include/libunwind-x86.h include/libunwind-mips.h \
include/libunwind-hppa.h include/libunwind-ia64.h \
include/libunwind-arm.h include/libunwind-dynamic.h \
include/libunwind-ptrace.h include/libunwind.h \
include/unwind.h
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@ -100,10 +101,14 @@ AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
ARCH = @ARCH@
ARCH_ARM_FALSE = @ARCH_ARM_FALSE@
ARCH_ARM_TRUE = @ARCH_ARM_TRUE@
ARCH_HPPA_FALSE = @ARCH_HPPA_FALSE@
ARCH_HPPA_TRUE = @ARCH_HPPA_TRUE@
ARCH_IA64_FALSE = @ARCH_IA64_FALSE@
ARCH_IA64_TRUE = @ARCH_IA64_TRUE@
ARCH_MIPS_FALSE = @ARCH_MIPS_FALSE@
ARCH_MIPS_TRUE = @ARCH_MIPS_TRUE@
ARCH_PPC32_FALSE = @ARCH_PPC32_FALSE@
ARCH_PPC32_TRUE = @ARCH_PPC32_TRUE@
ARCH_PPC64_FALSE = @ARCH_PPC64_FALSE@
@ -174,6 +179,7 @@ PKG_MINOR = @PKG_MINOR@
RANLIB = @RANLIB@
REMOTE_ONLY_FALSE = @REMOTE_ONLY_FALSE@
REMOTE_ONLY_TRUE = @REMOTE_ONLY_TRUE@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -233,12 +239,14 @@ target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_PPC32_FALSE@@ARCH_PPC64_TRUE@@ARCH_X86_64_FALSE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-ppc64.h
@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_PPC32_TRUE@@ARCH_X86_64_FALSE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-ppc32.h
@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_X86_64_TRUE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-x86_64.h
@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_X86_TRUE@include_HEADERS_tdep = include/libunwind-x86.h
@ARCH_HPPA_TRUE@@ARCH_IA64_FALSE@include_HEADERS_tdep = include/libunwind-hppa.h
@ARCH_IA64_TRUE@include_HEADERS_tdep = include/libunwind-ia64.h
@ARCH_ARM_FALSE@@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_MIPS_FALSE@@ARCH_PPC32_FALSE@@ARCH_PPC64_TRUE@@ARCH_X86_64_FALSE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-ppc64.h
@ARCH_ARM_FALSE@@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_MIPS_FALSE@@ARCH_PPC32_TRUE@@ARCH_X86_64_FALSE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-ppc32.h
@ARCH_ARM_FALSE@@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_MIPS_FALSE@@ARCH_X86_64_TRUE@@ARCH_X86_FALSE@include_HEADERS_tdep = include/libunwind-x86_64.h
@ARCH_ARM_FALSE@@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_MIPS_FALSE@@ARCH_X86_TRUE@include_HEADERS_tdep = include/libunwind-x86.h
@ARCH_ARM_FALSE@@ARCH_HPPA_FALSE@@ARCH_IA64_FALSE@@ARCH_MIPS_TRUE@include_HEADERS_tdep = include/libunwind-mips.h
@ARCH_ARM_FALSE@@ARCH_HPPA_TRUE@@ARCH_IA64_FALSE@include_HEADERS_tdep = include/libunwind-hppa.h
@ARCH_ARM_FALSE@@ARCH_IA64_TRUE@include_HEADERS_tdep = include/libunwind-ia64.h
@ARCH_ARM_TRUE@include_HEADERS_tdep = include/libunwind-arm.h
include_HEADERS_common = $(include_HEADERS_tdep) \
include/libunwind-dynamic.h include/libunwind-ptrace.h

500
aclocal.m4 vendored
View file

@ -13,7 +13,7 @@
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
# serial 48 Debian 1.5.22-4 AC_PROG_LIBTOOL
# serial 51 Debian 1.5.24-2 AC_PROG_LIBTOOL
# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
@ -176,7 +176,7 @@ test -z "$STRIP" && STRIP=:
test -z "$ac_objext" && ac_objext=o
# Determine commands to create old-style static archives.
old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
old_postinstall_cmds='chmod 644 $oldlib'
old_postuninstall_cmds=
@ -263,8 +263,9 @@ cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
# Check for compiler boilerplate output or warnings with
# the simple compiler test code.
AC_DEFUN([_LT_COMPILER_BOILERPLATE],
[ac_outfile=conftest.$ac_objext
printf "$lt_simple_compile_test_code" >conftest.$ac_ext
[AC_REQUIRE([LT_AC_PROG_SED])dnl
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" >conftest.$ac_ext
eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_compiler_boilerplate=`cat conftest.err`
$rm conftest*
@ -276,8 +277,9 @@ $rm conftest*
# Check for linker boilerplate output or warnings with
# the simple link test code.
AC_DEFUN([_LT_LINKER_BOILERPLATE],
[ac_outfile=conftest.$ac_objext
printf "$lt_simple_link_test_code" >conftest.$ac_ext
[AC_REQUIRE([LT_AC_PROG_SED])dnl
ac_outfile=conftest.$ac_objext
echo "$lt_simple_link_test_code" >conftest.$ac_ext
eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
_lt_linker_boilerplate=`cat conftest.err`
$rm conftest*
@ -293,12 +295,20 @@ $rm conftest*
# If we don't find anything, use the default library path according
# to the aix ld manual.
AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_LINK_IFELSE(AC_LANG_PROGRAM,[
lt_aix_libpath_sed='
/Import File Strings/,/^$/ {
/^0/ {
s/^0 *\(.*\)$/\1/
p
}
}'
aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
# Check for a 64-bit object if we didn't find anything.
if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`; fi],[])
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi],[])
if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
])# _LT_AC_SYS_LIBPATH_AIX
@ -529,13 +539,17 @@ ia64-*-hpux*)
rm -rf conftest*
;;
x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
s390*-*linux*|sparc*-*linux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
*32-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_i386_fbsd"
;;
x86_64-*linux*)
LD="${LD-ld} -m elf_i386"
;;
@ -552,6 +566,9 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
;;
*64-bit*)
case $host in
x86_64-*kfreebsd*-gnu)
LD="${LD-ld} -m elf_x86_64_fbsd"
;;
x86_64-*linux*)
LD="${LD-ld} -m elf_x86_64"
;;
@ -623,7 +640,7 @@ AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
AC_CACHE_CHECK([$1], [$2],
[$2=no
ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
printf "$lt_simple_compile_test_code" > conftest.$ac_ext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
lt_compiler_flag="$3"
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
@ -664,11 +681,12 @@ fi
# ------------------------------------------------------------
# Check whether the given compiler option works
AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
[AC_CACHE_CHECK([$1], [$2],
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_CACHE_CHECK([$1], [$2],
[$2=no
save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $3"
printf "$lt_simple_link_test_code" > conftest.$ac_ext
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
# The linker can only warn and ignore the option if not recognized
# So say no if there are warnings
@ -782,24 +800,27 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
fi
;;
*)
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
if test -n "$lt_cv_sys_max_cmd_len"; then
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
else
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
= "XX$teststring") >/dev/null 2>&1 &&
new_result=`expr "X$teststring" : ".*" 2>&1` &&
lt_cv_sys_max_cmd_len=$new_result &&
test $i != 17 # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
done
teststring=
# Add a significant safety factor because C++ compilers can tack on massive
# amounts of additional arguments before passing them to the linker.
# It appears as though 1/2 is a usable value.
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
new_result=`expr "X$teststring" : ".*" 2>&1` &&
lt_cv_sys_max_cmd_len=$new_result &&
test $i != 17 # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
done
teststring=
# Add a significant safety factor because C++ compilers can tack on massive
# amounts of additional arguments before passing them to the linker.
# It appears as though 1/2 is a usable value.
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
fi
;;
esac
])
@ -1026,7 +1047,8 @@ fi
# ---------------------------------
# Check to see if options -c and -o are simultaneously supported by compiler
AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
[_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
[_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
@ -1034,7 +1056,7 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
mkdir conftest
cd conftest
mkdir out
printf "$lt_simple_compile_test_code" > conftest.$ac_ext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
lt_compiler_flag="-o out/conftest2.$ac_objext"
# Insert the option either (1) after the last *FLAGS variable, or
@ -1174,6 +1196,7 @@ else
darwin*)
if test -n "$STRIP" ; then
striplib="$STRIP -x"
old_striplib="$STRIP -S"
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
@ -1191,7 +1214,8 @@ fi
# -----------------------------
# PORTME Fill in your ld.so characteristics
AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
[AC_MSG_CHECKING([dynamic linker characteristics])
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_MSG_CHECKING([dynamic linker characteristics])
library_names_spec=
libname_spec='lib$name'
soname_spec=
@ -1205,20 +1229,58 @@ shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
m4_if($1,[],[
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
case $host_os in
darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
*) lt_awk_arg="/^libraries:/" ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then
# if the path contains ";" then we assume it to be the separator
# otherwise default to the standard path separator (i.e. ":") - it is
# assumed that no part of a normal pathname contains ";" but that should
# okay in the real world where ";" in dirpaths is itself problematic.
sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'`
else
sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
fi
# Ok, now we have the path, separated by spaces, we can step through it
# and add multilib dir if necessary.
lt_tmp_lt_search_path_spec=
lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
for lt_sys_path in $lt_search_path_spec; do
if test -d "$lt_sys_path/$lt_multi_os_dir"; then
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
else
test -d "$lt_sys_path" && \
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
fi
done
lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk '
BEGIN {RS=" "; FS="/|\n";} {
lt_foo="";
lt_count=0;
for (lt_i = NF; lt_i > 0; lt_i--) {
if ($lt_i != "" && $lt_i != ".") {
if ($lt_i == "..") {
lt_count++;
} else {
if (lt_count == 0) {
lt_foo="/" $lt_i lt_foo;
} else {
lt_count--;
}
}
}
}
if (lt_foo != "") { lt_freq[[lt_foo]]++; }
if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
}'`
sys_lib_search_path_spec=`echo $lt_search_path_spec`
else
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
fi
fi])
need_lib_prefix=unknown
hardcode_into_libs=no
@ -1375,12 +1437,8 @@ darwin* | rhapsody*)
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
# Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
if test "$GCC" = yes; then
sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
else
sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
fi
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
;;
@ -1434,7 +1492,7 @@ freebsd* | dragonfly*)
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
;;
freebsd*) # from 4.6 on
*) # from 4.6 on, and DragonFly
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
;;
@ -1497,7 +1555,7 @@ hpux9* | hpux10* | hpux11*)
postinstall_cmds='chmod 555 $lib'
;;
interix3*)
interix[[3-9]]*)
version_type=linux
need_lib_prefix=no
need_version=no
@ -1568,7 +1626,7 @@ linux* | k*bsd*-gnu)
# Append ld.so.conf contents to the search path
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
fi
@ -1674,6 +1732,10 @@ osf3* | osf4* | osf5*)
sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
;;
rdos*)
dynamic_linker=no
;;
solaris*)
version_type=linux
need_lib_prefix=no
@ -1779,7 +1841,8 @@ fi
# _LT_AC_TAGCONFIG
# ----------------
AC_DEFUN([_LT_AC_TAGCONFIG],
[AC_ARG_WITH([tags],
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_ARG_WITH([tags],
[AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
[include additional configurations @<:@automatic@:>@])],
[tagnames="$withval"])
@ -2040,7 +2103,7 @@ m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
# AC_PATH_TOOL_PREFIX
# -------------------
# find a file program which can recognise shared library
# find a file program which can recognize shared library
AC_DEFUN([AC_PATH_TOOL_PREFIX],
[AC_REQUIRE([AC_PROG_EGREP])dnl
AC_MSG_CHECKING([for $1])
@ -2103,7 +2166,7 @@ fi
# AC_PATH_MAGIC
# -------------
# find a file program which can recognise a shared library
# find a file program which can recognize a shared library
AC_DEFUN([AC_PATH_MAGIC],
[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
if test -z "$lt_cv_path_MAGIC_CMD"; then
@ -2250,7 +2313,7 @@ esac
# how to check for library dependencies
# -- PORTME fill in with the dynamic library characteristics
AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
[AC_CACHE_CHECK([how to recognise dependent libraries],
[AC_CACHE_CHECK([how to recognize dependent libraries],
lt_cv_deplibs_check_method,
[lt_cv_file_magic_cmd='$MAGIC_CMD'
lt_cv_file_magic_test_file=
@ -2289,9 +2352,15 @@ cygwin*)
mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump'.
lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
lt_cv_file_magic_cmd='$OBJDUMP -f'
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
if ( file / ) >/dev/null 2>&1; then
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
lt_cv_file_magic_cmd='func_win32_libid'
else
lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
lt_cv_file_magic_cmd='$OBJDUMP -f'
fi
;;
darwin* | rhapsody*)
@ -2336,7 +2405,7 @@ hpux10.20* | hpux11*)
esac
;;
interix3*)
interix[[3-9]]*)
# PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
;;
@ -2386,6 +2455,10 @@ osf3* | osf4* | osf5*)
lt_cv_deplibs_check_method=pass_all
;;
rdos*)
lt_cv_deplibs_check_method=pass_all
;;
solaris*)
lt_cv_deplibs_check_method=pass_all
;;
@ -2438,7 +2511,7 @@ AC_DEFUN([AC_PROG_NM],
lt_cv_path_NM="$NM"
else
lt_nm_to_check="${ac_tool_prefix}nm"
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
lt_nm_to_check="$lt_nm_to_check nm"
fi
for lt_tmp_nm in $lt_nm_to_check; do
@ -2654,10 +2727,10 @@ objext=o
_LT_AC_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;\n"
lt_simple_compile_test_code="int some_variable = 0;"
# Code to be used in simple link tests
lt_simple_link_test_code='int main(){return(0);}\n'
lt_simple_link_test_code='int main(){return(0);}'
_LT_AC_SYS_COMPILER
@ -2759,10 +2832,10 @@ objext=o
_LT_AC_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;\n"
lt_simple_compile_test_code="int some_variable = 0;"
# Code to be used in simple link tests
lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
@ -2908,7 +2981,7 @@ case $host_os in
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
:
else
# We have old collect2
_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
@ -3067,10 +3140,10 @@ case $host_os in
case $cc_basename in
xlc*)
output_verbose_link_cmd='echo'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
_LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
# Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
_LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
;;
*)
@ -3153,9 +3226,7 @@ case $host_os in
_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
hppa*64*|ia64*)
_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
;;
hppa*64*|ia64*) ;;
*)
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
;;
@ -3223,7 +3294,7 @@ case $host_os in
;;
esac
;;
interix3*)
interix[[3-9]]*)
_LT_AC_TAGVAR(hardcode_direct, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
@ -3343,6 +3414,29 @@ case $host_os in
# dependencies.
output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
# Not sure whether something based on
# $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
# would be better.
output_verbose_link_cmd='echo'
# Archives containing C++ object files must be created using
# "CC -xar", where "CC" is the Sun C++ compiler. This is
# necessary to make sure instantiated templates are included
# in the archive.
_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
;;
esac
;;
esac
;;
lynxos*)
@ -3381,16 +3475,20 @@ case $host_os in
_LT_AC_TAGVAR(ld_shlibs, $1)=no
;;
openbsd*)
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
if test -f /usr/libexec/ld.so; then
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
fi
output_verbose_link_cmd='echo'
else
_LT_AC_TAGVAR(ld_shlibs, $1)=no
fi
output_verbose_link_cmd='echo'
;;
osf3*)
case $cc_basename in
@ -3552,15 +3650,10 @@ case $host_os in
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The C++ compiler is used as linker so we must use $wl
# flag to pass the commands to the underlying system
# linker. We must also pass each convience library through
# to the system linker between allextract/defaultextract.
# The C++ compiler will combine linker options so we
# cannot just pass the convience library names through
# without $wl.
# The compiler driver will combine and reorder linker options,
# but understands `-z linker_flag'.
# Supported since Solaris 2.6 (maybe 2.5.1?)
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
;;
esac
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
@ -3607,6 +3700,12 @@ case $host_os in
fi
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
;;
esac
fi
;;
esac
@ -3850,7 +3949,7 @@ $rm -f confest.$objext
# PORTME: override above test on systems where it is broken
ifelse([$1],[CXX],
[case $host_os in
interix3*)
interix[[3-9]]*)
# Interix 3.5 installs completely hosed .la files for C++, so rather than
# hack all around it, let's just trust "g++" to DTRT.
_LT_AC_TAGVAR(predep_objects,$1)=
@ -3858,13 +3957,46 @@ interix3*)
_LT_AC_TAGVAR(postdeps,$1)=
;;
linux*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
#
# The more standards-conforming stlport4 library is
# incompatible with the Cstd library. Avoid specifying
# it if it's in CXXFLAGS. Ignore libCrun as
# -library=stlport4 depends on it.
case " $CXX $CXXFLAGS " in
*" -library=stlport4 "*)
solaris_use_stlport4=yes
;;
esac
if test "$solaris_use_stlport4" != yes; then
_LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
fi
;;
esac
;;
solaris*)
case $cc_basename in
CC*)
# The more standards-conforming stlport4 library is
# incompatible with the Cstd library. Avoid specifying
# it if it's in CXXFLAGS. Ignore libCrun as
# -library=stlport4 depends on it.
case " $CXX $CXXFLAGS " in
*" -library=stlport4 "*)
solaris_use_stlport4=yes
;;
esac
# Adding this requires a known-good setup of shared libraries for
# Sun compiler versions before 5.6, else PIC objects from an old
# archive will be linked into the output, leading to subtle bugs.
_LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
if test "$solaris_use_stlport4" != yes; then
_LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
fi
;;
esac
;;
@ -3913,10 +4045,17 @@ objext=o
_LT_AC_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code=" subroutine t\n return\n end\n"
lt_simple_compile_test_code="\
subroutine t
return
end
"
# Code to be used in simple link tests
lt_simple_link_test_code=" program t\n end\n"
lt_simple_link_test_code="\
program t
end
"
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
@ -3995,10 +4134,10 @@ objext=o
_LT_AC_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code="class foo {}\n"
lt_simple_compile_test_code="class foo {}"
# Code to be used in simple link tests
lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_AC_SYS_COMPILER
@ -4051,7 +4190,7 @@ objext=o
_LT_AC_TAGVAR(objext, $1)=$objext
# Code to be used in simple compile tests
lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
# Code to be used in simple link tests
lt_simple_link_test_code="$lt_simple_compile_test_code"
@ -4140,6 +4279,7 @@ if test -f "$ltmain"; then
_LT_AC_TAGVAR(module_cmds, $1) \
_LT_AC_TAGVAR(module_expsym_cmds, $1) \
_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
_LT_AC_TAGVAR(fix_srcfile_path, $1) \
_LT_AC_TAGVAR(exclude_expsyms, $1) \
_LT_AC_TAGVAR(include_expsyms, $1); do
@ -4186,7 +4326,7 @@ ifelse([$1], [],
# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
#
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# Free Software Foundation, Inc.
#
# This file is part of GNU Libtool:
@ -4511,7 +4651,7 @@ sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
# Fix the shell variable \$srcfile for the compiler.
fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
fix_srcfile_path=$lt_fix_srcfile_path
# Set to yes if exported symbols are required.
always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
@ -4594,6 +4734,7 @@ fi
# ---------------------------------
AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
[AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([LT_AC_PROG_SED])
AC_REQUIRE([AC_PROG_NM])
AC_REQUIRE([AC_OBJEXT])
# Check for command to grab the raw symbol name followed by C symbol from nm.
@ -4820,12 +4961,14 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
# like `-m68040'.
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
# PIC is the default for these OSes.
;;
mingw* | os2* | pw32*)
mingw* | cygwin* | os2* | pw32*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
;;
darwin* | rhapsody*)
@ -4837,7 +4980,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
# DJGPP does not support shared libraries at all
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
;;
interix3*)
interix[[3-9]]*)
# Interix 3.x gcc -fpic/-fPIC options generate broken code.
# Instead, we relocate shared libraries at runtime.
;;
@ -4973,6 +5116,14 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C++ 5.9
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
;;
esac
;;
esac
;;
@ -5093,13 +5244,15 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
# PIC is the default for these OSes.
;;
mingw* | pw32* | os2*)
mingw* | cygwin* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
;;
@ -5109,7 +5262,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
;;
interix3*)
interix[[3-9]]*)
# Interix 3.x gcc -fpic/-fPIC options generate broken code.
# Instead, we relocate shared libraries at runtime.
;;
@ -5167,7 +5320,7 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
esac
;;
mingw* | pw32* | os2*)
mingw* | cygwin* | pw32* | os2*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
@ -5219,6 +5372,22 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
# All Alpha code is PIC.
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
# Sun C 5.9
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
;;
*Sun\ F*)
# Sun Fortran 8.3 passes all unrecognized flags to the linker
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=''
;;
esac
;;
esac
;;
@ -5228,6 +5397,10 @@ AC_MSG_CHECKING([for $compiler option to produce PIC])
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
rdos*)
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
;;
solaris*)
_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
@ -5322,7 +5495,8 @@ AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
# ------------------------------------
# See if the linker supports building shared libraries.
AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
[AC_REQUIRE([LT_AC_PROG_SED])dnl
AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
ifelse([$1],[CXX],[
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
case $host_os in
@ -5339,7 +5513,7 @@ ifelse([$1],[CXX],[
_LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
;;
cygwin* | mingw*)
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
;;
linux* | k*bsd*-gnu)
_LT_AC_TAGVAR(link_all_deplibs, $1)=no
@ -5481,7 +5655,7 @@ EOF
_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_AC_TAGVAR(always_export_symbols, $1)=no
_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
_LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
@ -5499,7 +5673,7 @@ EOF
fi
;;
interix3*)
interix[[3-9]]*)
_LT_AC_TAGVAR(hardcode_direct, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
@ -5514,7 +5688,7 @@ EOF
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
linux* | k*bsd*-gnu)
gnu* | linux* | k*bsd*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
tmp_addflag=
case $cc_basename,$host_cpu in
@ -5532,13 +5706,22 @@ EOF
ifc* | ifort*) # Intel Fortran compiler
tmp_addflag=' -nofor_main' ;;
esac
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*) # Sun C 5.9
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
tmp_sharedflag='-G' ;;
*Sun\ F*) # Sun Fortran 8.3
tmp_sharedflag='-G' ;;
*)
tmp_sharedflag='-shared' ;;
esac
_LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
if test $supports_anon_versioning = yes; then
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
$echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
fi
_LT_AC_TAGVAR(link_all_deplibs, $1)=no
else
@ -5579,7 +5762,7 @@ EOF
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
_LT_AC_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
@ -5698,7 +5881,7 @@ _LT_EOF
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
:
else
# We have old collect2
_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
@ -5791,7 +5974,7 @@ _LT_EOF
# The linker will automatically build a .lib file if we build a DLL.
_LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
# FIXME: Should let the user specify the lib program.
_LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
_LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
_LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
;;
@ -5833,10 +6016,10 @@ _LT_EOF
case $cc_basename in
xlc*)
output_verbose_link_cmd='echo'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
_LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
# Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
_LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
;;
*)
@ -5998,24 +6181,28 @@ _LT_EOF
;;
openbsd*)
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
if test -f /usr/libexec/ld.so; then
_LT_AC_TAGVAR(hardcode_direct, $1)=yes
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
else
case $host_os in
openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
;;
*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
;;
esac
fi
else
case $host_os in
openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
;;
*)
_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
;;
esac
_LT_AC_TAGVAR(ld_shlibs, $1)=no
fi
;;
@ -6074,17 +6261,16 @@ _LT_EOF
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine linker options so we
# cannot just pass the convience library names through
# without $wl, iff we do not link with $LD.
# Luckily, gcc supports the same syntax we need for Sun Studio.
# The compiler driver will combine and reorder linker options,
# but understands `-z linker_flag'. GCC discards it without `$wl',
# but is careful enough not to reorder.
# Supported since Solaris 2.6 (maybe 2.5.1?)
case $wlarc in
'')
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
*)
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
esac ;;
if test "$GCC" = yes; then
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
else
_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
fi
;;
esac
_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
;;
@ -6141,7 +6327,7 @@ _LT_EOF
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
_LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
@ -6216,7 +6402,7 @@ x|xyes)
# to ld, don't add -lc before -lgcc.
AC_MSG_CHECKING([whether -lc should be explicitly linked in])
$rm conftest*
printf "$lt_simple_compile_test_code" > conftest.$ac_ext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
soname=conftest
@ -6319,6 +6505,30 @@ AC_DEFUN([LT_AC_PROG_RC],
[AC_CHECK_TOOL(RC, windres, no)
])
# Cheap backport of AS_EXECUTABLE_P and required macros
# from Autoconf 2.59; we should not use $as_executable_p directly.
# _AS_TEST_PREPARE
# ----------------
m4_ifndef([_AS_TEST_PREPARE],
[m4_defun([_AS_TEST_PREPARE],
[if test -x / >/dev/null 2>&1; then
as_executable_p='test -x'
else
as_executable_p='test -f'
fi
])])# _AS_TEST_PREPARE
# AS_EXECUTABLE_P
# ---------------
# Check whether a file is executable.
m4_ifndef([AS_EXECUTABLE_P],
[m4_defun([AS_EXECUTABLE_P],
[AS_REQUIRE([_AS_TEST_PREPARE])dnl
$as_executable_p $1[]dnl
])])# AS_EXECUTABLE_P
# NOTE: This macro has been submitted for inclusion into #
# GNU Autoconf as AC_PROG_SED. When it is available in #
# a released version of Autoconf we should remove this #
@ -6339,12 +6549,13 @@ do
test -z "$as_dir" && as_dir=.
for lt_ac_prog in sed gsed; do
for ac_exec_ext in '' $ac_executable_extensions; do
if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then
lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
fi
done
done
done
IFS=$as_save_IFS
lt_ac_max=0
lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
@ -6377,6 +6588,7 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
done
])
SED=$lt_cv_path_SED
AC_SUBST([SED])
AC_MSG_RESULT([$SED])
])

1032
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -75,19 +75,24 @@ AM_CONDITIONAL(USE_ALTIVEC, test x$use_altivec = xhas_altivec)
get_arch() {
case "$1" in
arm*) echo arm;;
i?86) echo x86;;
hppa*) echo hppa;;
mips*) echo mips;;
powerpc64) is_gcc_m64;;
*) echo $1;;
esac
}
build_arch=`get_arch $build_cpu`
host_arch=`get_arch $host_cpu`
target_arch=`get_arch $target_cpu`
AM_CONDITIONAL(REMOTE_ONLY, test x$target_arch != x$build_arch)
AM_CONDITIONAL(REMOTE_ONLY, test x$target_arch != x$host_arch)
AM_CONDITIONAL(ARCH_ARM, test x$target_arch = xarm)
AM_CONDITIONAL(ARCH_IA64, test x$target_arch = xia64)
AM_CONDITIONAL(ARCH_HPPA, test x$target_arch = xhppa)
AM_CONDITIONAL(ARCH_MIPS, test x$target_arch = xmips)
AM_CONDITIONAL(ARCH_X86, test x$target_arch = xx86)
AM_CONDITIONAL(ARCH_X86_64, test x$target_arch = xx86_64)
AM_CONDITIONAL(ARCH_PPC32, test x$target_arch = xppc32)
@ -101,7 +106,7 @@ if test x$target_arch = xppc64; then
AC_SUBST([libdir])
fi
if test x$target_arch != x$build_arch; then
if test x$target_arch != x$host_arch; then
CPPFLAGS="${CPPFLAGS} -DUNW_REMOTE_ONLY"
fi
AC_CONFIG_LINKS(include/libunwind.h:include/libunwind-$target_arch.h

View file

@ -60,10 +60,14 @@ AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
ARCH = @ARCH@
ARCH_ARM_FALSE = @ARCH_ARM_FALSE@
ARCH_ARM_TRUE = @ARCH_ARM_TRUE@
ARCH_HPPA_FALSE = @ARCH_HPPA_FALSE@
ARCH_HPPA_TRUE = @ARCH_HPPA_TRUE@
ARCH_IA64_FALSE = @ARCH_IA64_FALSE@
ARCH_IA64_TRUE = @ARCH_IA64_TRUE@
ARCH_MIPS_FALSE = @ARCH_MIPS_FALSE@
ARCH_MIPS_TRUE = @ARCH_MIPS_TRUE@
ARCH_PPC32_FALSE = @ARCH_PPC32_FALSE@
ARCH_PPC32_TRUE = @ARCH_PPC32_TRUE@
ARCH_PPC64_FALSE = @ARCH_PPC64_FALSE@
@ -134,6 +138,7 @@ PKG_MINOR = @PKG_MINOR@
RANLIB = @RANLIB@
REMOTE_ONLY_FALSE = @REMOTE_ONLY_FALSE@
REMOTE_ONLY_TRUE = @REMOTE_ONLY_TRUE@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@

View file

@ -329,6 +329,23 @@ struct dwarf_rs_cache
dwarf_reg_state_t buckets[DWARF_UNW_CACHE_SIZE];
};
/* A list of descriptors for loaded .debug_frame sections. */
struct unw_debug_frame_list
{
/* The start (inclusive) and end (exclusive) of the described region. */
unw_word_t start;
unw_word_t end;
/* The debug frame itself. */
char *debug_frame;
size_t debug_frame_size;
/* Index (for binary search). */
struct table_entry *index;
size_t index_size;
/* Pointer to next descriptor. */
struct unw_debug_frame_list *next;
};
/* Convenience macros: */
#define dwarf_init UNW_ARCH_OBJ (dwarf_init)
#define dwarf_find_proc_info UNW_OBJ (dwarf_find_proc_info)
@ -363,6 +380,7 @@ extern int dwarf_extract_proc_info_from_fde (unw_addr_space_t as,
unw_word_t *fde_addr,
unw_proc_info_t *pi,
int need_unwind_info,
unw_word_t base,
void *arg);
extern int dwarf_find_save_locs (struct dwarf_cursor *c);
extern int dwarf_create_state_record (struct dwarf_cursor *c,

View file

@ -9,6 +9,12 @@
#include "dwarf.h"
#include "libunwind_i.h"
/* Unless we are told otherwise, assume that a "machine address" is
the size of an unw_word_t. */
#ifndef dwarf_addr_size
# define dwarf_addr_size(as) (sizeof (unw_word_t))
#endif
#define dwarf_to_unw_regnum_map UNW_OBJ (dwarf_to_unw_regnum_map)
extern uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH];
@ -22,7 +28,7 @@ extern uint8_t dwarf_to_unw_regnum_map[DWARF_REGNUM_MAP_LENGTH];
/* In the local-only case, we can let the compiler directly access
memory and don't need to worry about differing byte-order. */
typedef union
typedef union __attribute__ ((packed))
{
int8_t s8;
int16_t s16;
@ -32,16 +38,15 @@ typedef union
uint16_t u16;
uint32_t u32;
uint64_t u64;
unw_word_t w;
void *ptr;
}
dwarf_misaligned_value_t __attribute__ ((packed));
dwarf_misaligned_value_t;
static inline int
dwarf_reads8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->s8;
*addr += sizeof (mvp->s8);
@ -52,7 +57,7 @@ static inline int
dwarf_reads16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->s16;
*addr += sizeof (mvp->s16);
@ -63,7 +68,7 @@ static inline int
dwarf_reads32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->s32;
*addr += sizeof (mvp->s32);
@ -74,7 +79,7 @@ static inline int
dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
int64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->s64;
*addr += sizeof (mvp->s64);
@ -85,7 +90,7 @@ static inline int
dwarf_readu8 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint8_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->u8;
*addr += sizeof (mvp->u8);
@ -96,7 +101,7 @@ static inline int
dwarf_readu16 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint16_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->u16;
*addr += sizeof (mvp->u16);
@ -107,7 +112,7 @@ static inline int
dwarf_readu32 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint32_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->u32;
*addr += sizeof (mvp->u32);
@ -118,24 +123,13 @@ static inline int
dwarf_readu64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
uint64_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
dwarf_misaligned_value_t *mvp = (void *) (uintptr_t) *addr;
*val = mvp->u64;
*addr += sizeof (mvp->u64);
return 0;
}
static inline int
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
dwarf_misaligned_value_t *mvp = (void *) *addr;
*val = mvp->w;
*addr += sizeof (mvp->w);
return 0;
}
#else /* !UNW_LOCAL_ONLY */
static inline int
@ -263,25 +257,37 @@ dwarf_reads64 (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
return 0;
}
#endif /* !UNW_LOCAL_ONLY */
static inline int
dwarf_readw (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_word_t *val, void *arg)
{
switch (sizeof (unw_word_t))
uint32_t u32;
uint64_t u64;
int ret;
switch (dwarf_addr_size (as))
{
case 4:
return dwarf_readu32 (as, a, addr, (uint32_t *) val, arg);
ret = dwarf_readu32 (as, a, addr, &u32, arg);
if (ret < 0)
return ret;
*val = u32;
return ret;
case 8:
return dwarf_readu64 (as, a, addr, (uint64_t *) val, arg);
ret = dwarf_readu64 (as, a, addr, &u64, arg);
if (ret < 0)
return ret;
*val = u64;
return ret;
default:
abort ();
}
}
#endif /* !UNW_LOCAL_ONLY */
/* Read an unsigned "little-endian base 128" value. See Chapter 7.6
of DWARF spec v3. */
@ -360,7 +366,8 @@ dwarf_read_encoded_pointer_inlined (unw_addr_space_t as, unw_accessors_t *a,
}
else if (encoding == DW_EH_PE_aligned)
{
*addr = (initial_addr + sizeof (unw_word_t) - 1) & -sizeof (unw_word_t);
int size = dwarf_addr_size (as);
*addr = (initial_addr + size - 1) & -size;
return dwarf_readw (as, a, addr, valp, arg);
}
@ -459,6 +466,15 @@ dwarf_read_encoded_pointer_inlined (unw_addr_space_t as, unw_accessors_t *a,
return -UNW_EINVAL;
}
/* Trim off any extra bits. Assume that sign extension isn't
required; the only place it is needed is MIPS kernel space
addresses. */
if (sizeof (val) > dwarf_addr_size (as))
{
assert (dwarf_addr_size (as) == 4);
val = (uint32_t) val;
}
if (encoding & DW_EH_PE_indirect)
{
unw_word_t indirect_addr = val;

298
include/libunwind-arm.h Normal file
View file

@ -0,0 +1,298 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef LIBUNWIND_H
#define LIBUNWIND_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include <inttypes.h>
#include <ucontext.h>
#define UNW_TARGET arm
#define UNW_TARGET_ARM 1
#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */
/* This needs to be big enough to accommodate "struct cursor", while
leaving some slack for future expansion. Changing this value will
require recompiling all users of this library. Stack allocation is
relatively cheap and unwind-state copying is relatively rare, so we
want to err on making it rather too big than too small. */
/* FIXME for ARM. Too big? What do other things use for similar tasks? */
#define UNW_TDEP_CURSOR_LEN 4096
typedef uint32_t unw_word_t;
typedef int32_t unw_sword_t;
typedef long double unw_tdep_fpreg_t;
typedef enum
{
UNW_ARM_R0,
UNW_ARM_R1,
UNW_ARM_R2,
UNW_ARM_R3,
UNW_ARM_R4,
UNW_ARM_R5,
UNW_ARM_R6,
UNW_ARM_R7,
UNW_ARM_R8,
UNW_ARM_R9,
UNW_ARM_R10,
UNW_ARM_R11,
UNW_ARM_R12,
UNW_ARM_R13,
UNW_ARM_R14,
UNW_ARM_R15,
/* VFPv2 s0-s31 (obsolescent numberings). */
UNW_ARM_S0 = 64,
UNW_ARM_S1,
UNW_ARM_S2,
UNW_ARM_S3,
UNW_ARM_S4,
UNW_ARM_S5,
UNW_ARM_S6,
UNW_ARM_S7,
UNW_ARM_S8,
UNW_ARM_S9,
UNW_ARM_S10,
UNW_ARM_S11,
UNW_ARM_S12,
UNW_ARM_S13,
UNW_ARM_S14,
UNW_ARM_S15,
UNW_ARM_S16,
UNW_ARM_S17,
UNW_ARM_S18,
UNW_ARM_S19,
UNW_ARM_S20,
UNW_ARM_S21,
UNW_ARM_S22,
UNW_ARM_S23,
UNW_ARM_S24,
UNW_ARM_S25,
UNW_ARM_S26,
UNW_ARM_S27,
UNW_ARM_S28,
UNW_ARM_S29,
UNW_ARM_S30,
UNW_ARM_S31,
/* FPA register numberings. */
UNW_ARM_F0 = 96,
UNW_ARM_F1,
UNW_ARM_F2,
UNW_ARM_F3,
UNW_ARM_F4,
UNW_ARM_F5,
UNW_ARM_F6,
UNW_ARM_F7,
/* iWMMXt GR register numberings. */
UNW_ARM_wCGR0 = 104,
UNW_ARM_wCGR1,
UNW_ARM_wCGR2,
UNW_ARM_wCGR3,
UNW_ARM_wCGR4,
UNW_ARM_wCGR5,
UNW_ARM_wCGR6,
UNW_ARM_wCGR7,
/* iWMMXt register numberings. */
UNW_ARM_wR0 = 112,
UNW_ARM_wR1,
UNW_ARM_wR2,
UNW_ARM_wR3,
UNW_ARM_wR4,
UNW_ARM_wR5,
UNW_ARM_wR6,
UNW_ARM_wR7,
UNW_ARM_wR8,
UNW_ARM_wR9,
UNW_ARM_wR10,
UNW_ARM_wR11,
UNW_ARM_wR12,
UNW_ARM_wR13,
UNW_ARM_wR14,
UNW_ARM_wR15,
/* Two-byte encodings from here on. */
/* SPSR. */
UNW_ARM_SPSR = 128,
UNW_ARM_SPSR_FIQ,
UNW_ARM_SPSR_IRQ,
UNW_ARM_SPSR_ABT,
UNW_ARM_SPSR_UND,
UNW_ARM_SPSR_SVC,
/* User mode registers. */
UNW_ARM_R8_USR = 144,
UNW_ARM_R9_USR,
UNW_ARM_R10_USR,
UNW_ARM_R11_USR,
UNW_ARM_R12_USR,
UNW_ARM_R13_USR,
UNW_ARM_R14_USR,
/* FIQ registers. */
UNW_ARM_R8_FIQ = 151,
UNW_ARM_R9_FIQ,
UNW_ARM_R10_FIQ,
UNW_ARM_R11_FIQ,
UNW_ARM_R12_FIQ,
UNW_ARM_R13_FIQ,
UNW_ARM_R14_FIQ,
/* IRQ registers. */
UNW_ARM_R13_IRQ = 158,
UNW_ARM_R14_IRQ,
/* ABT registers. */
UNW_ARM_R13_ABT = 160,
UNW_ARM_R14_ABT,
/* UND registers. */
UNW_ARM_R13_UND = 162,
UNW_ARM_R14_UND,
/* SVC registers. */
UNW_ARM_R13_SVC = 164,
UNW_ARM_R14_SVC,
/* iWMMXt control registers. */
UNW_ARM_wC0 = 192,
UNW_ARM_wC1,
UNW_ARM_wC2,
UNW_ARM_wC3,
UNW_ARM_wC4,
UNW_ARM_wC5,
UNW_ARM_wC6,
UNW_ARM_wC7,
/* VFPv3/Neon 64-bit registers. */
UNW_ARM_D0 = 256,
UNW_ARM_D1,
UNW_ARM_D2,
UNW_ARM_D3,
UNW_ARM_D4,
UNW_ARM_D5,
UNW_ARM_D6,
UNW_ARM_D7,
UNW_ARM_D8,
UNW_ARM_D9,
UNW_ARM_D10,
UNW_ARM_D11,
UNW_ARM_D12,
UNW_ARM_D13,
UNW_ARM_D14,
UNW_ARM_D15,
UNW_ARM_D16,
UNW_ARM_D17,
UNW_ARM_D18,
UNW_ARM_D19,
UNW_ARM_D20,
UNW_ARM_D21,
UNW_ARM_D22,
UNW_ARM_D23,
UNW_ARM_D24,
UNW_ARM_D25,
UNW_ARM_D26,
UNW_ARM_D27,
UNW_ARM_D28,
UNW_ARM_D29,
UNW_ARM_D30,
UNW_ARM_D31,
/* For ARM, the CFA is the value of SP (r13) at the call site in the
previous frame. */
UNW_ARM_CFA,
UNW_TDEP_LAST_REG = UNW_ARM_D31,
UNW_TDEP_IP = UNW_ARM_R14, /* A little white lie. */
UNW_TDEP_SP = UNW_ARM_R13,
UNW_TDEP_EH = UNW_ARM_R0 /* FIXME. */
}
arm_regnum_t;
#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for ARM. */
typedef struct unw_tdep_save_loc
{
/* Additional target-dependent info on a save location. */
}
unw_tdep_save_loc_t;
/* On ARM, we can directly use ucontext_t as the unwind context. */
typedef ucontext_t unw_tdep_context_t;
/* There is no getcontext() on ARM. Use a stub version which only saves GP
registers. FIXME: Not ideal, may not be sufficient for all libunwind
use cases. Stores pc+8, which is only approximately correct, really. */
#ifndef __thumb__
#define unw_tdep_getcontext(uc) (({ \
unw_tdep_context_t *unw_ctx = (uc); \
register int unw_base asm ("r0") \
= (int) (&unw_ctx->uc_mcontext.arm_r0); \
__asm__ __volatile__ ( \
"stmia %[base], {r0-r15}" \
: : [base] "r" (unw_base) : "memory"); \
}), 0)
#else /* __thumb__ */
#define unw_tdep_getcontext(uc) (({ \
unw_tdep_context_t *unw_ctx = (uc); \
register int unw_base asm ("r0") \
= (int) (&unw_ctx->uc_mcontext.arm_r0); \
__asm__ __volatile__ ( \
".align 2\nbx pc\nnop\n.code 32\n" \
"stmia %[base], {r0-r15}\n" \
"orr %[base], pc, #1\nbx %[base]" \
: [base] "+r" (unw_base) : : "memory", "cc"); \
}), 0)
#endif
#include "libunwind-dynamic.h"
typedef struct
{
/* no arm-specific auxiliary proc-info */
}
unw_tdep_proc_info_t;
#include "libunwind-common.h"
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* LIBUNWIND_H */

155
include/libunwind-mips.h Normal file
View file

@ -0,0 +1,155 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef LIBUNWIND_H
#define LIBUNWIND_H
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include <inttypes.h>
#include <ucontext.h>
#ifdef mips
# undef mips
#endif
#define UNW_TARGET mips
#define UNW_TARGET_MIPS 1
#define _U_TDEP_QP_TRUE 0 /* see libunwind-dynamic.h */
/* This needs to be big enough to accommodate "struct cursor", while
leaving some slack for future expansion. Changing this value will
require recompiling all users of this library. Stack allocation is
relatively cheap and unwind-state copying is relatively rare, so we
want to err on making it rather too big than too small. */
/* 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. */
typedef uint64_t unw_word_t;
typedef int32_t unw_sword_t;
/* FIXME: MIPS ABIs. */
typedef long double unw_tdep_fpreg_t;
typedef enum
{
UNW_MIPS_R0,
UNW_MIPS_R1,
UNW_MIPS_R2,
UNW_MIPS_R3,
UNW_MIPS_R4,
UNW_MIPS_R5,
UNW_MIPS_R6,
UNW_MIPS_R7,
UNW_MIPS_R8,
UNW_MIPS_R9,
UNW_MIPS_R10,
UNW_MIPS_R11,
UNW_MIPS_R12,
UNW_MIPS_R13,
UNW_MIPS_R14,
UNW_MIPS_R15,
UNW_MIPS_R16,
UNW_MIPS_R17,
UNW_MIPS_R18,
UNW_MIPS_R19,
UNW_MIPS_R20,
UNW_MIPS_R21,
UNW_MIPS_R22,
UNW_MIPS_R23,
UNW_MIPS_R24,
UNW_MIPS_R25,
UNW_MIPS_R26,
UNW_MIPS_R27,
UNW_MIPS_R28,
UNW_MIPS_R29,
UNW_MIPS_R30,
UNW_MIPS_R31,
/* FIXME: Other registers! */
/* For MIPS, the CFA is the value of SP (r29) at the call site in the
previous frame. */
UNW_MIPS_CFA,
UNW_TDEP_LAST_REG = UNW_MIPS_R31,
UNW_TDEP_IP = UNW_MIPS_R31,
UNW_TDEP_SP = UNW_MIPS_R29,
UNW_TDEP_EH = UNW_MIPS_R0 /* FIXME. */
}
mips_regnum_t;
typedef enum
{
UNW_MIPS_ABI_O32,
UNW_MIPS_ABI_N32,
UNW_MIPS_ABI_N64
}
mips_abi_t;
#define UNW_TDEP_NUM_EH_REGS 2 /* FIXME for MIPS. */
typedef struct unw_tdep_save_loc
{
/* Additional target-dependent info on a save location. */
}
unw_tdep_save_loc_t;
/* On x86, we can directly use ucontext_t as the unwind context. FIXME for
MIPS. */
typedef ucontext_t unw_tdep_context_t;
#include "libunwind-dynamic.h"
typedef struct
{
/* no mips-specific auxiliary proc-info */
}
unw_tdep_proc_info_t;
#include "libunwind-common.h"
/* There is no getcontext() on MIPS. Use a stub version which only saves GP
registers. FIXME: Not ideal, may not be sufficient for all libunwind
use cases. */
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
extern int unw_tdep_getcontext (ucontext_t *uc);
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
extern int unw_tdep_is_fpreg (int);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* LIBUNWIND_H */

View file

@ -11,7 +11,7 @@ static inline int
fetch8 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int8_t *valp, void *arg)
{
*valp = *(int8_t *) *addr;
*valp = *(int8_t *) (uintptr_t) *addr;
*addr += 1;
return 0;
}
@ -20,7 +20,7 @@ static inline int
fetch16 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int16_t *valp, void *arg)
{
*valp = *(int16_t *) *addr;
*valp = *(int16_t *) (uintptr_t) *addr;
*addr += 2;
return 0;
}
@ -29,7 +29,7 @@ static inline int
fetch32 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int32_t *valp, void *arg)
{
*valp = *(int32_t *) *addr;
*valp = *(int32_t *) (uintptr_t) *addr;
*addr += 4;
return 0;
}
@ -38,7 +38,7 @@ static inline int
fetchw (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_word_t *valp, void *arg)
{
*valp = *(unw_word_t *) *addr;
*valp = *(unw_word_t *) (uintptr_t) *addr;
*addr += sizeof (unw_word_t);
return 0;
}

View file

@ -0,0 +1,51 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef dwarf_config_h
#define dwarf_config_h
/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not
explicitly defined. */
#define DWARF_NUM_PRESERVED_REGS 128
/* FIXME: Probably unnecessary on ARM. See arm/Gglobal.c. */
#define DWARF_REGNUM_MAP_LENGTH 16
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
#define dwarf_is_big_endian(addr_space) 0
/* Convert a pointer to a dwarf_cursor structure to a pointer to
unw_cursor_t. */
#define dwarf_to_cursor(c) ((unw_cursor_t *) (c))
typedef struct dwarf_loc
{
unw_word_t val;
#ifndef UNW_LOCAL_ONLY
unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */
#endif
}
dwarf_loc_t;
#endif /* dwarf_config_h */

32
include/tdep-arm/jmpbuf.h Normal file
View file

@ -0,0 +1,32 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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. */
/* Use glibc's jump-buffer indices; NPTL peeks at SP: */
/* FIXME for ARM! */
#define JB_SP 4
#define JB_RP 5
#define JB_MASK_SAVED 6
#define JB_MASK 7

View file

@ -0,0 +1,254 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef ARM_LIBUNWIND_I_H
#define ARM_LIBUNWIND_I_H
/* Target-dependent definitions that are internal to libunwind but need
to be shared with target-independent code. */
#include <stdlib.h>
#include <libunwind.h>
#include "elf32.h"
#include "mempool.h"
#include "dwarf.h"
struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
#else
uint32_t cache_generation;
#endif
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
};
struct cursor
{
struct dwarf_cursor dwarf; /* must be first */
unw_word_t sigcontext_addr;
};
#define DWARF_GET_LOC(l) ((l).val)
#ifdef UNW_LOCAL_ONLY
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0)
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) })
# define DWARF_IS_REG_LOC(l) 0
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(unw_fpreg_t *) DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(unw_fpreg_t *) DWARF_GET_LOC (loc) = val;
return 0;
}
static inline int
dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(unw_word_t *) DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(unw_word_t *) DWARF_GET_LOC (loc) = val;
return 0;
}
#else /* !UNW_LOCAL_ONLY */
# define DWARF_LOC_TYPE_FP (1 << 0)
# define DWARF_LOC_TYPE_REG (1 << 1)
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) \
({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; })
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) })
# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0)
# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0)
# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG)
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \
| DWARF_LOC_TYPE_FP))
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
char *valp = (char *) &val;
unw_word_t addr;
int ret;
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
val, 0, c->as_arg);
addr = DWARF_GET_LOC (loc);
if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp,
0, c->as_arg)) < 0)
return ret;
return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0,
c->as_arg);
}
static inline int
dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
char *valp = (char *) &val;
unw_word_t addr;
int ret;
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
&val, 1, c->as_arg);
addr = DWARF_GET_LOC (loc);
if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp,
1, c->as_arg)) < 0)
return ret;
return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1,
1, c->as_arg);
}
static inline int
dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
/* If a code-generator were to save a value of type unw_word_t in a
floating-point register, we would have to support this case. I
suppose it could happen with MMX registers, but does it really
happen? */
assert (!DWARF_IS_FP_LOC (loc));
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
else
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
}
static inline int
dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
/* If a code-generator were to save a value of type unw_word_t in a
floating-point register, we would have to support this case. I
suppose it could happen with MMX registers, but does it really
happen? */
assert (!DWARF_IS_FP_LOC (loc));
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
else
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
}
#endif /* !UNW_LOCAL_ONLY */
#define tdep_needs_initialization UNW_OBJ(needs_initialization)
#define tdep_init UNW_OBJ(init)
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
#define tdep_search_unwind_table dwarf_search_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg)
#ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \
dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
dwarf_put_unwind_info((as), (pi), (arg))
#else
# define tdep_find_proc_info(c,ip,n) \
(*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
(*(as)->acc.put_unwind_info)((as), (pi), (arg))
#endif
#define tdep_get_as(c) ((c)->dwarf.as)
#define tdep_get_as_arg(c) ((c)->dwarf.as_arg)
#define tdep_get_ip(c) ((c)->dwarf.ip)
#define tdep_big_endian(as) ((as)->big_endian)
extern int tdep_needs_initialization;
extern void tdep_init (void);
extern 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);
extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff);
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,
unw_fpreg_t *valp, int write);
#endif /* ARM_LIBUNWIND_I_H */

View file

@ -46,6 +46,7 @@ struct unw_addr_space
#endif
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct unw_debug_frame_list *debug_frames;
};
struct cursor

View file

@ -0,0 +1,54 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef dwarf_config_h
#define dwarf_config_h
/* This is FIRST_PSEUDO_REGISTER in GCC, since DWARF_FRAME_REGISTERS is not
explicitly defined. */
#define DWARF_NUM_PRESERVED_REGS 188
/* FIXME: Probably unnecessary on MIPS. See mips/Gglobal.c. */
#define DWARF_REGNUM_MAP_LENGTH 32
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian)
/* Return the size of an address, for DWARF purposes. */
#define dwarf_addr_size(addr_space) ((addr_space)->addr_size)
/* Convert a pointer to a dwarf_cursor structure to a pointer to
unw_cursor_t. */
#define dwarf_to_cursor(c) ((unw_cursor_t *) (c))
typedef struct dwarf_loc
{
unw_word_t val;
#ifndef UNW_LOCAL_ONLY
unw_word_t type; /* see DWARF_LOC_TYPE_* macros. */
#endif
}
dwarf_loc_t;
#endif /* dwarf_config_h */

View file

@ -0,0 +1,32 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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. */
/* Use glibc's jump-buffer indices; NPTL peeks at SP: */
/* FIXME for MIPS! */
#define JB_SP 4
#define JB_RP 5
#define JB_MASK_SAVED 6
#define JB_MASK 7

View file

@ -0,0 +1,315 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef MIPS_LIBUNWIND_I_H
#define MIPS_LIBUNWIND_I_H
/* Target-dependent definitions that are internal to libunwind but need
to be shared with target-independent code. */
#include <stdlib.h>
#include <libunwind.h>
#if !defined(UNW_REMOTE_ONLY) && _MIPS_SIM == _ABI64
# include "elf64.h"
#else
# include "elf32.h"
#endif
#include "mempool.h"
#include "dwarf.h"
struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
mips_abi_t abi;
unsigned int addr_size;
unw_caching_policy_t caching_policy;
#ifdef HAVE_ATOMIC_OPS_H
AO_t cache_generation;
#else
uint32_t cache_generation;
#endif
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
};
#define tdep_big_endian(as) ((as)->big_endian)
struct cursor
{
struct dwarf_cursor dwarf; /* must be first */
unw_word_t sigcontext_addr;
};
#define DWARF_GET_LOC(l) ((l).val)
#ifndef UNW_REMOTE_ONLY
# if _MIPS_SIM == _ABIN32
typedef long long mips_reg_t;
# else
typedef long mips_reg_t;
# endif
#endif
#ifdef UNW_LOCAL_ONLY
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) (DWARF_GET_LOC (l) == 0)
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r) })
# define DWARF_IS_REG_LOC(l) 0
# define DWARF_REG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
# define DWARF_FPREG_LOC(c,r) (DWARF_LOC((unw_word_t) (intptr_t) \
tdep_uc_addr((c)->as_arg, (r)), 0))
/* FIXME: Implement these for the MIPS FPU. */
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(unw_fpreg_t *) (intptr_t) DWARF_GET_LOC (loc) = val;
return 0;
}
static inline int
dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*val = *(mips_reg_t *) (intptr_t) DWARF_GET_LOC (loc);
return 0;
}
static inline int
dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
if (!DWARF_GET_LOC (loc))
return -1;
*(mips_reg_t *) (intptr_t) DWARF_GET_LOC (loc) = val;
return 0;
}
#else /* !UNW_LOCAL_ONLY */
# define DWARF_LOC_TYPE_FP (1 << 0)
# define DWARF_LOC_TYPE_REG (1 << 1)
# define DWARF_NULL_LOC DWARF_LOC (0, 0)
# define DWARF_IS_NULL_LOC(l) \
({ dwarf_loc_t _l = (l); _l.val == 0 && _l.type == 0; })
# define DWARF_LOC(r, t) ((dwarf_loc_t) { .val = (r), .type = (t) })
# define DWARF_IS_REG_LOC(l) (((l).type & DWARF_LOC_TYPE_REG) != 0)
# define DWARF_IS_FP_LOC(l) (((l).type & DWARF_LOC_TYPE_FP) != 0)
# define DWARF_REG_LOC(c,r) DWARF_LOC((r), DWARF_LOC_TYPE_REG)
# define DWARF_MEM_LOC(c,m) DWARF_LOC ((m), 0)
# define DWARF_FPREG_LOC(c,r) DWARF_LOC((r), (DWARF_LOC_TYPE_REG \
| DWARF_LOC_TYPE_FP))
static inline int
read_s32 (struct dwarf_cursor *c, unw_word_t addr, unw_word_t *val)
{
int offset = addr & 4;
int ret;
unw_word_t memval;
ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg);
if (ret < 0)
return ret;
if ((offset != 0) == tdep_big_endian (c->as))
*val = (int32_t) memval;
else
*val = (int32_t) (memval >> 32);
return 0;
}
static inline int
write_s32 (struct dwarf_cursor *c, unw_word_t addr, const unw_word_t *val)
{
int offset = addr & 4;
int ret;
unw_word_t memval;
ret = (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 0, c->as_arg);
if (ret < 0)
return ret;
if ((offset != 0) == tdep_big_endian (c->as))
memval = (memval & ~0xffffffffLL) | (uint32_t) *val;
else
memval = (memval & 0xffffffffLL) | (uint32_t) (*val << 32);
return (*c->as->acc.access_mem) (c->as, addr - offset, &memval, 1, c->as_arg);
}
/* FIXME: Implement these for the MIPS FPU. */
static inline int
dwarf_getfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t *val)
{
char *valp = (char *) &val;
unw_word_t addr;
int ret;
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
val, 0, c->as_arg);
addr = DWARF_GET_LOC (loc);
if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp,
0, c->as_arg)) < 0)
return ret;
return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1, 0,
c->as_arg);
}
static inline int
dwarf_putfp (struct dwarf_cursor *c, dwarf_loc_t loc, unw_fpreg_t val)
{
char *valp = (char *) &val;
unw_word_t addr;
int ret;
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_fpreg) (c->as, DWARF_GET_LOC (loc),
&val, 1, c->as_arg);
addr = DWARF_GET_LOC (loc);
if ((ret = (*c->as->acc.access_mem) (c->as, addr + 0, (unw_word_t *) valp,
1, c->as_arg)) < 0)
return ret;
return (*c->as->acc.access_mem) (c->as, addr + 4, (unw_word_t *) valp + 1,
1, c->as_arg);
}
static inline int
dwarf_get (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t *val)
{
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
/* If a code-generator were to save a value of type unw_word_t in a
floating-point register, we would have to support this case. I
suppose it could happen with MMX registers, but does it really
happen? */
assert (!DWARF_IS_FP_LOC (loc));
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
else if (c->as->abi == UNW_MIPS_ABI_O32)
return read_s32 (c, DWARF_GET_LOC (loc), val);
else
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), val,
0, c->as_arg);
}
static inline int
dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
{
if (DWARF_IS_NULL_LOC (loc))
return -UNW_EBADREG;
/* If a code-generator were to save a value of type unw_word_t in a
floating-point register, we would have to support this case. I
suppose it could happen with MMX registers, but does it really
happen? */
assert (!DWARF_IS_FP_LOC (loc));
if (DWARF_IS_REG_LOC (loc))
return (*c->as->acc.access_reg) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
else if (c->as->abi == UNW_MIPS_ABI_O32)
return write_s32 (c, DWARF_GET_LOC (loc), &val);
else
return (*c->as->acc.access_mem) (c->as, DWARF_GET_LOC (loc), &val,
1, c->as_arg);
}
#endif /* !UNW_LOCAL_ONLY */
#define tdep_needs_initialization UNW_OBJ(needs_initialization)
#define tdep_init UNW_OBJ(init)
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
#define tdep_search_unwind_table dwarf_search_unwind_table
#define tdep_uc_addr UNW_ARCH_OBJ(uc_addr)
#define tdep_get_elf_image UNW_ARCH_OBJ(get_elf_image)
#define tdep_access_reg UNW_OBJ(access_reg)
#define tdep_access_fpreg UNW_OBJ(access_fpreg)
#ifdef UNW_LOCAL_ONLY
# define tdep_find_proc_info(c,ip,n) \
dwarf_find_proc_info((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
dwarf_put_unwind_info((as), (pi), (arg))
#else
# define tdep_find_proc_info(c,ip,n) \
(*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \
(c)->as_arg)
# define tdep_put_unwind_info(as,pi,arg) \
(*(as)->acc.put_unwind_info)((as), (pi), (arg))
#endif
#define tdep_get_as(c) ((c)->dwarf.as)
#define tdep_get_as_arg(c) ((c)->dwarf.as_arg)
#define tdep_get_ip(c) ((c)->dwarf.ip)
extern int tdep_needs_initialization;
extern void tdep_init (void);
extern 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);
extern void *tdep_uc_addr (ucontext_t *uc, int reg);
extern int tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
unsigned long *segbase, unsigned long *mapoff);
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,
unw_fpreg_t *valp, int write);
#endif /* MIPS_LIBUNWIND_I_H */

View file

@ -54,6 +54,7 @@ struct unw_addr_space
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
int validate;
};

View file

@ -54,6 +54,7 @@ struct unw_addr_space
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
int validate;
};

View file

@ -48,6 +48,7 @@ struct unw_addr_space
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
};
struct cursor

View file

@ -50,6 +50,7 @@ struct unw_addr_space
unw_word_t dyn_generation; /* see dyn-common.h */
unw_word_t dyn_info_list_addr; /* (cached) dyn_info_list_addr */
struct dwarf_rs_cache global_cache;
struct unw_debug_frame_list *debug_frames;
int validate;
};

View file

@ -33,9 +33,11 @@ libunwind_setjmp_la_LIBADD = libunwind-$(arch).la -lc
libunwind_setjmp_la_SOURCES_common = setjmp/setjmp_i.h \
setjmp/longjmp.c \
setjmp/siglongjmp.c
libunwind_setjmp_la_SOURCES_arm = arm/siglongjmp.S
libunwind_setjmp_la_SOURCES_ia64 = ia64/setjmp.S ia64/sigsetjmp.S \
ia64/longjmp.S ia64/siglongjmp.S
libunwind_setjmp_la_SOURCES_hppa = hppa/siglongjmp.S
libunwind_setjmp_la_SOURCES_mips = mips/siglongjmp.S
libunwind_setjmp_la_SOURCES_x86 = x86/longjmp.S x86/siglongjmp.S
libunwind_setjmp_la_SOURCES_x86_64 = x86_64/longjmp.S x86_64/siglongjmp.S
libunwind_setjmp_la_SOURCES_ppc64 = ppc/longjmp.S ppc/siglongjmp.S
@ -59,8 +61,17 @@ libunwind_la_SOURCES_generic = \
mi/Gget_fpreg.c mi/Gset_fpreg.c \
mi/Gset_caching_policy.c
libunwind_la_SOURCES_local_unwind = \
unwind/Backtrace.c unwind/DeleteException.c \
unwind/FindEnclosingFunction.c unwind/ForcedUnwind.c \
unwind/GetBSP.c unwind/GetCFA.c unwind/GetDataRelBase.c \
unwind/GetGR.c unwind/GetIP.c unwind/GetLanguageSpecificData.c \
unwind/GetRegionStart.c unwind/GetTextRelBase.c \
unwind/RaiseException.c unwind/Resume.c \
unwind/Resume_or_Rethrow.c unwind/SetGR.c unwind/SetIP.c
# List of arch-independent files needed by local-only library (libunwind):
libunwind_la_SOURCES_local = \
libunwind_la_SOURCES_local_nounwind = \
$(libunwind_la_SOURCES_os_local) \
mi/backtrace.c \
mi/dyn-cancel.c mi/dyn-info-list.c mi/dyn-register.c \
@ -70,14 +81,23 @@ libunwind_la_SOURCES_local = \
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 \
unwind/Backtrace.c unwind/DeleteException.c \
unwind/FindEnclosingFunction.c unwind/ForcedUnwind.c \
unwind/GetBSP.c unwind/GetCFA.c unwind/GetDataRelBase.c \
unwind/GetGR.c unwind/GetIP.c unwind/GetLanguageSpecificData.c \
unwind/GetRegionStart.c unwind/GetTextRelBase.c \
unwind/RaiseException.c unwind/Resume.c \
unwind/Resume_or_Rethrow.c unwind/SetGR.c unwind/SetIP.c
mi/Lset_caching_policy.c
# On some platforms, defining _Unwind replacements really upsets
# exception-handling. Turn off those functions for those platforms.
if ARCH_ARM
libunwind_la_SOURCES_local = \
$(libunwind_la_SOURCES_local_nounwind)
else
if ARCH_MIPS
libunwind_la_SOURCES_local = \
$(libunwind_la_SOURCES_local_nounwind)
else
libunwind_la_SOURCES_local = \
$(libunwind_la_SOURCES_local_nounwind) \
$(libunwind_la_SOURCES_local_unwind)
endif # ARCH_MIPS
endif # ARCH_ARM
libunwind_la_SOURCES_os_linux = os-linux.h os-linux.c
@ -94,6 +114,31 @@ dwarf_SOURCES_local = \
dwarf_SOURCES_generic = \
dwarf/Gexpr.c dwarf/Gfde.c dwarf/Gparser.c dwarf/Gpe.c dwarf/Gstep.c
# The list of files that go info libunwind and libunwind-arm:
libunwind_la_SOURCES_arm_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \
elf32.c elf32.h \
arm/init.h arm/offsets.h arm/regs.h \
arm/is_fpreg.c arm/regname.c
# The list of files that go into libunwind:
libunwind_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
$(libunwind_la_SOURCES_local) \
arm/getcontext.S \
$(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.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
libunwind_arm_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
$(libunwind_la_SOURCES_generic) \
$(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.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
# The list of files that go both into libunwind and libunwind-ia64:
libunwind_la_SOURCES_ia64_common = $(libunwind_la_SOURCES_common) \
elf64.c elf64.h \
@ -150,6 +195,31 @@ libunwind_hppa_la_SOURCES_hppa = $(libunwind_la_SOURCES_hppa_common) \
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:
libunwind_la_SOURCES_mips_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \
elfxx.c \
mips/init.h mips/offsets.h mips/regs.h \
mips/is_fpreg.c mips/regname.c
# The list of files that go into libunwind:
libunwind_la_SOURCES_mips = $(libunwind_la_SOURCES_mips_common) \
$(libunwind_la_SOURCES_local) \
mips/getcontext.S \
$(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.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) \
$(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.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 both into libunwind and libunwind-x86:
libunwind_la_SOURCES_x86_common = $(libunwind_la_SOURCES_common) \
$(dwarf_SOURCES_common) \
@ -289,6 +359,17 @@ if OS_HPUX
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_hpux_local)
endif
if ARCH_ARM
lib_LTLIBRARIES_arch = libunwind-arm.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_arm)
libunwind_arm_la_SOURCES = $(libunwind_arm_la_SOURCES_arm)
libunwind_arm_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION)
if !REMOTE_ONLY
libunwind_arm_la_LIBADD = libunwind.la -lc
endif
libunwind_setjmp_la_SOURCES = $(libunwind_setjmp_la_SOURCES_common) \
$(libunwind_setjmp_la_SOURCES_arm)
else
if ARCH_IA64
ia64_mk_Gcursor_i_SOURCES = ia64/mk_Gcursor_i.c
ia64_mk_Lcursor_i_SOURCES = ia64/mk_Lcursor_i.c
@ -319,6 +400,17 @@ endif
libunwind_setjmp_la_SOURCES = $(libunwind_setjmp_la_SOURCES_common) \
$(libunwind_setjmp_la_SOURCES_hppa)
else
if ARCH_MIPS
lib_LTLIBRARIES_arch = libunwind-mips.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_mips)
libunwind_mips_la_SOURCES = $(libunwind_mips_la_SOURCES_mips)
libunwind_mips_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -version-info $(SOVERSION)
if !REMOTE_ONLY
libunwind_mips_la_LIBADD = libunwind.la -lc
endif
libunwind_setjmp_la_SOURCES = $(libunwind_setjmp_la_SOURCES_common) \
$(libunwind_setjmp_la_SOURCES_mips)
else
if ARCH_X86
lib_LTLIBRARIES_arch = libunwind-x86.la
libunwind_la_SOURCES = $(libunwind_la_SOURCES_x86)
@ -367,8 +459,10 @@ endif # ARCH_PPC64
endif # ARCH_PPC32
endif # ARCH_X86_64
endif # ARCH_X86
endif # ARCH_MIPS
endif # ARCH_HPPA
endif # ARCH_IA64
endif # ARCH_ARM
#
# Don't link with standard libraries, because those may mention
@ -386,22 +480,28 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/tdep-$(arch) -I.
AM_CCASFLAGS = $(AM_CPPFLAGS)
EXTRA_DIST = elfxx.h elfxx.c unwind/unwind-internal.h \
$(libunwind_la_SOURCES_arm) \
$(libunwind_la_SOURCES_hppa) \
$(libunwind_la_SOURCES_ia64) \
$(libunwind_la_SOURCES_mips) \
$(libunwind_la_SOURCES_x86) \
$(libunwind_la_SOURCES_os_linux) \
$(libunwind_la_SOURCES_os_hpux) \
$(libunwind_la_SOURCES_common) \
$(libunwind_la_SOURCES_local) \
$(libunwind_la_SOURCES_generic) \
$(libunwind_arm_la_SOURCES_arm) \
$(libunwind_hppa_la_SOURCES_hppa) \
$(libunwind_ia64_la_SOURCES_ia64) \
$(libunwind_mips_la_SOURCES_mips) \
$(libunwind_x86_la_SOURCES_x86) \
$(libunwind_x86_64_la_SOURCES_x86_64) \
$(libunwind_ptrace_a_SOURCES) \
$(libunwind_setjmp_la_SOURCES_common) \
$(libunwind_setjmp_la_SOURCES_arm) \
$(libunwind_setjmp_la_SOURCES_hppa) \
$(libunwind_setjmp_la_SOURCES_ia64) \
$(libunwind_setjmp_la_SOURCES_mips) \
$(libunwind_setjmp_la_SOURCES_x86) \
$(libunwind_setjmp_la_SOURCES_x86_64) \
$(libunwind_setjmp_la_SOURCES_ppc32) \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 <stdlib.h>
#include "unwind_i.h"
PROTECTED unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
return NULL;
#else
unw_addr_space_t as = malloc (sizeof (*as));
if (!as)
return NULL;
memset (as, 0, sizeof (*as));
as->acc = *a;
/*
* ARM supports little-endian and big-endian.
*/
if (byte_order != 0 && byte_order != __LITTLE_ENDIAN
&& byte_order != __BIG_ENDIAN)
return NULL;
/* Default to little-endian for ARM. */
if (byte_order == 0 || byte_order == __LITTLE_ENDIAN)
as->big_endian = 0;
else
as->big_endian = 1;
return as;
#endif
}

41
src/arm/Gget_proc_info.c Normal file
View file

@ -0,0 +1,41 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
/* We can only unwind using Dwarf into on ARM: return failure code
if it's not present. */
ret = dwarf_make_proc_info (&c->dwarf);
if (ret < 0)
return ret;
*pi = c->dwarf.pi;
return 0;
}

81
src/arm/Gget_save_loc.c Normal file
View file

@ -0,0 +1,81 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
dwarf_loc_t loc;
loc = DWARF_NULL_LOC; /* default to "not saved" */
switch (reg)
{
case UNW_ARM_R0:
case UNW_ARM_R1:
case UNW_ARM_R2:
case UNW_ARM_R3:
case UNW_ARM_R4:
case UNW_ARM_R5:
case UNW_ARM_R6:
case UNW_ARM_R7:
case UNW_ARM_R8:
case UNW_ARM_R9:
case UNW_ARM_R10:
case UNW_ARM_R11:
case UNW_ARM_R12:
case UNW_ARM_R13:
case UNW_ARM_R14:
case UNW_ARM_R15:
loc = c->dwarf.loc[reg - UNW_ARM_R0];
break;
default:
break;
}
memset (sloc, 0, sizeof (sloc));
if (DWARF_IS_NULL_LOC (loc))
{
sloc->type = UNW_SLT_NONE;
return 0;
}
#if !defined(UNW_LOCAL_ONLY)
if (DWARF_IS_REG_LOC (loc))
{
sloc->type = UNW_SLT_REG;
sloc->u.regnum = DWARF_GET_LOC (loc);
}
else
#endif
{
sloc->type = UNW_SLT_MEMORY;
sloc->u.addr = DWARF_GET_LOC (loc);
}
return 0;
}

66
src/arm/Gglobal.c Normal file
View file

@ -0,0 +1,66 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 <ucontext.h>
#include "unwind_i.h"
#include "dwarf_i.h"
HIDDEN pthread_mutex_t arm_lock = PTHREAD_MUTEX_INITIALIZER;
HIDDEN int tdep_needs_initialization = 1;
/* FIXME: I'm pretty sure we don't need this at all for ARM, but "generic"
code (include/dwarf_i.h) seems to expect it to be here at present. */
HIDDEN uint8_t dwarf_to_unw_regnum_map[16] =
{
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15
};
HIDDEN void
tdep_init (void)
{
intrmask_t saved_mask;
sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask);
mutex_lock (&arm_lock);
{
if (!tdep_needs_initialization)
/* another thread else beat us to it... */
goto out;
mi_init ();
dwarf_init ();
#ifndef UNW_REMOTE_ONLY
arm_local_addr_space_init ();
#endif
tdep_needs_initialization = 0; /* signal that we're initialized... */
}
out:
mutex_unlock (&arm_lock);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
}

207
src/arm/Ginit.c Normal file
View file

@ -0,0 +1,207 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 <stdlib.h>
#include <string.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;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_ARM_R0: addr = &uc->uc_mcontext.arm_r0; break;
case UNW_ARM_R1: addr = &uc->uc_mcontext.arm_r1; break;
case UNW_ARM_R2: addr = &uc->uc_mcontext.arm_r2; break;
case UNW_ARM_R3: addr = &uc->uc_mcontext.arm_r3; break;
case UNW_ARM_R4: addr = &uc->uc_mcontext.arm_r4; break;
case UNW_ARM_R5: addr = &uc->uc_mcontext.arm_r5; break;
case UNW_ARM_R6: addr = &uc->uc_mcontext.arm_r6; break;
case UNW_ARM_R7: addr = &uc->uc_mcontext.arm_r7; break;
case UNW_ARM_R8: addr = &uc->uc_mcontext.arm_r8; break;
case UNW_ARM_R9: addr = &uc->uc_mcontext.arm_r9; break;
case UNW_ARM_R10: addr = &uc->uc_mcontext.arm_r10; break;
case UNW_ARM_R11: addr = &uc->uc_mcontext.arm_fp; break;
case UNW_ARM_R12: addr = &uc->uc_mcontext.arm_ip; break;
case UNW_ARM_R13: addr = &uc->uc_mcontext.arm_sp; break;
case UNW_ARM_R14: addr = &uc->uc_mcontext.arm_lr; break;
case UNW_ARM_R15: addr = &uc->uc_mcontext.arm_pc; break;
default:
addr = NULL;
}
return addr;
}
# ifdef UNW_LOCAL_ONLY
HIDDEN void *
tdep_uc_addr (ucontext_t *uc, int reg)
{
return uc_addr (uc, reg);
}
# endif /* UNW_LOCAL_ONLY */
HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
/* XXX fix me: there is currently no way to locate the dyn-info list
by a remote unwinder. On ia64, this is done via a special
unwind-table entry. Perhaps something similar can be done with
DWARF2 unwind info. */
static void
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
{
/* it's a no-op */
}
static int
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
void *arg)
{
*dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
return 0;
}
static int
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
void *arg)
{
if (write)
{
Debug (16, "mem[%x] <- %x\n", addr, *val);
*(unw_word_t *) addr = *val;
}
else
{
*val = *(unw_word_t *) addr;
Debug (16, "mem[%x] -> %x\n", addr, *val);
}
return 0;
}
static int
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
void *arg)
{
unw_word_t *addr;
ucontext_t *uc = arg;
if (unw_is_fpreg (reg))
goto badreg;
Debug (16, "reg = %s\n", unw_regname (reg));
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
*(unw_word_t *) addr = *val;
Debug (12, "%s <- %x\n", unw_regname (reg), *val);
}
else
{
*val = *(unw_word_t *) addr;
Debug (12, "%s -> %x\n", unw_regname (reg), *val);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
static int
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
ucontext_t *uc = arg;
unw_fpreg_t *addr;
if (!unw_is_fpreg (reg))
goto badreg;
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
*(unw_fpreg_t *) addr = *val;
}
else
{
*val = *(unw_fpreg_t *) addr;
Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
/* attempt to access a non-preserved register */
return -UNW_EBADREG;
}
static int
get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp,
void *arg)
{
return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp);
}
HIDDEN void
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.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;
local_addr_space.acc.access_mem = access_mem;
local_addr_space.acc.access_reg = access_reg;
local_addr_space.acc.access_fpreg = access_fpreg;
local_addr_space.acc.resume = 0; /* arm_local_resume? FIXME! */
local_addr_space.acc.get_proc_name = get_static_proc_name;
unw_flush_cache (&local_addr_space, 0, 0);
}
#endif /* !UNW_REMOTE_ONLY */

53
src/arm/Ginit_local.c Normal file
View file

@ -0,0 +1,53 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "init.h"
#ifdef UNW_REMOTE_ONLY
PROTECTED 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)
{
struct cursor *c = (struct cursor *) cursor;
if (tdep_needs_initialization)
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
return common_init (c);
}
#endif /* !UNW_REMOTE_ONLY */

45
src/arm/Ginit_remote.c Normal file
View file

@ -0,0 +1,45 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 "init.h"
#include "unwind_i.h"
PROTECTED int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
return -UNW_EINVAL;
#else /* !UNW_LOCAL_ONLY */
struct cursor *c = (struct cursor *) cursor;
if (tdep_needs_initialization)
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = as;
c->dwarf.as_arg = as_arg;
return common_init (c);
#endif /* !UNW_LOCAL_ONLY */
}

View file

@ -0,0 +1,35 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
/* FIXME for ARM. */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
}

81
src/arm/Gregs.c Normal file
View file

@ -0,0 +1,81 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
HIDDEN int
tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write)
{
dwarf_loc_t loc = DWARF_NULL_LOC;
switch (reg)
{
case UNW_ARM_R0:
case UNW_ARM_R1:
case UNW_ARM_R2:
case UNW_ARM_R3:
case UNW_ARM_R4:
case UNW_ARM_R5:
case UNW_ARM_R6:
case UNW_ARM_R7:
case UNW_ARM_R8:
case UNW_ARM_R9:
case UNW_ARM_R10:
case UNW_ARM_R11:
case UNW_ARM_R12:
case UNW_ARM_R13:
case UNW_ARM_R14:
case UNW_ARM_R15:
loc = c->dwarf.loc[reg - UNW_ARM_R0];
break;
case UNW_ARM_CFA:
if (write)
return -UNW_EREADONLYREG;
*valp = c->dwarf.cfa;
return 0;
/* FIXME: Initialise coprocessor & shadow registers? */
default:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
if (write)
return dwarf_put (&c->dwarf, loc, *valp);
else
return dwarf_get (&c->dwarf, loc, valp);
}
/* FIXME for ARM. */
HIDDEN int
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;
}

45
src/arm/Gresume.c Normal file
View file

@ -0,0 +1,45 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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. */
/* FIXME for ARM. */
#include <stdlib.h>
#include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY
HIDDEN inline int
arm_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
return -UNW_EINVAL;
}
#endif /* !UNW_REMOTE_ONLY */
PROTECTED int
unw_resume (unw_cursor_t *cursor)
{
return -UNW_EINVAL;
}

48
src/arm/Gstep.c Normal file
View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
Debug (1, "(cursor=%p)\n", c);
/* Try DWARF-based unwinding... this is the only method likely to work for
ARM. */
ret = dwarf_step (&c->dwarf);
if (unlikely (ret == -UNW_ESTOPUNWIND))
return ret;
/* Dwarf unwinding didn't work, stop. */
if (unlikely (ret < 0))
return 0;
return (c->dwarf.ip == 0) ? 0 : 1;
}

View file

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

5
src/arm/Lget_proc_info.c Normal file
View file

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

5
src/arm/Lget_save_loc.c Normal file
View file

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

5
src/arm/Lglobal.c Normal file
View file

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

5
src/arm/Linit.c Normal file
View file

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

5
src/arm/Linit_local.c Normal file
View file

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

5
src/arm/Linit_remote.c Normal file
View file

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

View file

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

5
src/arm/Lregs.c Normal file
View file

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

5
src/arm/Lresume.c Normal file
View file

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

5
src/arm/Lstep.c Normal file
View file

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

54
src/arm/gen-offsets.c Normal file
View file

@ -0,0 +1,54 @@
#include <stdio.h>
#include <stddef.h>
#include <ucontext.h>
#include <asm/sigcontext.h>
#define UC(N,X) \
printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X))
#define SC(N,X) \
printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X))
int
main (void)
{
printf (
"/* Linux-specific definitions: */\n\n"
"/* Define various structure offsets to simplify cross-compilation. */\n\n"
"/* Offsets for ARM Linux \"ucontext_t\": */\n\n");
UC ("FLAGS", uc_flags);
UC ("LINK", uc_link);
UC ("STACK", uc_stack);
UC ("MCONTEXT", uc_mcontext);
UC ("SIGMASK", uc_sigmask);
UC ("REGSPACE", uc_regspace);
printf ("\n/* Offsets for ARM Linux \"struct sigcontext\": */\n\n");
SC ("TRAPNO", trap_no);
SC ("ERRORCODE", error_code);
SC ("OLDMASK", oldmask);
SC ("R0", arm_r0);
SC ("R1", arm_r1);
SC ("R2", arm_r2);
SC ("R3", arm_r3);
SC ("R4", arm_r4);
SC ("R5", arm_r5);
SC ("R6", arm_r6);
SC ("R7", arm_r7);
SC ("R8", arm_r8);
SC ("R9", arm_r9);
SC ("R10", arm_r10);
SC ("FP", arm_fp);
SC ("IP", arm_ip);
SC ("SP", arm_sp);
SC ("LR", arm_lr);
SC ("PC", arm_pc);
SC ("CPSR", arm_cpsr);
SC ("FAULTADDR", fault_address);
return 0;
}

52
src/arm/getcontext.S Normal file
View file

@ -0,0 +1,52 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "offsets.h"
.text
.arm
.global _Uarm_getcontext
.type _Uarm_getcontext, %function
@ This is a stub version of getcontext() for ARM which only stores core
@ registers. It must be called in a special way, not as a regular
@ function -- see also the libunwind-arm.h:unw_tdep_getcontext macro.
_Uarm_getcontext:
stmfd sp!, {r0, r1}
@ store r0
str r0, [r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF]
add r0, r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF
@ store r1 to r12
stmib r0, {r1-r12}
@ reconstruct r13 at call site, then store
add r1, sp, #12
str r1, [r0, #13 * 4]
@ retrieve r14 from call site, then store
ldr r1, [sp, #8]
str r1, [r0, #14 * 4]
@ point lr to instruction after call site's stack adjustment
add r1, lr, #4
str r1, [r0, #15 * 4]
ldmfd sp!, {r0, r1}
bx lr

71
src/arm/init.h Normal file
View file

@ -0,0 +1,71 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
static inline int
common_init (struct cursor *c)
{
int ret, i;
c->dwarf.loc[R0] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R0);
c->dwarf.loc[R1] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R1);
c->dwarf.loc[R2] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R2);
c->dwarf.loc[R3] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R3);
c->dwarf.loc[R4] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R4);
c->dwarf.loc[R5] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R5);
c->dwarf.loc[R6] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R6);
c->dwarf.loc[R7] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R7);
c->dwarf.loc[R8] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R8);
c->dwarf.loc[R9] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R9);
c->dwarf.loc[R10] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R10);
c->dwarf.loc[R11] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R11);
c->dwarf.loc[R12] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R12);
c->dwarf.loc[R13] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R13);
c->dwarf.loc[R14] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R14);
c->dwarf.loc[R15] = DWARF_REG_LOC (&c->dwarf, UNW_ARM_R15);
for (i = R15 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC;
ret = dwarf_get (&c->dwarf, c->dwarf.loc[R15], &c->dwarf.ip);
if (ret < 0)
return ret;
/* FIXME: correct for ARM? */
ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_ARM_R13),
&c->dwarf.cfa);
if (ret < 0)
return ret;
/* FIXME: Initialisation for other registers. */
c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0;
c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0;
c->dwarf.prev_rs = 0;
return 0;
}

39
src/arm/is_fpreg.c Normal file
View file

@ -0,0 +1,39 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
/* 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
unw_is_fpreg (int regnum)
{
return ((regnum >= UNW_ARM_S0 && regnum <= UNW_ARM_S31)
|| (regnum >= UNW_ARM_F0 && regnum <= UNW_ARM_F7)
|| (regnum >= UNW_ARM_wCGR0 && regnum <= UNW_ARM_wCGR7)
|| (regnum >= UNW_ARM_wR0 && regnum <= UNW_ARM_wR15)
|| (regnum >= UNW_ARM_wC0 && regnum <= UNW_ARM_wC7)
|| (regnum >= UNW_ARM_D0 && regnum <= UNW_ARM_D31));
}

36
src/arm/offsets.h Normal file
View file

@ -0,0 +1,36 @@
/* Linux-specific definitions: */
/* Define various structure offsets to simplify cross-compilation. */
/* Offsets for ARM Linux "ucontext_t": */
#define LINUX_UC_FLAGS_OFF 0x00
#define LINUX_UC_LINK_OFF 0x04
#define LINUX_UC_STACK_OFF 0x08
#define LINUX_UC_MCONTEXT_OFF 0x14
#define LINUX_UC_SIGMASK_OFF 0x68
#define LINUX_UC_REGSPACE_OFF 0xE8
/* Offsets for ARM Linux "struct sigcontext": */
#define LINUX_SC_TRAPNO_OFF 0x00
#define LINUX_SC_ERRORCODE_OFF 0x04
#define LINUX_SC_OLDMASK_OFF 0x08
#define LINUX_SC_R0_OFF 0x0C
#define LINUX_SC_R1_OFF 0x10
#define LINUX_SC_R2_OFF 0x14
#define LINUX_SC_R3_OFF 0x18
#define LINUX_SC_R4_OFF 0x1C
#define LINUX_SC_R5_OFF 0x20
#define LINUX_SC_R6_OFF 0x24
#define LINUX_SC_R7_OFF 0x28
#define LINUX_SC_R8_OFF 0x2C
#define LINUX_SC_R9_OFF 0x30
#define LINUX_SC_R10_OFF 0x34
#define LINUX_SC_FP_OFF 0x38
#define LINUX_SC_IP_OFF 0x3C
#define LINUX_SC_SP_OFF 0x40
#define LINUX_SC_LR_OFF 0x44
#define LINUX_SC_PC_OFF 0x48
#define LINUX_SC_CPSR_OFF 0x4C
#define LINUX_SC_FAULTADDR_OFF 0x50

90
src/arm/regname.c Normal file
View file

@ -0,0 +1,90 @@
#include "unwind_i.h"
static const char *regname[] =
{
/* 0. */
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
/* 8. */
"r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
/* 16. Obsolete FPA names. */
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
/* 24. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 32. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 40. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 48. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 56. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 64. */
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
/* 72. */
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
/* 80. */
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
/* 88. */
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
/* 96. */
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
/* 104. */
"wCGR0", "wCGR1", "wCGR2", "wCGR3", "wCGR4", "wCGR5", "wCGR6", "wCGR7",
/* 112. */
"wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7",
/* 128. */
"spsr", "spsr_fiq", "spsr_irq", "spsr_abt", "spsr_und", "spsr_svc", 0, 0,
/* 136. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 144. */
"r8_usr", "r9_usr", "r10_usr", "r11_usr", "r12_usr", "r13_usr", "r14_usr",
/* 151. */
"r8_fiq", "r9_fiq", "r10_fiq", "r11_fiq", "r12_fiq", "r13_fiq", "r14_fiq",
/* 158. */
"r13_irq", "r14_irq",
/* 160. */
"r13_abt", "r14_abt",
/* 162. */
"r13_und", "r14_und",
/* 164. */
"r13_svc", "r14_svc", 0, 0,
/* 168. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 176. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 184. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 192. */
"wC0", "wC1", "wC2", "wC3", "wC4", "wC5", "wC6", "wC7",
/* 200. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 208. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 216. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 224. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 232. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 240. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 248. */
0, 0, 0, 0, 0, 0, 0, 0,
/* 256. */
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
/* 264. */
"d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
/* 272. */
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
/* 280. */
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
};
PROTECTED const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
return regname[reg];
else
return "???";
}

8
src/arm/siglongjmp.S Normal file
View file

@ -0,0 +1,8 @@
/* Dummy implementation for now. */
.globl _UI_siglongjmp_cont
.globl _UI_longjmp_cont
_UI_siglongjmp_cont:
_UI_longjmp_cont:
bx lr

39
src/arm/unwind_i.h Normal file
View file

@ -0,0 +1,39 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef unwind_i_h
#define unwind_i_h
#include <memory.h>
#include <stdint.h>
#include <libunwind-arm.h>
#include "libunwind_i.h"
#define arm_local_addr_space_init UNW_OBJ(local_addr_space_init)
extern void arm_local_addr_space_init (void);
#endif /* unwind_i_h */

View file

@ -47,10 +47,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define ULEB128 0x4
#define SLEB128 0x5
#define OFFSET 0x6 /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */
#define ADDR 0x7 /* Machine address. */
static uint8_t operands[256] =
{
[DW_OP_addr] = OPND1 (sizeof (unw_word_t) == 4 ? VAL32 : VAL64),
[DW_OP_addr] = OPND1 (ADDR),
[DW_OP_const1u] = OPND1 (VAL8),
[DW_OP_const1s] = OPND1 (VAL8),
[DW_OP_const2u] = OPND1 (VAL16),
@ -106,7 +107,18 @@ static uint8_t operands[256] =
[DW_OP_call_ref] = OPND1 (OFFSET)
};
#define sword(X) ((unw_sword_t) (X))
static inline unw_sword_t
sword (unw_addr_space_t as, unw_word_t val)
{
switch (dwarf_addr_size (as))
{
case 1: return (int8_t) val;
case 2: return (int16_t) val;
case 4: return (int32_t) val;
case 8: return (int64_t) val;
default: abort ();
}
}
static inline unw_word_t
read_operand (unw_addr_space_t as, unw_accessors_t *a,
@ -118,25 +130,43 @@ read_operand (unw_addr_space_t as, unw_accessors_t *a,
uint64_t u64;
int ret;
if (operand_type == ADDR)
switch (dwarf_addr_size (as))
{
case 1: operand_type = VAL8; break;
case 2: operand_type = VAL16; break;
case 4: operand_type = VAL32; break;
case 8: operand_type = VAL64; break;
default: abort ();
}
switch (operand_type)
{
case VAL8:
ret = dwarf_readu8 (as, a, addr, &u8, arg);
if (ret < 0)
return ret;
*val = u8;
break;
case VAL16:
ret = dwarf_readu16 (as, a, addr, &u16, arg);
if (ret < 0)
return ret;
*val = u16;
break;
case VAL32:
ret = dwarf_readu32 (as, a, addr, &u32, arg);
if (ret < 0)
return ret;
*val = u32;
break;
case VAL64:
ret = dwarf_readu64 (as, a, addr, &u64, arg);
if (ret < 0)
return ret;
*val = u64;
break;
@ -345,8 +375,10 @@ do { \
tmp1 = pop ();
switch (operand1)
{
case 0:
break;
default:
Debug (1, "Unexpected DW_OP_deref_size size %d\n",
(int) operand1);
return -UNW_EINVAL;
case 1:
if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0)
@ -379,7 +411,7 @@ do { \
case 8:
if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0)
return ret;
tmp2 = u16;
tmp2 = u64;
if (operand1 != 8)
{
if (dwarf_is_big_endian (as))
@ -433,7 +465,7 @@ do { \
case DW_OP_abs:
Debug (15, "OP_abs\n");
tmp1 = pop ();
if (tmp1 & ((unw_word_t) 1 << (8 * sizeof (unw_word_t) - 1)))
if (tmp1 & ((unw_word_t) 1 << (8 * dwarf_addr_size (as) - 1)))
tmp1 = -tmp1;
push (tmp1);
break;
@ -450,7 +482,7 @@ do { \
tmp1 = pop ();
tmp2 = pop ();
if (tmp1)
tmp1 = sword (tmp2) / sword (tmp1);
tmp1 = sword (as, tmp2) / sword (as, tmp1);
push (tmp1);
break;
@ -528,7 +560,7 @@ do { \
Debug (15, "OP_shra\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp2) >> tmp1);
push (sword (as, tmp2) >> tmp1);
break;
case DW_OP_xor:
@ -542,42 +574,42 @@ do { \
Debug (15, "OP_le\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) <= sword (tmp2));
push (sword (as, tmp1) <= sword (as, tmp2));
break;
case DW_OP_ge:
Debug (15, "OP_ge\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) >= sword (tmp2));
push (sword (as, tmp1) >= sword (as, tmp2));
break;
case DW_OP_eq:
Debug (15, "OP_eq\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) == sword (tmp2));
push (sword (as, tmp1) == sword (as, tmp2));
break;
case DW_OP_lt:
Debug (15, "OP_lt\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) < sword (tmp2));
push (sword (as, tmp1) < sword (as, tmp2));
break;
case DW_OP_gt:
Debug (15, "OP_gt\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) > sword (tmp2));
push (sword (as, tmp1) > sword (as, tmp2));
break;
case DW_OP_ne:
Debug (15, "OP_ne\n");
tmp1 = pop ();
tmp2 = pop ();
push (sword (tmp1) != sword (tmp2));
push (sword (as, tmp1) != sword (as, tmp2));
break;
case DW_OP_skip:

View file

@ -26,12 +26,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf_i.h"
static inline int
is_cie_id (unw_word_t val)
is_cie_id (unw_word_t val, int is_debug_frame)
{
/* DWARF spec says CIE_id is 0xffffffff (for 32-bit ELF) or
0xffffffffffffffff (for 64-bit ELF). However, the GNU toolchain
/* The CIE ID is normally 0xffffffff (for 32-bit ELF) or
0xffffffffffffffff (for 64-bit ELF). However, .eh_frame
uses 0. */
return (val == 0 || val == - (unw_word_t) 1);
if (is_debug_frame)
return (val == - (uint32_t) 1 || val == - (uint64_t) 1);
else
return (val == 0);
}
/* Note: we don't need to keep track of more than the first four
@ -41,7 +44,8 @@ is_cie_id (unw_word_t val)
repeated. */
static inline int
parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
const unw_proc_info_t *pi, struct dwarf_cie_info *dci, void *arg)
const unw_proc_info_t *pi, struct dwarf_cie_info *dci,
unw_word_t base, void *arg)
{
uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
unw_word_t len, cie_end_addr, aug_size;
@ -57,7 +61,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
"address-unit sized constants". The `R' augmentation can be used
to override this, but by default, we pick an address-sized unit
for fde_encoding. */
switch (sizeof (unw_word_t))
switch (dwarf_addr_size (as))
{
case 4: fde_encoding = DW_EH_PE_udata4; break;
case 8: fde_encoding = DW_EH_PE_udata8; break;
@ -74,13 +78,14 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
{
/* the CIE is in the 32-bit DWARF format */
uint32_t cie_id;
/* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
const uint32_t expected_id = (base) ? 0xffffffff : 0;
len = u32val;
cie_end_addr = addr + len;
if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0)
return ret;
/* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
if (cie_id != 0)
if (cie_id != expected_id)
{
Debug (1, "Unexpected CIE id %x\n", cie_id);
return -UNW_EINVAL;
@ -90,6 +95,9 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
{
/* the CIE is in the 64-bit DWARF format */
uint64_t cie_id;
/* DWARF says CIE id should be 0xffffffffffffffff, but in
.eh_frame, it's 0 */
const uint64_t expected_id = (base) ? 0xffffffffffffffffull : 0;
if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
return ret;
@ -97,9 +105,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
cie_end_addr = addr + len;
if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0)
return ret;
/* DWARF says CIE id should be 0xffffffffffffffff, but in
.eh_frame, it's 0 */
if (cie_id != 0)
if (cie_id != expected_id)
{
Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
return -UNW_EINVAL;
@ -146,14 +152,16 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
arg)) < 0)
return ret;
i = 0;
if (augstr[0] == 'z')
{
dci->sized_augmentation = 1;
if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
return ret;
i++;
}
for (i = 1; i < sizeof (augstr) && augstr[i]; ++i)
for (; i < sizeof (augstr) && augstr[i]; ++i)
switch (augstr[i])
{
case 'L':
@ -185,16 +193,15 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
break;
default:
Debug (1, "Unexpected augmentation string `%s'\n", augstr);
if (dci->sized_augmentation)
/* If we have the size of the augmentation body, we can skip
over the parts that we don't understand, so we're OK. */
return 0;
goto done;
else
{
Debug (1, "Unexpected augmentation string `%s'\n", augstr);
return -UNW_EINVAL;
}
return -UNW_EINVAL;
}
done:
dci->fde_encoding = fde_encoding;
dci->cie_instr_start = addr;
Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
@ -202,12 +209,15 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
return 0;
}
/* Extract proc-info from the FDE starting at adress ADDR. */
/* Extract proc-info from the FDE starting at adress ADDR.
Pass BASE as zero for eh_frame behaviour, or a pointer to
debug_frame base for debug_frame behaviour. */
HIDDEN int
dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addrp, unw_proc_info_t *pi,
int need_unwind_info,
int need_unwind_info, unw_word_t base,
void *arg)
{
unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
@ -226,7 +236,7 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
if (u32val != 0xffffffff)
{
uint32_t cie_offset;
int32_t cie_offset;
/* In some configurations, an FDE with a 0 length indicates the
end of the FDE-table. */
@ -241,19 +251,22 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0)
return ret;
if (is_cie_id (cie_offset))
if (is_cie_id (cie_offset, base != 0))
/* ignore CIEs (happens during linear searches) */
return 0;
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = cie_offset_addr - cie_offset;
if (base != 0)
cie_addr = base + cie_offset;
else
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = cie_offset_addr - cie_offset;
}
else
{
uint64_t cie_offset;
int64_t cie_offset;
/* the FDE is in the 64-bit DWARF format */
@ -266,18 +279,23 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0)
return ret;
if (is_cie_id (cie_offset))
if (is_cie_id (cie_offset, base != 0))
/* ignore CIEs (happens during linear searches) */
return 0;
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
if (base != 0)
cie_addr = base + cie_offset;
else
/* DWARF says that the CIE_pointer in the FDE is a
.debug_frame-relative offset, but the GCC-generated .eh_frame
sections instead store a "pcrelative" offset, which is just
as fine as it's self-contained. */
cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
}
if ((ret = parse_cie (as, a, cie_addr, pi, &dci, arg)) < 0)
Debug (15, "looking for CIE at address %x\n", (int) cie_addr);
if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0)
return ret;
/* IP-range has same encoding as FDE pointers, except that it's

View file

@ -28,6 +28,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <link.h>
#include <stddef.h>
#include <stdio.h>
#include <limits.h>
#include "dwarf_i.h"
#include "dwarf-eh.h"
@ -41,6 +43,10 @@ struct table_entry
#ifndef UNW_REMOTE_ONLY
#ifdef __linux
#include "os-linux.h"
#endif
struct callback_data
{
/* in: */
@ -50,6 +56,7 @@ struct callback_data
/* 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 */
};
static int
@ -65,7 +72,7 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
while (i++ < fde_count && addr < eh_frame_end)
{
fde_addr = addr;
if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, arg))
if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, 0, arg))
< 0)
return ret;
@ -75,7 +82,8 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
return 1;
addr = fde_addr;
if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
need_unwind_info, arg))
need_unwind_info, 0,
arg))
< 0)
return ret;
return 1;
@ -84,8 +92,316 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
return -UNW_ENOINFO;
}
/* Info is a pointer to a unw_dyn_info_t structure and, on entry,
member u.rti.segbase contains the instruction-pointer we're looking
/* 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. */
/* 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;
char *stringtab;
unsigned int i;
size_t linksize = 0;
char *linkbuf = NULL;
*buf = NULL;
*bufsize = 0;
f = fopen (file, "r");
if (!f)
return 1;
fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f);
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)));
fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f);
Debug (4, "loading string table of size %d\n",
sec_hdrs[shstrndx].sh_size);
stringtab = malloc (sec_hdrs[shstrndx].sh_size);
fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f);
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);
fread (*buf, 1, *bufsize, f);
Debug (4, "read %d bytes of .debug_frame from offset %d\n",
*bufsize, sec_hdrs[i].sh_offset);
}
else if (is_local >= 0 && strcmp (secname, ".gnu_debuglink") == 0)
{
linksize = sec_hdrs[i].sh_size;
linkbuf = malloc (linksize);
fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
fread (linkbuf, 1, linksize, f);
Debug (4, "read %d bytes of .gnu_debuglink from offset %d\n",
*bufsize, sec_hdrs[i].sh_offset);
}
}
free (stringtab);
free (sec_hdrs);
fclose (f);
if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
{
char *newname, *basedir, *p;
static const char *debugdir = "/usr/lib/debug";
int ret;
/* 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);
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);
return 0;
}
/* Locate the binary which originated the contents of address ADDR. Return
the name of the binary in *name (which is allocated on the heap, and must
be freed by the caller). Returns 0 if a binary is successfully found, or 1
if an error occurs. */
static int
find_binary_for_address (unw_word_t ip, char **name)
{
#ifdef __linux
struct map_iterator mi;
char path[PATH_MAX];
int found = 0;
int pid = getpid ();
unsigned long segbase, mapoff, hi;
maps_init (&mi, pid);
while (maps_next (&mi, &segbase, &hi, &mapoff, path, sizeof (path)))
if (ip >= segbase && ip < hi)
{
found = 1;
break;
}
maps_close (&mi);
if (found)
{
*name = strdup (path);
return 0;
}
#endif
return 1;
}
/* Locate and/or try to load a debug_frame section for address ADDR. Return
pointer to debug frame descriptor, or zero if not found. */
static struct unw_debug_frame_list *
locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info,
unw_word_t addr, const char *dlname)
{
struct unw_debug_frame_list *w, *fdesc = 0;
char *name = 0;
int err;
uint64_t start = 0, end = 0;
char *buf;
size_t bufsize;
unsigned int i;
/* First, see if we loaded this frame already. */
for (w = as->debug_frames; w; w = w->next)
{
Debug (4, "checking %p: %x-%x\n", w, (int)w->start, (int)w->end);
if (addr >= w->start && addr < w->end)
return w;
}
/* If the object name we receive is blank, there's still a chance of locating
the file by parsing /proc/self/maps. */
if (strcmp (dlname, "") == 0)
{
err = find_binary_for_address (addr, &name);
if (err)
{
Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
(uint64_t) addr);
return 0;
}
}
else
name = (char*) dlname;
/* Find the start/end of the described region by parsing the
dl_phdr_info structure. */
start = info->dlpi_addr + info->dlpi_phdr[0].p_vaddr;
end = start;
for (i = 0; i < info->dlpi_phnum; i++)
{
Elf_W (Addr) hdrbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
Elf_W (Addr) hdrlimit = hdrbase + info->dlpi_phdr[i].p_memsz;
if (info->dlpi_phdr[i].p_type != PT_LOAD)
continue;
if (hdrbase < start)
start = hdrbase;
if (hdrlimit > end)
end = hdrlimit;
}
Debug (4, "calculated bounds of %x-%x for '%s'\n", (int)start, (int)end,
name);
err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
if (!err)
{
fdesc = malloc (sizeof (struct unw_debug_frame_list));
fdesc->start = start;
fdesc->end = end;
fdesc->debug_frame = buf;
fdesc->debug_frame_size = bufsize;
fdesc->index = NULL;
fdesc->next = as->debug_frames;
as->debug_frames = fdesc;
}
if (name && name != dlname)
free (name);
return fdesc;
}
struct debug_frame_tab
{
struct table_entry *tab;
uint32_t length;
uint32_t size;
};
static struct debug_frame_tab *
debug_frame_tab_new (unsigned int base_size)
{
struct debug_frame_tab *tab = malloc (sizeof (struct debug_frame_tab));
tab->tab = calloc (base_size, sizeof (struct table_entry));
tab->length = 0;
tab->size = base_size;
return tab;
}
static void
debug_frame_tab_append (struct debug_frame_tab *tab,
unw_word_t fde_offset, unw_word_t start_ip)
{
unsigned int length = tab->length;
if (length == tab->size)
{
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;
}
static void
debug_frame_tab_shrink (struct debug_frame_tab *tab)
{
if (tab->size > tab->length)
{
tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
tab->size = tab->length;
}
}
static int
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 -1;
else
return 0;
}
/* ptr is a pointer to a callback_data structure and, on entry,
member ip contains the instruction-pointer we're looking
for. */
static int
callback (struct dl_phdr_info *info, size_t size, void *ptr)
@ -100,6 +416,8 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
struct dwarf_eh_frame_hdr *hdr;
unw_accessors_t *a;
long n;
struct unw_debug_frame_list *fdesc = 0;
int found = 0;
ip = cb_data->ip;
@ -136,117 +454,261 @@ callback (struct dl_phdr_info *info, size_t size, void *ptr)
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
if (!p_text || !p_eh_hdr)
if (!p_text)
return 0;
if (likely (p_eh_hdr->p_vaddr >= p_text->p_vaddr
&& p_eh_hdr->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
/* normal case: eh-hdr is inside text segment */
segbase = p_text->p_vaddr + load_base;
else
if (p_eh_hdr)
{
/* Special case: eh-hdr is in some other segment; this may
happen, e.g., for the Linux kernel's gate DSO, for
example. */
phdr = info->dlpi_phdr;
for (n = info->dlpi_phnum; --n >= 0; phdr++)
if (likely (p_eh_hdr->p_vaddr >= p_text->p_vaddr
&& p_eh_hdr->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
/* normal case: eh-hdr is inside text segment */
segbase = p_text->p_vaddr + load_base;
else
{
if (phdr->p_type == PT_LOAD && p_eh_hdr->p_vaddr >= phdr->p_vaddr
&& p_eh_hdr->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
/* Special case: eh-hdr is in some other segment; this may
happen, e.g., for the Linux kernel's gate DSO, for
example. */
phdr = info->dlpi_phdr;
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
segbase = phdr->p_vaddr + load_base;
break;
if (phdr->p_type == PT_LOAD && p_eh_hdr->p_vaddr >= phdr->p_vaddr
&& p_eh_hdr->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
{
segbase = phdr->p_vaddr + load_base;
break;
}
}
}
if (p_dynamic)
{
/* For dynamicly linked executables and shared libraries,
DT_PLTGOT is the value that data-relative addresses are
relative to for that object. We call this the "gp". */
Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
for (; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == DT_PLTGOT)
{
/* Assume that _DYNAMIC is writable and GLIBC has
relocated it (true for x86 at least). */
di->gp = dyn->d_un.d_ptr;
break;
}
}
else
/* Otherwise this is a static executable with no _DYNAMIC. Assume
that data-relative addresses are relative to 0, i.e.,
absolute. */
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",
info->dlpi_name, hdr->version);
return 0;
}
a = unw_get_accessors (unw_local_addr_space);
addr = (unw_word_t) (uintptr_t) (hdr + 1);
/* (Optionally) read eh_frame_ptr: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->eh_frame_ptr_enc, pi,
&eh_frame_start, NULL)) < 0)
return ret;
/* (Optionally) read fde_count: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->fde_count_enc, pi,
&fde_count, NULL)) < 0)
return ret;
if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
{
/* If there is no search table or it has an unsupported
encoding, fall back on linear search. */
if (hdr->table_enc == DW_EH_PE_omit)
Debug (4, "table `%s' lacks search table; doing linear search\n",
info->dlpi_name);
else
Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
info->dlpi_name, hdr->table_enc);
eh_frame_end = max_load_addr; /* XXX can we do better? */
if (hdr->fde_count_enc == DW_EH_PE_omit)
fde_count = ~0UL;
if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
abort ();
/* 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
{
di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
di->start_ip = p_text->p_vaddr + load_base;
di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
di->u.rti.table_data = addr;
assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
/ sizeof (unw_word_t));
/* For the binary-search table in the eh_frame_hdr, data-relative
means relative to the start of that section... */
di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr;
found = 1;
Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
"table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr,
(long) di->u.rti.segbase, (long) di->u.rti.table_len,
(long) di->gp, (long) di->u.rti.table_data);
}
}
if (p_dynamic)
Debug (15, "Trying to find .debug_frame\n");
di = &cb_data->di_debug;
fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name);
if (!fdesc)
{
/* For dynamicly linked executables and shared libraries,
DT_PLTGOT is the value that data-relative addresses are
relative to for that object. We call this the "gp". */
Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
for (; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == DT_PLTGOT)
{
/* Assume that _DYNAMIC is writable and GLIBC has
relocated it (true for x86 at least). */
di->gp = dyn->d_un.d_ptr;
break;
}
Debug (15, "couldn't load .debug_frame\n");
return found;
}
else
/* Otherwise this is a static executable with no _DYNAMIC. Assume
that data-relative addresses are relative to 0, i.e.,
absolute. */
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",
info->dlpi_name, hdr->version);
return 0;
char *buf;
size_t bufsize;
unw_word_t item_start, item_end = 0;
uint32_t u32val = 0;
uint64_t cie_id = 0;
struct debug_frame_tab *tab;
Debug (15, "loaded .debug_frame\n");
buf = fdesc->debug_frame;
bufsize = fdesc->debug_frame_size;
if (bufsize == 0)
{
Debug (15, "zero-length .debug_frame\n");
return found;
}
/* Now create a binary-search table, if it does not already exist. */
if (!fdesc->index)
{
addr = (unw_word_t) (uintptr_t) buf;
a = unw_get_accessors (unw_local_addr_space);
/* Find all FDE entries in debug_frame, and make into a sorted
index. */
tab = debug_frame_tab_new (16);
while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
{
uint64_t id_for_cie;
item_start = addr;
dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
if (u32val == 0)
break;
else if (u32val != 0xffffffff)
{
uint32_t cie_id32 = 0;
item_end = addr + u32val;
dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
NULL);
cie_id = cie_id32;
id_for_cie = 0xffffffff;
}
else
{
uint64_t u64val = 0;
/* Extended length. */
dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
item_end = addr + u64val;
dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
id_for_cie = 0xffffffffffffffffull;
}
/*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
if (cie_id == id_for_cie)
;
/*Debug (1, "Found CIE at %.8x.\n", item_start);*/
else
{
unw_word_t fde_addr = item_start;
unw_proc_info_t this_pi;
int err;
/*Debug (1, "Found FDE at %.8x\n", item_start);*/
err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
a, &fde_addr,
&this_pi, 0,
(uintptr_t) buf,
NULL);
if (err == 0)
{
Debug (15, "start_ip = %x, end_ip = %x\n",
(int) this_pi.start_ip, (int) this_pi.end_ip);
debug_frame_tab_append (tab,
item_start - (unw_word_t) (uintptr_t) buf,
this_pi.start_ip);
}
/*else
Debug (1, "FDE parse failed\n");*/
}
addr = item_end;
}
debug_frame_tab_shrink (tab);
qsort (tab->tab, tab->length, sizeof (struct table_entry),
debug_frame_tab_compare);
/* for (i = 0; i < tab->length; i++)
{
fprintf (stderr, "ip %x, fde offset %x\n",
(int) tab->tab[i].start_ip_offset,
(int) tab->tab[i].fde_offset);
}*/
fdesc->index = tab->tab;
fdesc->index_size = tab->length;
free (tab);
}
di->format = UNW_INFO_FORMAT_TABLE;
di->start_ip = fdesc->start;
di->end_ip = fdesc->end;
di->u.ti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
di->u.ti.table_data = (unw_word_t *) fdesc;
di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
di->u.ti.segbase = (unw_word_t) (uintptr_t) info->dlpi_addr;
found = 1;
Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
"gp=0x%lx, table_data=0x%lx\n",
(char *) (uintptr_t) di->u.ti.name_ptr,
(long) di->u.ti.segbase, (long) di->u.ti.table_len,
(long) di->gp, (long) di->u.ti.table_data);
}
a = unw_get_accessors (unw_local_addr_space);
addr = (unw_word_t) (hdr + 1);
/* (Optionally) read eh_frame_ptr: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->eh_frame_ptr_enc, pi,
&eh_frame_start, NULL)) < 0)
return ret;
/* (Optionally) read fde_count: */
if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
&addr, hdr->fde_count_enc, pi,
&fde_count, NULL)) < 0)
return ret;
if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
{
/* If there is no search table or it has an unsupported
encoding, fall back on linear search. */
if (hdr->table_enc == DW_EH_PE_omit)
Debug (4, "table `%s' lacks search table; doing linear search\n",
info->dlpi_name);
else
Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
info->dlpi_name, hdr->table_enc);
eh_frame_end = max_load_addr; /* XXX can we do better? */
if (hdr->fde_count_enc == DW_EH_PE_omit)
fde_count = ~0UL;
if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
abort ();
cb_data->single_fde = 1;
return linear_search (unw_local_addr_space, ip,
eh_frame_start, eh_frame_end, fde_count,
pi, need_unwind_info, NULL);
}
cb_data->single_fde = 0;
di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
di->start_ip = p_text->p_vaddr + load_base;
di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
di->u.rti.name_ptr = (unw_word_t) info->dlpi_name;
di->u.rti.table_data = addr;
assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
/ sizeof (unw_word_t));
/* For the binary-search table in the eh_frame_hdr, data-relative
means relative to the start of that section... */
di->u.rti.segbase = (unw_word_t) hdr;
Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
"table_data=0x%lx\n", (char *) di->u.rti.name_ptr,
(long) di->u.rti.segbase, (long) di->u.rti.table_len,
(long) di->gp, (long) di->u.rti.table_data);
return 1;
return found;
}
HIDDEN int
@ -259,9 +721,12 @@ dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
Debug (14, "looking for IP=0x%lx\n", (long) ip);
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 (callback, &cb_data);
@ -276,14 +741,22 @@ dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
if (cb_data.single_fde)
/* already got the result in *pi */
return 0;
else
/* search the table: */
return dwarf_search_unwind_table (as, ip, &cb_data.di,
/* search the table: */
if (cb_data.di.format != -1)
ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
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 inline const struct table_entry *
lookup (struct table_entry *table, size_t table_size, int32_t rel_ip)
lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
{
unsigned long table_len = table_size / sizeof (struct table_entry);
const struct table_entry *e = 0;
@ -294,6 +767,7 @@ lookup (struct table_entry *table, size_t table_size, int32_t rel_ip)
{
mid = (lo + hi) / 2;
e = table + mid;
Debug (1, "e->start_ip_offset = %x\n", (int) e->start_ip_offset);
if (rel_ip < e->start_ip_offset)
hi = mid;
else
@ -353,16 +827,47 @@ 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;
const struct table_entry *e = NULL, *table;
unw_word_t segbase = 0, fde_addr;
unw_accessors_t *a;
#ifndef UNW_LOCAL_ONLY
struct table_entry ent;
#endif
int ret;
unw_word_t debug_frame_base;
size_t table_len;
#ifdef UNW_REMOTE_ONLY
assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
#else
assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
&& (ip >= di->start_ip && ip < di->end_ip));
|| di->format == UNW_INFO_FORMAT_TABLE);
#endif
assert (ip >= di->start_ip && ip < di->end_ip);
if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
{
table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
table_len = di->u.rti.table_len * sizeof (unw_word_t);
debug_frame_base = 0;
}
else
{
#ifndef UNW_REMOTE_ONLY
struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
/* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is currently only
supported for the local address space. Both the index and
the unwind tables live in local memory, but the address space
to check for properties like the address size and endianness
is the target one. When the ptrace code adds support for
.debug_frame something will have to change. */
assert (as == unw_local_addr_space);
table = fdesc->index;
table_len = fdesc->index_size * sizeof (struct table_entry);
debug_frame_base = (uintptr_t) fdesc->debug_frame;
#endif
}
a = unw_get_accessors (as);
@ -370,16 +875,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
if (as == unw_local_addr_space)
{
segbase = di->u.rti.segbase;
e = lookup ((struct table_entry *) di->u.rti.table_data,
di->u.rti.table_len * sizeof (unw_word_t), ip - segbase);
e = lookup (table, table_len, ip - segbase);
}
else
#endif
{
#ifndef UNW_LOCAL_ONLY
segbase = di->u.rti.segbase;
if ((ret = remote_lookup (as, di->u.rti.table_data,
di->u.rti.table_len * sizeof (unw_word_t),
if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
ip - segbase, &ent, arg)) < 0)
return ret;
if (ret)
@ -390,17 +893,34 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
}
if (!e)
{
Debug (1, "IP %x inside range %x-%x, but no explicit unwind info found\n",
(int) ip, (int) di->start_ip, (int) di->end_ip);
/* IP is inside this table's range, but there is no explicit
unwind info. */
return -UNW_ENOINFO;
}
Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
(long) ip, (long) (e->start_ip_offset + segbase));
fde_addr = e->fde_offset + segbase;
(long) ip, (long) (e->start_ip_offset));
if (debug_frame_base)
fde_addr = e->fde_offset + debug_frame_base;
else
fde_addr = e->fde_offset + segbase;
Debug (1, "e->fde_offset = %x, segbase = %x, debug_frame_base = %x, "
"fde_addr = %x\n", (int) e->fde_offset, (int) segbase,
(int) debug_frame_base, (int) fde_addr);
if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
need_unwind_info, arg)) < 0)
need_unwind_info,
debug_frame_base, arg)) < 0)
return ret;
/* .debug_frame uses an absolute encoding that does not know about any
shared library relocation. */
if (di->format == UNW_INFO_FORMAT_TABLE)
{
pi->start_ip += segbase;
pi->end_ip += segbase;
}
if (ip < pi->start_ip || ip >= pi->end_ip)
return -UNW_ENOINFO;

View file

@ -26,6 +26,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf_i.h"
#include "libunwind_i.h"
#include <assert.h>
HIDDEN int
dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unsigned char encoding,

View file

@ -49,7 +49,7 @@ local_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
return -UNW_ENOINFO;
#endif
list = (unw_dyn_info_list_t *) _U_dyn_info_list_addr ();
list = (unw_dyn_info_list_t *) (uintptr_t) _U_dyn_info_list_addr ();
for (di = list->first; di; di = di->next)
if (ip >= di->start_ip && ip < di->end_ip)
return unwi_extract_dynamic_proc_info (as, ip, pi, di, need_unwind_info,

View file

@ -49,7 +49,7 @@ backtrace (void **buffer, int size)
if (unw_get_reg (&cursor, UNW_REG_IP, &ip) < 0)
return n;
buffer[n++] = (void *) ip;
buffer[n++] = (void *) (uintptr_t) ip;
}
return n;
}

View file

@ -30,5 +30,5 @@ HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
PROTECTED unw_word_t
_U_dyn_info_list_addr (void)
{
return (unw_word_t) &_U_dyn_info_list;
return (unw_word_t) (uintptr_t) &_U_dyn_info_list;
}

View file

@ -28,9 +28,23 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
PROTECTED void
unw_flush_cache (unw_addr_space_t as, unw_word_t lo, unw_word_t hi)
{
#if !UNW_TARGET_IA64
struct unw_debug_frame_list *w = as->debug_frames;
#endif
/* clear dyn_info_list_addr cache: */
as->dyn_info_list_addr = 0;
#if !UNW_TARGET_IA64
for (; w; w = w->next)
{
if (w->index)
free (w->index);
free (w->debug_frame);
}
as->debug_frames = NULL;
#endif
/* This lets us flush caches lazily. The implementation currently
ignores the flush range arguments (lo-hi). This is OK because
unw_flush_cache() is allowed to flush more than the requested

View file

@ -0,0 +1,65 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 <stdlib.h>
#include "unwind_i.h"
PROTECTED unw_addr_space_t
unw_create_addr_space (unw_accessors_t *a, int byte_order)
{
#ifdef UNW_LOCAL_ONLY
return NULL;
#else
unw_addr_space_t as = malloc (sizeof (*as));
if (!as)
return NULL;
memset (as, 0, sizeof (*as));
as->acc = *a;
/*
* MIPS supports only big or little-endian, not weird stuff like
* PDP_ENDIAN.
*/
if (byte_order != 0
&& byte_order != __LITTLE_ENDIAN
&& byte_order != __BIG_ENDIAN)
return NULL;
if (byte_order == 0)
/* use host default: */
as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
else
as->big_endian = (byte_order == __BIG_ENDIAN);
/* FIXME! There is no way to specify the ABI. */
as->abi = UNW_MIPS_ABI_O32;
as->addr_size = 4;
return as;
#endif
}

41
src/mips/Gget_proc_info.c Normal file
View file

@ -0,0 +1,41 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
PROTECTED int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
/* We can only unwind using Dwarf into on MIPS: return failure code
if it's not present. */
ret = dwarf_make_proc_info (&c->dwarf);
if (ret < 0)
return ret;
*pi = c->dwarf.pi;
return 0;
}

99
src/mips/Gget_save_loc.c Normal file
View file

@ -0,0 +1,99 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
/* FIXME for MIPS. */
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
struct cursor *c = (struct cursor *) cursor;
dwarf_loc_t loc;
loc = DWARF_NULL_LOC; /* default to "not saved" */
switch (reg)
{
case UNW_MIPS_R0:
case UNW_MIPS_R1:
case UNW_MIPS_R2:
case UNW_MIPS_R3:
case UNW_MIPS_R4:
case UNW_MIPS_R5:
case UNW_MIPS_R6:
case UNW_MIPS_R7:
case UNW_MIPS_R8:
case UNW_MIPS_R9:
case UNW_MIPS_R10:
case UNW_MIPS_R11:
case UNW_MIPS_R12:
case UNW_MIPS_R13:
case UNW_MIPS_R14:
case UNW_MIPS_R15:
case UNW_MIPS_R16:
case UNW_MIPS_R17:
case UNW_MIPS_R18:
case UNW_MIPS_R19:
case UNW_MIPS_R20:
case UNW_MIPS_R21:
case UNW_MIPS_R22:
case UNW_MIPS_R23:
case UNW_MIPS_R24:
case UNW_MIPS_R25:
case UNW_MIPS_R26:
case UNW_MIPS_R27:
case UNW_MIPS_R28:
case UNW_MIPS_R29:
case UNW_MIPS_R30:
case UNW_MIPS_R31:
loc = c->dwarf.loc[reg - UNW_MIPS_R0];
break;
default:
break;
}
memset (sloc, 0, sizeof (sloc));
if (DWARF_IS_NULL_LOC (loc))
{
sloc->type = UNW_SLT_NONE;
return 0;
}
#if !defined(UNW_LOCAL_ONLY)
if (DWARF_IS_REG_LOC (loc))
{
sloc->type = UNW_SLT_REG;
sloc->u.regnum = DWARF_GET_LOC (loc);
}
else
#endif
{
sloc->type = UNW_SLT_MEMORY;
sloc->u.addr = DWARF_GET_LOC (loc);
}
return 0;
}

66
src/mips/Gglobal.c Normal file
View file

@ -0,0 +1,66 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "dwarf_i.h"
HIDDEN pthread_mutex_t mips_lock = PTHREAD_MUTEX_INITIALIZER;
HIDDEN int tdep_needs_initialization = 1;
/* FIXME: I'm pretty sure we don't need this at all for MIPS, but "generic"
code (include/dwarf_i.h) seems to expect it to be here at present. */
HIDDEN uint8_t dwarf_to_unw_regnum_map[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
};
HIDDEN void
tdep_init (void)
{
intrmask_t saved_mask;
sigfillset (&unwi_full_mask);
sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask);
mutex_lock (&mips_lock);
{
if (!tdep_needs_initialization)
/* another thread else beat us to it... */
goto out;
mi_init ();
dwarf_init ();
#ifndef UNW_REMOTE_ONLY
mips_local_addr_space_init ();
#endif
tdep_needs_initialization = 0; /* signal that we're initialized... */
}
out:
mutex_unlock (&mips_lock);
sigprocmask (SIG_SETMASK, &saved_mask, NULL);
}

208
src/mips/Ginit.c Normal file
View file

@ -0,0 +1,208 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 <stdlib.h>
#include <string.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;
#else /* !UNW_REMOTE_ONLY */
static struct unw_addr_space local_addr_space;
PROTECTED 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). */
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
if (reg >= UNW_MIPS_R0 && reg < UNW_MIPS_R0 + 32)
return &uc->uc_mcontext.gregs[reg - UNW_MIPS_R0];
else
return NULL;
}
# ifdef UNW_LOCAL_ONLY
HIDDEN void *
tdep_uc_addr (ucontext_t *uc, int reg)
{
char *addr = uc_addr (uc, reg);
if (reg >= UNW_MIPS_R0 && reg <= UNW_MIPS_R31
&& tdep_big_endian (unw_local_addr_space)
&& unw_local_addr_space->abi == UNW_MIPS_ABI_O32)
addr += 4;
return addr;
}
# endif /* UNW_LOCAL_ONLY */
HIDDEN unw_dyn_info_list_t _U_dyn_info_list;
/* XXX fix me: there is currently no way to locate the dyn-info list
by a remote unwinder. On ia64, this is done via a special
unwind-table entry. Perhaps something similar can be done with
DWARF2 unwind info. */
static void
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
{
/* it's a no-op */
}
static int
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
void *arg)
{
*dyn_info_list_addr = (unw_word_t) (intptr_t) &_U_dyn_info_list;
return 0;
}
static int
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
void *arg)
{
if (write)
{
Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val);
*(unw_word_t *) (intptr_t) addr = *val;
}
else
{
*val = *(unw_word_t *) (intptr_t) addr;
Debug (16, "mem[%llx] -> %llx\n", (long long) addr, (long long) *val);
}
return 0;
}
static int
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
void *arg)
{
unw_word_t *addr;
ucontext_t *uc = arg;
if (unw_is_fpreg (reg))
goto badreg;
Debug (16, "reg = %s\n", unw_regname (reg));
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
*(unw_word_t *) (intptr_t) addr = (mips_reg_t) *val;
Debug (12, "%s <- %llx\n", unw_regname (reg), (long long) *val);
}
else
{
*val = (mips_reg_t) *(unw_word_t *) (intptr_t) addr;
Debug (12, "%s -> %llx\n", unw_regname (reg), (long long) *val);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
static int
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
ucontext_t *uc = arg;
unw_fpreg_t *addr;
if (!unw_is_fpreg (reg))
goto badreg;
if (!(addr = uc_addr (uc, reg)))
goto badreg;
if (write)
{
Debug (12, "%s <- %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
*(unw_fpreg_t *) (intptr_t) addr = *val;
}
else
{
*val = *(unw_fpreg_t *) (intptr_t) addr;
Debug (12, "%s -> %08lx.%08lx.%08lx\n", unw_regname (reg),
((long *)val)[0], ((long *)val)[1], ((long *)val)[2]);
}
return 0;
badreg:
Debug (1, "bad register number %u\n", reg);
/* attempt to access a non-preserved register */
return -UNW_EBADREG;
}
static int
get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
char *buf, size_t buf_len, unw_word_t *offp,
void *arg)
{
return elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp);
}
HIDDEN void
mips_local_addr_space_init (void)
{
memset (&local_addr_space, 0, sizeof (local_addr_space));
local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
#if _MIPS_SIM == _ABIO32
local_addr_space.abi = UNW_MIPS_ABI_O32;
#elif _MIPS_SIM == _ABIN32
local_addr_space.abi = UNW_MIPS_ABI_N32;
#elif _MIPS_SIM == _ABI64
local_addr_space.abi = UNW_MIPS_ABI_N64;
#else
# error Unsupported ABI
#endif
local_addr_space.addr_size = sizeof (void *);
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
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;
local_addr_space.acc.access_mem = access_mem;
local_addr_space.acc.access_reg = access_reg;
local_addr_space.acc.access_fpreg = access_fpreg;
local_addr_space.acc.resume = 0; /* mips_local_resume? FIXME! */
local_addr_space.acc.get_proc_name = get_static_proc_name;
unw_flush_cache (&local_addr_space, 0, 0);
}
#endif /* !UNW_REMOTE_ONLY */

53
src/mips/Ginit_local.c Normal file
View file

@ -0,0 +1,53 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "init.h"
#ifdef UNW_REMOTE_ONLY
PROTECTED 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)
{
struct cursor *c = (struct cursor *) cursor;
if (tdep_needs_initialization)
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = unw_local_addr_space;
c->dwarf.as_arg = uc;
return common_init (c);
}
#endif /* !UNW_REMOTE_ONLY */

45
src/mips/Ginit_remote.c Normal file
View file

@ -0,0 +1,45 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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 "init.h"
#include "unwind_i.h"
PROTECTED int
unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
{
#ifdef UNW_LOCAL_ONLY
return -UNW_EINVAL;
#else /* !UNW_LOCAL_ONLY */
struct cursor *c = (struct cursor *) cursor;
if (tdep_needs_initialization)
tdep_init ();
Debug (1, "(cursor=%p)\n", c);
c->dwarf.as = as;
c->dwarf.as_arg = as_arg;
return common_init (c);
#endif /* !UNW_LOCAL_ONLY */
}

View file

@ -0,0 +1,35 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include <stdio.h>
/* FIXME for MIPS. */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
}

99
src/mips/Gregs.c Normal file
View file

@ -0,0 +1,99 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
/* FIXME: The following is probably unfinished and/or at least partly bogus. */
HIDDEN int
tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write)
{
dwarf_loc_t loc = DWARF_NULL_LOC;
switch (reg)
{
case UNW_MIPS_R0:
case UNW_MIPS_R1:
case UNW_MIPS_R2:
case UNW_MIPS_R3:
case UNW_MIPS_R4:
case UNW_MIPS_R5:
case UNW_MIPS_R6:
case UNW_MIPS_R7:
case UNW_MIPS_R8:
case UNW_MIPS_R9:
case UNW_MIPS_R10:
case UNW_MIPS_R11:
case UNW_MIPS_R12:
case UNW_MIPS_R13:
case UNW_MIPS_R14:
case UNW_MIPS_R15:
case UNW_MIPS_R16:
case UNW_MIPS_R17:
case UNW_MIPS_R18:
case UNW_MIPS_R19:
case UNW_MIPS_R20:
case UNW_MIPS_R21:
case UNW_MIPS_R22:
case UNW_MIPS_R23:
case UNW_MIPS_R24:
case UNW_MIPS_R25:
case UNW_MIPS_R26:
case UNW_MIPS_R27:
case UNW_MIPS_R28:
case UNW_MIPS_R29:
case UNW_MIPS_R30:
case UNW_MIPS_R31:
loc = c->dwarf.loc[reg - UNW_MIPS_R0];
break;
case UNW_MIPS_CFA:
if (write)
return -UNW_EREADONLYREG;
*valp = c->dwarf.cfa;
return 0;
/* FIXME: IP? Copro & shadow registers? */
default:
Debug (1, "bad register number %u\n", reg);
return -UNW_EBADREG;
}
if (write)
return dwarf_put (&c->dwarf, loc, *valp);
else
return dwarf_get (&c->dwarf, loc, valp);
}
/* FIXME for MIPS. */
HIDDEN int
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;
}

45
src/mips/Gresume.c Normal file
View file

@ -0,0 +1,45 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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. */
/* FIXME for MIPS. */
#include <stdlib.h>
#include "unwind_i.h"
#ifndef UNW_REMOTE_ONLY
HIDDEN inline int
mips_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
return -UNW_EINVAL;
}
#endif /* !UNW_REMOTE_ONLY */
PROTECTED int
unw_resume (unw_cursor_t *cursor)
{
return -UNW_EINVAL;
}

48
src/mips/Gstep.c Normal file
View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
Debug (1, "(cursor=%p)\n", c);
/* Try DWARF-based unwinding... this is the only method likely to work for
MIPS. */
ret = dwarf_step (&c->dwarf);
if (unlikely (ret == -UNW_ESTOPUNWIND))
return ret;
/* Dwarf unwinding didn't work, stop. */
if (unlikely (ret < 0))
return 0;
return (c->dwarf.ip == 0) ? 0 : 1;
}

View file

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

View file

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

5
src/mips/Lget_save_loc.c Normal file
View file

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

5
src/mips/Lglobal.c Normal file
View file

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

5
src/mips/Linit.c Normal file
View file

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

5
src/mips/Linit_local.c Normal file
View file

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

5
src/mips/Linit_remote.c Normal file
View file

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

View file

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

5
src/mips/Lregs.c Normal file
View file

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

5
src/mips/Lresume.c Normal file
View file

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

5
src/mips/Lstep.c Normal file
View file

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

27
src/mips/elfxx.c Normal file
View file

@ -0,0 +1,27 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
#include "../src/elfxx.c"

30
src/mips/gen-offsets.c Normal file
View file

@ -0,0 +1,30 @@
#include <stdio.h>
#include <stddef.h>
#include <ucontext.h>
#define UC(N,X) \
printf ("#define LINUX_UC_" N "_OFF\t0x%X\n", offsetof (ucontext_t, X))
#define SC(N,X) \
printf ("#define LINUX_SC_" N "_OFF\t0x%X\n", offsetof (struct sigcontext, X))
int
main (void)
{
printf (
"/* Linux-specific definitions: */\n\n"
"/* Define various structure offsets to simplify cross-compilation. */\n\n"
"/* Offsets for MIPS Linux \"ucontext_t\": */\n\n");
UC ("FLAGS", uc_flags);
UC ("LINK", uc_link);
UC ("STACK", uc_stack);
UC ("MCONTEXT", uc_mcontext);
UC ("SIGMASK", uc_sigmask);
UC ("MCONTEXT_GREGS", uc_mcontext.gregs);
return 0;
}

85
src/mips/getcontext.S Normal file
View file

@ -0,0 +1,85 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "offsets.h"
#include <endian.h>
.text
#if _MIPS_SIM == _ABIO32
# if __BYTE_ORDER == __BIG_ENDIAN
# define OFFSET 4
# else
# define OFFSET 0
# endif
# define SREG(X) \
sw $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X + OFFSET) ($4); \
sra $1, $X, 31; \
sw $1, (LINUX_UC_MCONTEXT_GREGS + 8 * X + 4 - OFFSET) ($4)
#else
# define SREG(X) sd $X, (LINUX_UC_MCONTEXT_GREGS + 8 * X) ($4)
#endif
.global _Umips_getcontext
.type _Umips_getcontext, %function
# This is a stub version of getcontext() for MIPS which only stores core
# registers.
_Umips_getcontext:
.set noat
SREG (1)
SREG (0)
SREG (2)
SREG (3)
SREG (4)
SREG (5)
SREG (6)
SREG (7)
SREG (8)
SREG (9)
SREG (10)
SREG (11)
SREG (12)
SREG (13)
SREG (14)
SREG (15)
SREG (16)
SREG (17)
SREG (18)
SREG (19)
SREG (20)
SREG (21)
SREG (22)
SREG (23)
SREG (24)
SREG (25)
SREG (26)
SREG (27)
SREG (28)
SREG (29)
SREG (30)
SREG (31)
li $2, 0
j $31
.size _Umips_getcontext, .-_Umips_getcontext

56
src/mips/init.h Normal file
View file

@ -0,0 +1,56 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
static inline int
common_init (struct cursor *c)
{
int ret, i;
for (i = 0; i < 32; i++)
c->dwarf.loc[i] = DWARF_REG_LOC (&c->dwarf, UNW_MIPS_R0 + i);
for (i = 32; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC;
ret = dwarf_get (&c->dwarf, c->dwarf.loc[31], &c->dwarf.ip);
if (ret < 0)
return ret;
ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_MIPS_R29),
&c->dwarf.cfa);
if (ret < 0)
return ret;
/* FIXME: Initialisation for other registers. */
c->dwarf.args_size = 0;
c->dwarf.ret_addr_column = 0;
c->dwarf.pi_valid = 0;
c->dwarf.pi_is_dynamic = 0;
c->dwarf.hint = 0;
c->dwarf.prev_rs = 0;
return 0;
}

35
src/mips/is_fpreg.c Normal file
View file

@ -0,0 +1,35 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
/* FIXME: I'm not sure if libunwind's GP/FP register distinction is very useful
on MIPS. */
PROTECTED int
unw_is_fpreg (int regnum)
{
/* FIXME: Support FP. */
return 0;
}

39
src/mips/offsets.h Normal file
View file

@ -0,0 +1,39 @@
/* Linux-specific definitions: */
/* Define various structure offsets to simplify cross-compilation. */
/* FIXME: Currently these are only used in getcontext.S, which is only used
for a local unwinder, so we can use the compile-time ABI. At a later date
we will want all three here, to use for signal handlers. Also, because
of the three ABIs, gen-offsets.c can not quite generate this file. */
/* Offsets for MIPS Linux "ucontext_t": */
#if _MIPS_SIM == _ABIO32
# define LINUX_UC_FLAGS_OFF 0x0
# define LINUX_UC_LINK_OFF 0x4
# define LINUX_UC_STACK_OFF 0x8
# define LINUX_UC_MCONTEXT_OFF 0x18
# define LINUX_UC_SIGMASK_OFF 0x268
# define LINUX_UC_MCONTEXT_GREGS 0x28
#elif _MIPS_SIM == _ABIN32
# define LINUX_UC_FLAGS_OFF 0x0
# define LINUX_UC_LINK_OFF 0x4
# define LINUX_UC_STACK_OFF 0x8
# define LINUX_UC_MCONTEXT_OFF 0x18
# define LINUX_UC_SIGMASK_OFF 0x270
# define LINUX_UC_MCONTEXT_GREGS 0x18
#elif _MIPS_SIM == _ABI64
# define LINUX_UC_FLAGS_OFF 0x0
# define LINUX_UC_LINK_OFF 0x8
# define LINUX_UC_STACK_OFF 0x10
# define LINUX_UC_MCONTEXT_OFF 0x28
# define LINUX_UC_SIGMASK_OFF 0x280
# define LINUX_UC_MCONTEXT_GREGS 0x28
#endif

46
src/mips/regname.c Normal file
View file

@ -0,0 +1,46 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
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"
static const char *regname[] =
{
/* 0. */
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
/* 8. */
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
/* 16. */
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
/* 24. */
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
};
PROTECTED const char *
unw_regname (unw_regnum_t reg)
{
if (reg < (unw_regnum_t) ARRAY_SIZE (regname))
return regname[reg];
else
return "???";
}

8
src/mips/siglongjmp.S Normal file
View file

@ -0,0 +1,8 @@
/* Dummy implementation for now. */
.globl _UI_siglongjmp_cont
.globl _UI_longjmp_cont
_UI_siglongjmp_cont:
_UI_longjmp_cont:
j $31

48
src/mips/unwind_i.h Normal file
View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#ifndef unwind_i_h
#define unwind_i_h
#include <memory.h>
#include <stdint.h>
#include <libunwind-mips.h>
#include "libunwind_i.h"
/*
#define x86_lock UNW_OBJ(lock)
#define x86_local_resume UNW_OBJ(local_resume)
#define x86_local_addr_space_init UNW_OBJ(local_addr_space_init)
#define x86_scratch_loc UNW_OBJ(scratch_loc)
extern int x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor,
void *arg);
extern dwarf_loc_t x86_scratch_loc (struct cursor *c, unw_regnum_t reg);
*/
extern void mips_local_addr_space_init (void);
#endif /* unwind_i_h */

View file

@ -288,6 +288,8 @@ int _UPT_reg_offset[UNW_REG_LAST + 1] =
// [UNW_X86_64_SS] = 0xa0
#elif defined(UNW_TARGET_PPC32)
#elif defined(UNW_TARGET_PPC64)
#elif defined(UNW_TARGET_ARM)
#elif defined(UNW_TARGET_MIPS)
#else
# error Fix me.
#endif

View file

@ -63,7 +63,7 @@ _longjmp (jmp_buf env, int val)
if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0
|| unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
|| unw_set_reg (&c, UNW_REG_IP,
(unw_word_t) &_UI_longjmp_cont))
(unw_word_t) (uintptr_t) &_UI_longjmp_cont))
abort ();
unw_resume (&c);

View file

@ -81,7 +81,7 @@ siglongjmp (sigjmp_buf env, int val)
if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0
|| unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
|| unw_set_reg (&c, UNW_REG_IP, (unw_word_t) cont))
|| unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont))
abort ();
unw_resume (&c);

View file

@ -30,11 +30,12 @@ _Unwind_FindEnclosingFunction (void *ip)
{
unw_proc_info_t pi;
if (unw_get_proc_info_by_ip (unw_local_addr_space, (unw_word_t) ip, &pi, 0)
if (unw_get_proc_info_by_ip (unw_local_addr_space,
(unw_word_t) (uintptr_t) ip, &pi, 0)
< 0)
return NULL;
return (void *) pi.start_ip;
return (void *) (uintptr_t) pi.start_ip;
}
void *__libunwind_Unwind_FindEnclosingFunction (void *)

View file

@ -60,7 +60,7 @@ _Unwind_RaiseException (struct _Unwind_Exception *exception_object)
if (unw_get_proc_info (&context.cursor, &pi) < 0)
return _URC_FATAL_PHASE1_ERROR;
personality = (_Unwind_Personality_Fn) pi.handler;
personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler;
if (personality)
{
reason = (*personality) (_U_VERSION, _UA_SEARCH_PHASE,

View file

@ -103,7 +103,7 @@ _Unwind_Phase2 (struct _Unwind_Exception *exception_object,
|| unw_get_proc_info (&context->cursor, &pi) < 0)
return _URC_FATAL_PHASE2_ERROR;
personality = (_Unwind_Personality_Fn) pi.handler;
personality = (_Unwind_Personality_Fn) (uintptr_t) pi.handler;
if (personality)
{
if (!stop)

View file

@ -322,10 +322,14 @@ AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
ARCH = @ARCH@
ARCH_ARM_FALSE = @ARCH_ARM_FALSE@
ARCH_ARM_TRUE = @ARCH_ARM_TRUE@
ARCH_HPPA_FALSE = @ARCH_HPPA_FALSE@
ARCH_HPPA_TRUE = @ARCH_HPPA_TRUE@
ARCH_IA64_FALSE = @ARCH_IA64_FALSE@
ARCH_IA64_TRUE = @ARCH_IA64_TRUE@
ARCH_MIPS_FALSE = @ARCH_MIPS_FALSE@
ARCH_MIPS_TRUE = @ARCH_MIPS_TRUE@
ARCH_PPC32_FALSE = @ARCH_PPC32_FALSE@
ARCH_PPC32_TRUE = @ARCH_PPC32_TRUE@
ARCH_PPC64_FALSE = @ARCH_PPC64_FALSE@
@ -396,6 +400,7 @@ PKG_MINOR = @PKG_MINOR@
RANLIB = @RANLIB@
REMOTE_ONLY_FALSE = @REMOTE_ONLY_FALSE@
REMOTE_ONLY_TRUE = @REMOTE_ONLY_TRUE@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@