aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWeimin Pan <weimin.pan@oracle.com>2022-09-27 15:24:47 -0700
committerIndu Bhagat <indu.bhagat@oracle.com>2024-04-25 15:03:50 -0700
commit171324cb0325c6c54a1d98d3564a4da5ca2dc1a5 (patch)
tree7fc69957cc74e9b2f60d93246fd32f8efbc308cc
parent6d551065a7add22cef04864d850400443cdd065b (diff)
downloadgdb-171324cb0325c6c54a1d98d3564a4da5ca2dc1a5.zip
gdb-171324cb0325c6c54a1d98d3564a4da5ca2dc1a5.tar.gz
gdb-171324cb0325c6c54a1d98d3564a4da5ca2dc1a5.tar.bz2
unwinder: Add SFrame unwinder tests
[Changes in V4] - Addressed Mike's review comments. - Be careful with the use of # and dnl in configure.ac - Add AC_CANONICAL_TARGET as we check for target. - Remove the LC_ALL=C bits. - Minor code fixups in the testcases - Removed unnecessary unistd.h. - use ATTRIBUTE_NOCLONE consistently. - Other minor cleanups. [End of changes in V4] [Changes in V3] - Added two new tests with attributes -f(no-)omit-frame-pointer. - Minor adjustments due to buildsystem changes in libsframe. [End of changes in V3] [Changes in V2] - minor changes in filenames in the testsuite. [End of changes in V2] Add tests for backtracing using SFrame section. ChangeLog: * libsframe/Makefile.in: Regenerated. * libsframe/configure: Regenerated. * libsframe/configure.ac: Check for cross compilation. * libsframe/testsuite/Makefile.in: Regenerated. * libsframe/testsuite/config/default.exp: Load sframe-lib.exp. * libsframe/testsuite/libsframe.decode/Makefile.in: Regenerated. * libsframe/testsuite/libsframe.encode/Makefile.in: Regenerated. * libsframe/testsuite/lib/sframe-lib.exp: New file. Add procedures for handling unwinder tests. * libsframe/testsuite/libsframe.unwind/backtrace.c: New test. * libsframe/testsuite/libsframe.unwind/backtrace.lk: New test. * libsframe/testsuite/libsframe.unwind/inline-cmds.c: New test. * libsframe/testsuite/libsframe.unwind/inline-cmds.lk: New test. * libsframe/testsuite/libsframe.unwind/inline.c: New test. * libsframe/testsuite/libsframe.unwind/inline.lk: New test. * libsframe/testsuite/libsframe.unwind/solib-lib1.c: New test. * libsframe/testsuite/libsframe.unwind/solib-lib2.c: New test. * libsframe/testsuite/libsframe.unwind/solib-main.c: New test. * libsframe/testsuite/libsframe.unwind/solib-main.d: New test. * libsframe/testsuite/libsframe.unwind/solib.exp: New file. * libsframe/testsuite/libsframe.unwind/solib-lib1.h: New test. * libsframe/testsuite/libsframe.unwind/solib-lib2.h: New test. * libsframe/testsuite/libsframe.unwind/tailcall.c: New test. * libsframe/testsuite/libsframe.unwind/tailcall.lk: New test. * libsframe/testsuite/libsframe.unwind/ttest.c: New test. * libsframe/testsuite/libsframe.unwind/ttest.lk: New test. * libsframe/testsuite/libsframe.unwind/unwind.exp: New file. * libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.c: Likewise. * libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.lk: Likewise. * libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.c: Likewise. * libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.lk: Likewise.
-rw-r--r--libsframe/Makefile.in8
-rwxr-xr-xlibsframe/configure218
-rw-r--r--libsframe/configure.ac13
-rw-r--r--libsframe/testsuite/config/default.exp3
-rw-r--r--libsframe/testsuite/lib/sframe-lib.exp180
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.c108
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.lk4
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.c109
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.lk4
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace.c144
-rw-r--r--libsframe/testsuite/libsframe.unwind/backtrace.lk3
-rw-r--r--libsframe/testsuite/libsframe.unwind/inline-cmds.c107
-rw-r--r--libsframe/testsuite/libsframe.unwind/inline-cmds.lk3
-rw-r--r--libsframe/testsuite/libsframe.unwind/inline.c96
-rw-r--r--libsframe/testsuite/libsframe.unwind/inline.lk3
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-lib1.c8
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-lib1.h3
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-lib2.c55
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-lib2.h3
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-main.c46
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib-main.d3
-rw-r--r--libsframe/testsuite/libsframe.unwind/solib.exp70
-rw-r--r--libsframe/testsuite/libsframe.unwind/tailcall.c102
-rw-r--r--libsframe/testsuite/libsframe.unwind/tailcall.lk3
-rw-r--r--libsframe/testsuite/libsframe.unwind/ttest.c126
-rw-r--r--libsframe/testsuite/libsframe.unwind/ttest.lk3
-rw-r--r--libsframe/testsuite/libsframe.unwind/unwind.exp189
27 files changed, 1533 insertions, 81 deletions
diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in
index 46ea309..03ac628 100644
--- a/libsframe/Makefile.in
+++ b/libsframe/Makefile.in
@@ -107,6 +107,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+target_triplet = @target@
@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_1 = libsframebt.la
@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_2 = $(INCDIR)/sframe-backtrace-api.h
@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am__append_3 = libsframebt.la
@@ -411,6 +412,7 @@ CFLAGS = @CFLAGS@
COMPAT_DEJAGNU = @COMPAT_DEJAGNU@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CROSS_COMPILE = @CROSS_COMPILE@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
@@ -509,8 +511,12 @@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
+target = @target@
target_alias = @target_alias@
+target_cpu = @target_cpu@
target_noncanonical = @target_noncanonical@
+target_os = @target_os@
+target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
@@ -1192,6 +1198,8 @@ site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
@echo 'set build_triplet $(build_triplet)' >>site.tmp
@echo 'set host_alias "$(host_alias)"' >>site.tmp
@echo 'set host_triplet $(host_triplet)' >>site.tmp
+ @echo 'set target_alias "$(target_alias)"' >>site.tmp
+ @echo 'set target_triplet $(target_triplet)' >>site.tmp
@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
echo "## Begin content included from file $$f. Do not modify. ##" \
&& cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
diff --git a/libsframe/configure b/libsframe/configure
index acfc805..5f4d613 100755
--- a/libsframe/configure
+++ b/libsframe/configure
@@ -645,6 +645,7 @@ MAINTAINER_MODE_FALSE
MAINTAINER_MODE_TRUE
HAVE_SFRAME_AS_FALSE
HAVE_SFRAME_AS_TRUE
+CROSS_COMPILE
HAVE_LD_VERSION_SCRIPT_FALSE
HAVE_LD_VERSION_SCRIPT_TRUE
HAVE_SOLARIS_LD_FALSE
@@ -668,14 +669,6 @@ DUMPBIN
LD
FGREP
SED
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
LIBTOOL
ac_ct_AR
AR
@@ -727,6 +720,18 @@ CPPFLAGS
LDFLAGS
CFLAGS
CC
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
target_alias
host_alias
build_alias
@@ -1394,6 +1399,7 @@ Program names:
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
_ACEOF
fi
@@ -2302,6 +2308,117 @@ ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
@@ -5370,77 +5487,6 @@ macro_revision='1.3134'
ltmain="$ac_aux_dir/ltmain.sh"
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
# Backslashify metacharacters that are still active within
# double-quoted strings.
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
@@ -11519,7 +11565,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11522 "configure"
+#line 11568 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11625,7 +11671,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11628 "configure"
+#line 11674 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12420,6 +12466,16 @@ fi
+is_cross_compiler=
+if test x"${host}" = x"${target}" ; then
+ is_cross_compiler=no
+else
+ is_cross_compiler=yes
+fi
+CROSS_COMPILE=$is_cross_compiler
+
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if as supports --gsframe" >&5
$as_echo_n "checking if as supports --gsframe... " >&6; }
diff --git a/libsframe/configure.ac b/libsframe/configure.ac
index c0da671..3059303 100644
--- a/libsframe/configure.ac
+++ b/libsframe/configure.ac
@@ -20,6 +20,8 @@ dnl
AC_INIT([libsframe], BFD_VERSION)
AC_CONFIG_SRCDIR(sframe.c)
+AC_CANONICAL_TARGET
+AC_CANONICAL_HOST
AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE
AM_SILENT_RULES([yes])
@@ -109,6 +111,17 @@ else
fi
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
+dnl Determine if we are cross compiling
+
+is_cross_compiler=
+if test x"${host}" = x"${target}" ; then
+ is_cross_compiler=no
+else
+ is_cross_compiler=yes
+fi
+CROSS_COMPILE=$is_cross_compiler
+AC_SUBST([CROSS_COMPILE])
+
dnl The libsframebt library needs to be built with SFrame info.
dnl If the build assembler is not capable of generate SFrame then
dnl the library is not built.
diff --git a/libsframe/testsuite/config/default.exp b/libsframe/testsuite/config/default.exp
index 609f286..b3cc58d 100644
--- a/libsframe/testsuite/config/default.exp
+++ b/libsframe/testsuite/config/default.exp
@@ -52,3 +52,6 @@ if {![info exists CFLAGS]} {
if {![info exists CFLAGS_FOR_TARGET]} {
set CFLAGS_FOR_TARGET $CFLAGS
}
+
+# load the utility procedures
+load_lib sframe-lib.exp
diff --git a/libsframe/testsuite/lib/sframe-lib.exp b/libsframe/testsuite/lib/sframe-lib.exp
new file mode 100644
index 0000000..d686d27
--- /dev/null
+++ b/libsframe/testsuite/lib/sframe-lib.exp
@@ -0,0 +1,180 @@
+# Support routines for libsframe testsuite.
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+load_file $srcdir/../../ld/testsuite/lib/ld-lib.exp
+
+set unwind_test_file_name ""
+
+proc run_native_host_cmd { command } {
+ global link_output
+ global ld
+
+ verbose -log "$command"
+ set run_output ""
+ try {
+ set run_output [exec "sh" "-c" "$command" "2>@1"]
+ set status 0
+ } trap CHILDSTATUS {results options} {
+ set status [lindex [dict get $options -errorcode] 2]
+ set run_output $results
+ }
+ regsub "\n$" $run_output "" run_output
+ if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+ append run_output "child process exited abnormally"
+ }
+
+ if [string match "" $run_output] then {
+ return ""
+ }
+
+ verbose -log "$run_output"
+ return "$run_output"
+}
+
+# Compile and link a C source file for execution on the host.
+proc compile_link_one_host_cc { src output additional_args } {
+ global CC
+ global CFLAGS
+
+ return [run_native_host_cmd "./libtool --quiet --tag=CC --mode=link $CC $CFLAGS $src -o $output $additional_args" ]
+}
+
+proc make_unwind_parallel_path { args } {
+ global objdir
+ set joiner [list "file" "join" $objdir]
+ set joiner [concat $joiner $args]
+ return [eval $joiner]
+}
+
+proc standard_output_file {basename} {
+ global objdir subdir unwind_test_file_name
+
+ set dir [make_unwind_parallel_path outputs $subdir $unwind_test_file_name]
+ file mkdir $dir
+ return [file join $dir $basename]
+}
+
+proc standard_testfile {args} {
+ global unwind_test_file_name
+ global subdir
+ global unwind_test_file_last_vars
+
+ # Outputs.
+ global testfile binfile
+
+ set testfile $unwind_test_file_name
+ set binfile [standard_output_file ${testfile}]
+
+ if {[llength $args] == 0} {
+ set args .c
+ }
+
+ # Unset our previous output variables.
+ # This can help catch hidden bugs.
+ if {[info exists unwind_test_file_last_vars]} {
+ foreach varname $unwind_test_file_last_vars {
+ global $varname
+ catch {unset $varname}
+ }
+ }
+ # 'executable' is often set by tests.
+ set unwind_test_file_last_vars {executable}
+
+ set suffix ""
+ foreach arg $args {
+ set varname srcfile$suffix
+ global $varname
+
+ # Handle an extension.
+ if {$arg == ""} {
+ set arg $testfile.c
+ } else {
+ set first [string range $arg 0 0]
+ if { $first == "." || $first == "-" } {
+ set arg $testfile$arg
+ }
+ }
+
+ set $varname $arg
+ lappend unwind_test_file_last_vars $varname
+
+ if {$suffix == ""} {
+ set suffix 2
+ } else {
+ incr suffix
+ }
+ }
+}
+
+# Build a shared object DEST from SOURCES.
+proc unwind_compile_so {sources dest} {
+ global CFLAGS
+ set obj_options $CFLAGS
+ lappend obj_options "additional_flags=-fPIC -Wa,--gsframe"
+
+ set outdir [file dirname $dest]
+ set objects ""
+ foreach source $sources {
+ set sourcebase [file tail $source]
+ set object ${outdir}/${sourcebase}.o
+
+ if {[target_compile $source $object object \
+ $obj_options] != ""} {
+ return -1
+ }
+
+ lappend objects $object
+ }
+
+ set link_options "additional_flags=-shared"
+
+ set destbase [file tail $dest]
+ lappend link_options "additional_flags=-Wl,-soname,$destbase"
+
+ if {[target_compile "${objects}" "${dest}" executable $link_options] != ""} {
+ catch "exec rm ${objects}" status
+ return -1
+ }
+ catch "exec rm ${objects}" status
+ return ""
+}
+
+# Build a binary of TYPE from SOURCE at path DEST.
+proc unwind_compile {source dest type options} {
+ set new_options ""
+
+ foreach opt $options {
+ if {[regexp {^shlib=(.*)} $opt dummy_var shlib_name]
+ && $type == "executable"} {
+ lappend source "-Wl,$shlib_name"
+ } else {
+ lappend new_options $opt
+ }
+ }
+ set options $new_options
+
+ verbose "options are $options"
+ verbose "source is $source $dest $type $options"
+
+ lappend options "additional_flags=-rdynamic -Wa,--gsframe ./.libs/libsframebt.a ./.libs/libsframe.a"
+ set result [target_compile $source $dest $type $options]
+
+ return $result
+}
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.c b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.c
new file mode 100644
index 0000000..ef01e97
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is a revised version of gdb/testsuite/gdb.base/backtrace.c. */
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+# define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+#define BT_EXPECTED_NPTRS 5
+/* Expected funclist. */
+static const char *const func_list[] =
+{
+ "show_bt",
+ "baz",
+ "bar",
+ "foo",
+ "main"
+};
+
+void __attribute__((__noinline__,__optimize__("omit-frame-pointer"))) ATTRIBUTE_NOCLONE
+show_bt ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int j, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (err)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+ if (nptrs != BT_EXPECTED_NPTRS)
+ {
+ printf ("Backtace nptrs mismatch: expected = %d, generated = %d \n",
+ BT_EXPECTED_NPTRS, nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+
+ printf ("%s: backtrace with omit-frame-pointer attr\n",
+ (j == nptrs) ? "PASS" : "FAIL");
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+baz ()
+{
+ show_bt ();
+ return 0;
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+bar ()
+{
+ return baz ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+foo ()
+{
+ return bar ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+main ()
+{
+ return foo ();
+}
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.lk b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.lk
new file mode 100644
index 0000000..a26ef7e
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-1.lk
@@ -0,0 +1,4 @@
+# source: backtrace-fp-attr-1.c
+# cflags: -fno-omit-frame-pointer
+# link: on
+PASS: backtrace with omit-frame-pointer attr
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.c b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.c
new file mode 100644
index 0000000..ee62b20
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.c
@@ -0,0 +1,109 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is a revised version of gdb/testsuite/gdb.base/backtrace.c. */
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+# define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+#define BT_EXPECTED_NPTRS 5
+
+/* Expected funclist. */
+static const char *const func_list[] =
+{
+ "show_bt",
+ "baz",
+ "bar",
+ "foo",
+ "main"
+};
+
+void __attribute__((__noinline__,__optimize__("no-omit-frame-pointer"))) ATTRIBUTE_NOCLONE
+show_bt ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int j, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (err)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+ if (nptrs != BT_EXPECTED_NPTRS)
+ {
+ printf ("Backtace nptrs mismatch: expected = %d, generated = %d \n",
+ BT_EXPECTED_NPTRS, nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+
+ printf ("%s: backtrace with no-omit-frame-pointer attr\n",
+ (j == nptrs) ? "PASS" : "FAIL");
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+baz ()
+{
+ show_bt ();
+ return 0;
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+bar ()
+{
+ return baz ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+foo ()
+{
+ return bar ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+main ()
+{
+ return foo ();
+}
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.lk b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.lk
new file mode 100644
index 0000000..97f49ef
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace-fp-attr-2.lk
@@ -0,0 +1,4 @@
+# source: backtrace-fp-attr-2.c
+# cflags: -fomit-frame-pointer
+# link: on
+PASS: backtrace with no-omit-frame-pointer attr
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace.c b/libsframe/testsuite/libsframe.unwind/backtrace.c
new file mode 100644
index 0000000..3e00b76
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace.c
@@ -0,0 +1,144 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is a revised version of gdb/testsuite/gdb.base/backtrace.c. */
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+# define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 100
+
+/* Expected funclist. */
+static const char *const func_list[] =
+{
+ "show_bt",
+ "baz",
+ "bar",
+ "foo",
+ "main"
+};
+
+void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+show_bt ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int j, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs != 5)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+
+ printf ("%s: backtrace test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+baz ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return -1;
+ }
+
+ show_bt ();
+ return 0;
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+bar ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return -1;
+ }
+
+ return baz ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+foo ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return -1;
+ }
+
+ return bar ();
+}
+
+int __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+main ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return -1;
+ }
+
+ return foo ();
+}
diff --git a/libsframe/testsuite/libsframe.unwind/backtrace.lk b/libsframe/testsuite/libsframe.unwind/backtrace.lk
new file mode 100644
index 0000000..fdc78eb
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/backtrace.lk
@@ -0,0 +1,3 @@
+# source: backtrace.c
+# link: on
+PASS: backtrace test
diff --git a/libsframe/testsuite/libsframe.unwind/inline-cmds.c b/libsframe/testsuite/libsframe.unwind/inline-cmds.c
new file mode 100644
index 0000000..bc15545
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline-cmds.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is only ever run if it is compiled with a new-enough GCC, but
+ we don't want the compilation to fail if compiled by some other
+ compiler. */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-cmds.c. */
+
+#ifdef __GNUC__
+#define ATTR __attribute__((always_inline))
+#else
+#define ATTR
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <execinfo.h>
+#include "sframe-backtrace-api.h"
+
+#define BT_BUF_SIZE 10
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+void noinline(void);
+
+inline ATTR void outer_inline1(void)
+{
+ noinline ();
+}
+
+inline ATTR void outer_inline2(void)
+{
+ outer_inline1 ();
+}
+
+int main (void)
+{ /* start of main */
+ int val;
+
+ x = 7;
+ y = 8;
+
+ outer_inline2 ();
+
+ return 0;
+}
+
+
+/* funclist for inline-cmds. */
+const char *const func_list[] =
+{
+ "noinline",
+ "main"
+};
+
+inline ATTR void inlined_fn(void)
+{
+ x += y + z;
+
+ void *buffer[BT_BUF_SIZE];
+ char **strings;
+ /* Call the unwinder to get an array of return addresses. */
+ int j, err;
+ int nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1 || nptrs != 2)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL)
+ {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+ printf ("%s: inline-cmds test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+void noinline(void)
+{
+ inlined_fn (); /* inlined */
+}
diff --git a/libsframe/testsuite/libsframe.unwind/inline-cmds.lk b/libsframe/testsuite/libsframe.unwind/inline-cmds.lk
new file mode 100644
index 0000000..053b66b
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline-cmds.lk
@@ -0,0 +1,3 @@
+# source: inline-cmds.c
+# link: on
+PASS: inline-cmds test
diff --git a/libsframe/testsuite/libsframe.unwind/inline.c b/libsframe/testsuite/libsframe.unwind/inline.c
new file mode 100644
index 0000000..fc753fc
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline.c
@@ -0,0 +1,96 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is a revised version of gdb/testsuite/gdb.opt/inline-bt.c. */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#define ATTR __attribute__((always_inline))
+
+#define BT_BUF_SIZE 32
+
+int x, y;
+volatile int z = 0;
+volatile int result;
+
+/* funclist. */
+const char *const flist[] =
+{
+ "main"
+};
+
+void bar(void)
+{
+ x += y;
+}
+
+inline ATTR int func1(void)
+{
+ bar ();
+ return x * y;
+}
+
+inline ATTR int func2(void)
+{
+ void *buffer[BT_BUF_SIZE];
+ int ok = 0, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s\n", sframe_bt_errmsg (err));
+ return -1;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return -1;
+ }
+
+ /* Verify the results. */
+ if (nptrs == 1 && strstr (strings[0], flist[0]))
+ ok = 1;
+
+ free(strings);
+
+ printf ("%s: unwind test\n", ok == 1 ? "PASS" : "FAIL");
+
+ return x * func1 ();
+}
+
+int main (void)
+{
+ int val;
+
+ x = 7;
+ y = 8;
+ bar ();
+
+ val = func1 ();
+ result = val;
+
+ val = func2 ();
+ result = val;
+
+ return 0;
+}
diff --git a/libsframe/testsuite/libsframe.unwind/inline.lk b/libsframe/testsuite/libsframe.unwind/inline.lk
new file mode 100644
index 0000000..88f846b
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/inline.lk
@@ -0,0 +1,3 @@
+# source: inline.c
+# link: on
+PASS: unwind test
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib1.c b/libsframe/testsuite/libsframe.unwind/solib-lib1.c
new file mode 100644
index 0000000..16c77ca
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib1.c
@@ -0,0 +1,8 @@
+#include "solib-lib1.h"
+
+unsigned int
+adder(unsigned int a, unsigned int b, int (*call)(int))
+{
+ (void)(*call)(a+b);
+ return (a+b);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib1.h b/libsframe/testsuite/libsframe.unwind/solib-lib1.h
new file mode 100644
index 0000000..d40eac0
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib1.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib2.c b/libsframe/testsuite/libsframe.unwind/solib-lib2.c
new file mode 100644
index 0000000..9ba3096
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib2.c
@@ -0,0 +1,55 @@
+#include <execinfo.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+#include "solib-lib2.h"
+
+#define BT_BUF_SIZE 100
+
+/* funclist for running "ttest.x 3". */
+static const char *const bt_list[] =
+{
+ "adder2",
+ "bar",
+ "adder",
+ "main"
+};
+
+unsigned int
+adder2 (unsigned int a, unsigned int b, int (*call)(int))
+{
+ void *buffer[BT_BUF_SIZE];
+ int i, nptrs, err;
+ char **strings;
+
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (err)
+ {
+ printf ("SFrame error: %s\n", sframe_bt_errmsg (err));
+ return (-1);
+ }
+ if (nptrs != 4)
+ {
+ printf ("sframe_backtrace failed: %d %d\n", nptrs, err);
+ return (-1);
+ }
+
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL)
+ {
+ printf ("Error in backtrace_symbols");
+ return (-1);
+ }
+
+ /* Verify the results. */
+ for (i = 0; i < nptrs; i++)
+ if (!strstr (strings[i], bt_list[i]))
+ break;
+
+ free (strings);
+
+ printf ("%s: unwind solib test\n", i == nptrs ? "PASS" : "FAIL");
+
+ (void)(*call) (a+b);
+ return (a+b);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-lib2.h b/libsframe/testsuite/libsframe.unwind/solib-lib2.h
new file mode 100644
index 0000000..61b7212
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-lib2.h
@@ -0,0 +1,3 @@
+#include<stdio.h>
+
+extern unsigned int adder2(unsigned int a, unsigned int b, int (*call)(int));
diff --git a/libsframe/testsuite/libsframe.unwind/solib-main.c b/libsframe/testsuite/libsframe.unwind/solib-main.c
new file mode 100644
index 0000000..d0bd806
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-main.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "sframe-backtrace-api.h"
+#include "solib-lib1.h"
+#include "solib-lib2.h"
+
+#define BT_BUF_SIZE 100
+
+int foo (int x)
+{
+ return ++x;
+}
+
+int bar (int x)
+{
+ x = adder2 (x, x+1, foo);
+
+ return ++x;
+}
+
+int main (void)
+{
+ unsigned int a = 1;
+ unsigned int b = 2;
+ unsigned int result = 0;
+
+ result = adder (a,b, bar);
+
+ return 0;
+}
diff --git a/libsframe/testsuite/libsframe.unwind/solib-main.d b/libsframe/testsuite/libsframe.unwind/solib-main.d
new file mode 100644
index 0000000..483ded5
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib-main.d
@@ -0,0 +1,3 @@
+# source: solib-main.c
+# link: on
+PASS: unwind solib test
diff --git a/libsframe/testsuite/libsframe.unwind/solib.exp b/libsframe/testsuite/libsframe.unwind/solib.exp
new file mode 100644
index 0000000..9ea8ce7
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/solib.exp
@@ -0,0 +1,70 @@
+# Copyright 2022 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Run the test only if sframebt library exists.
+if [catch "exec ls $objdir/.libs/libsframebt.la" status] then {
+ return;
+}
+
+set experimental ""
+
+# Shared object files.
+set libname1 "solib-lib1"
+set srcfile_lib1 ${srcdir}/${subdir}/${libname1}.c
+set binfile_lib1 ${objdir}/${libname1}.so
+set libname2 "solib-lib2"
+set srcfile_lib2 ${srcdir}/${subdir}/${libname2}.c
+set binfile_lib2 ${objdir}/${libname2}.so
+
+# Binary file.
+set testfile "solib-main"
+set srcfile ${srcdir}/${subdir}/${testfile}.c
+set binfile [standard_output_file ${testfile}]
+set bin_flags [list debug shlib=${binfile_lib1} shlib=${binfile_lib2}]
+
+if { [unwind_compile_so ${srcfile_lib1} ${binfile_lib1}] != ""
+ || [unwind_compile_so ${srcfile_lib2} ${binfile_lib2}] != ""
+ || [unwind_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
+ untested "failed to compile"
+ return -1
+}
+
+if {[info exists env(LD_LIBRARY_PATH)]} {
+ set old_ld_lib $env(LD_LIBRARY_PATH)
+}
+set env(LD_LIBRARY_PATH) "${objdir}"
+
+set solib_output "${binfile} ${binfile_lib1} ${binfile_lib2}"
+set results [run_host_cmd ${binfile} $solib_output]
+
+set f [open "tmpdir/solib.out" "w"]
+puts $f $results
+close $f
+
+if { [regexp_diff "tmpdir/solib.out" "${srcdir}/${subdir}/${testfile}.d"] } then {
+ fail "$test_name"
+} else {
+ pass "$test_name"
+}
+
+catch "exec rm ${binfile_lib1}" status
+catch "exec rm ${binfile_lib2}" status
+catch "exec rm tmpdir/solib.out" status
+
+if {[info exists old_ld_lib]} {
+ set env(LD_LIBRARY_PATH) $old_ld_lib
+} else {
+ unset env(LD_LIBRARY_PATH)
+}
diff --git a/libsframe/testsuite/libsframe.unwind/tailcall.c b/libsframe/testsuite/libsframe.unwind/tailcall.c
new file mode 100644
index 0000000..fd3add2
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/tailcall.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+# define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 16
+
+/* funclist for running tailcall. */
+const char *const func_list[] =
+{
+ "show_bt",
+ "dec",
+ "dec",
+ "main"
+};
+
+void show_bt ()
+{
+ void *buffer[BT_BUF_SIZE];
+ int j, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1 || nptrs != 4)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+
+ printf ("%s: tailcall test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+/* An example of tail recursive function. */
+void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+dec (int n)
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ if (n < 0)
+ return;
+
+ if (n == 2)
+ show_bt ();
+
+ /* The last executed statement is recursive call. */
+ dec (n-1);
+}
+
+int
+main (void)
+{
+ dec (3);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/tailcall.lk b/libsframe/testsuite/libsframe.unwind/tailcall.lk
new file mode 100644
index 0000000..3d7ab98
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/tailcall.lk
@@ -0,0 +1,3 @@
+# source: tailcall.c
+# link: on
+PASS: tailcall test
diff --git a/libsframe/testsuite/libsframe.unwind/ttest.c b/libsframe/testsuite/libsframe.unwind/ttest.c
new file mode 100644
index 0000000..342ba14
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/ttest.c
@@ -0,0 +1,126 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is the revised version of the example in "man backtrace". */
+
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sframe-backtrace-api.h"
+
+#ifdef __has_attribute
+# if !__has_attribute (noclone)
+# define ATTRIBUTE_NOCLONE
+# endif
+#endif
+#ifndef ATTRIBUTE_NOCLONE
+# define ATTRIBUTE_NOCLONE __attribute__((noclone))
+#endif
+
+#define BT_BUF_SIZE 100
+
+/* funclist */
+static const char *const func_list[] =
+{
+ "myfunc3",
+ "()",
+ "myfunc",
+ "myfunc",
+ "myfunc",
+ "main"
+};
+
+void myfunc3 (void)
+{
+ void *buffer[BT_BUF_SIZE];
+ int j, nptrs, err;
+ char **strings;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1 || nptrs != 6)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ /* Get these addresses symbolically. */
+ strings = backtrace_symbols (buffer, nptrs);
+ if (strings == NULL) {
+ printf ("Error in backtrace_symbols");
+ return;
+ }
+
+ /* Verify the results. */
+ for (j = 0; j < nptrs; j++)
+ if (!strstr (strings[j], func_list[j]))
+ break;
+
+ free(strings);
+
+ printf ("%s: unwind test\n", j == nptrs ? "PASS" : "FAIL");
+}
+
+static void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+/* "static" means don't export the symbol. */
+myfunc2 (void)
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ myfunc3 ();
+}
+
+void __attribute__((__noinline__)) ATTRIBUTE_NOCLONE
+myfunc (int ncalls)
+{
+ void *buffer[BT_BUF_SIZE];
+ int nptrs, err;
+
+ /* Call the unwinder to get an array of return addresses. */
+ nptrs = sframe_backtrace (buffer, BT_BUF_SIZE, &err);
+ if (nptrs == -1)
+ {
+ printf ("SFrame error: %s (%d)\n", sframe_bt_errmsg (err), nptrs);
+ return;
+ }
+
+ if (ncalls > 1)
+ myfunc (ncalls - 1);
+ else
+ myfunc2 ();
+}
+
+int
+main (int argc, char *argv[])
+{
+ int cnt;
+ if (argc != 2) {
+ cnt = 3;
+ }
+ else
+ cnt = atoi(argv[1]);
+ myfunc (cnt);
+ exit (EXIT_SUCCESS);
+}
diff --git a/libsframe/testsuite/libsframe.unwind/ttest.lk b/libsframe/testsuite/libsframe.unwind/ttest.lk
new file mode 100644
index 0000000..80aa224
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/ttest.lk
@@ -0,0 +1,3 @@
+# source: ttest.c
+# link: on
+PASS: unwind test
diff --git a/libsframe/testsuite/libsframe.unwind/unwind.exp b/libsframe/testsuite/libsframe.unwind/unwind.exp
new file mode 100644
index 0000000..510b92e
--- /dev/null
+++ b/libsframe/testsuite/libsframe.unwind/unwind.exp
@@ -0,0 +1,189 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# Run the tests only if sframebt library exists.
+
+if [catch "exec ls $objdir/.libs/libsframebt.la" status] then {
+ verbose -log "$objdir/.libs/libsframebt.la not found.";
+ verbose -log "Skipping SFrame unwind tests";
+ return;
+}
+
+proc run_unwind_test { name } {
+ global CC
+ global CFLAGS
+ global copyfile env runtests srcdir subdir verbose
+
+ # Append additional flags for unwinder to work properly
+ set unwind_cflags "-Wa,--gsframe -rdynamic "
+
+ if ![runtest_file_p $runtests $name] then {
+ return
+ }
+
+ if [string match "*/*" $name] {
+ set file $name
+ set name [file tail $name]
+ } else {
+ set file "$srcdir/$subdir/$name"
+ }
+
+ set opt_array [slurp_options "${file}.lk"]
+ if { $opt_array == -1 } {
+ perror "error reading options from $file.lk"
+ unresolved $subdir/$name
+ return
+ }
+ set run_ld 0
+ set shared "-shared"
+ set opts(cflags) {}
+ set opts(link) {}
+ set opts(link_flags) {}
+ set opts(nonshared) {}
+ set opts(unwind) {}
+ set opts(name) {}
+ set opts(source) {}
+ set opts(xfail) {}
+
+ foreach i $opt_array {
+ set opt_name [lindex $i 0]
+ set opt_val [lindex $i 1]
+ if { $opt_name == "" } {
+ set in_extra 1
+ continue
+ }
+ if ![info exists opts($opt_name)] {
+ perror "unknown option $opt_name in file $file.lk"
+ unresolved $subdir/$name
+ return
+ }
+
+ set opts($opt_name) [concat $opts($opt_name) $opt_val]
+ }
+
+ if { [llength $opts(unwind)] == 0 } {
+ set opts(unwind) "$file.c"
+ } else {
+ set opts(unwind) "[file dirname $file]/$opts(unwind)"
+ }
+
+ if { [llength $opts(name)] == 0 } {
+ set opts(name) $opts(unwind)
+ }
+
+ if { [llength $opts(cflags)] != 0 } {
+ append unwind_cflags $opts(cflags)
+ }
+
+ if { [llength $opts(link)] != 0
+ || [llength $opts(source)] > 1 } {
+ set run_ld 1
+ }
+
+ if { [llength $opts(nonshared)] != 0 } {
+ set shared ""
+ }
+
+ set testname $opts(name)
+ if { $opts(name) == "" } {
+ set testname "$subdir/$name"
+ }
+
+ # Compile and link the unwind program.
+ set comp_output [compile_link_one_host_cc $opts(unwind) "tmpdir/test_x" "./.libs/libsframebt.la ./.libs/libsframe.la"]
+
+ if { $comp_output != ""} {
+ send_log "compilation of unwind program $opts(unwind) failed with <$comp_output>"
+ perror "compilation of unwind program $opts(unwind) failed"
+ fail $testname
+ return 0
+ }
+
+ # Compile the inputs and posibly link them together.
+
+ set unwind ""
+ if { [llength $opts(source)] > 0 } {
+ set unwind ""
+ if { $run_ld } {
+ set unwind_output "tmpdir/test_x ./.libs/libsframebt.a ./.libs/libsframe.a"
+ # set unwind_output "tmpdir/out.so"
+ # set unwind_flags "-fPIC $shared $opts(link_flags)"
+ } else {
+ set unwind_output "tmpdir/out.o"
+ # set unwind_flags "-fPIC -c"
+ }
+ if [board_info [target_info name] exists cflags] {
+ append unwind_flags " [board_info [target_info name] cflags]"
+ }
+ if [board_info [target_info name] exists ldflags] {
+ append unwind_flags " [board_info [target_info name] ldflags]"
+ }
+ set src {}
+ foreach sfile $opts(source) {
+ if [is_remote host] {
+ lappend src [remote_download host [file join [file dirname $file] $sfile]]
+ } else {
+ lappend src [file join [file dirname $file] $sfile]
+ }
+ }
+
+ set comp_output [run_host_cmd "$CC" "$CFLAGS $unwind_cflags [concat $src] -o $unwind_output"]
+
+ if { $comp_output != ""} {
+ send_log "compilation of SFrame test program [concat $src] failed with <$comp_output>"
+ fail $testname
+ return 0
+ }
+ }
+
+ # Time to setup xfailures.
+ foreach targ $opts(xfail) {
+ if [match_target $targ] {
+ setup_xfail "*-*-*"
+ break
+ }
+ }
+
+ # Invoke the unwind program on the outputs.
+
+ verbose -log "$srcdir"
+ set results [run_host_cmd tmpdir/test_x $unwind_output]
+
+ set f [open "tmpdir/test_x.out" "w"]
+ puts $f $results
+ close $f
+
+ if { [regexp_diff "tmpdir/test_x.out" "${file}.lk"] } then {
+ fail $testname
+ if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/test_x.out]" 2 }
+ return 0
+ }
+
+ pass $testname
+ return 0
+}
+
+set sframe_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach sframe_test $sframe_test_list {
+ verbose [file rootname $sframe_test]
+ verbose running unwind test on $sframe_test
+ run_unwind_test [file rootname $sframe_test]
+}