1# Copyright (C) 2013, 2015 Red Hat, Inc.
2# This file is part of elfutils.
3#
4# This file is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3 of the License, or
7# (at your option) any later version.
8#
9# elfutils is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17. $srcdir/test-subr.sh
18
19# Verify one of the backtraced threads contains function 'main'.
20check_main()
21{
22  if grep -w main $1; then
23    return
24  fi
25  echo >&2 $2: no main
26  false
27}
28
29# Without proper ELF symbols resolution we could get inappropriate weak
30# symbol "gsignal" with the same address as the correct symbol "raise".
31# It was fixed by GIT commit 78dec228b3cfb2f9300cd0b682ebf416c9674c91 .
32# [patch] Improve ELF symbols preference (global > weak)
33# https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/002624.html
34check_gsignal()
35{
36  if ! grep -w gsignal $1; then
37    return
38  fi
39  echo >&2 $2: found gsignal
40  false
41}
42
43
44# Makes sure we saw the function that initiated the backtrace
45# when the core was generated through the tests backtrace --gencore.
46# This might disappear when frame pointer chasing gone bad.
47check_backtracegen()
48{
49  if grep -w backtracegen $1; then
50    return
51  fi
52  echo >&2 $2: no backtracegen
53  false
54}
55
56# Verify the STDERR output does not contain unexpected errors.
57# In some cases we cannot reliably find out we got behind _start as some
58# operating system do not properly terminate CFI by undefined PC.
59# Ignore it here as it is a bug of OS, not a bug of elfutils.
60check_err()
61{
62  if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range|address out of range|Invalid register|\(null\))$' \
63         | wc -c) \
64       -eq 0 ]
65  then
66    return
67  fi
68  echo >&2 $2: neither empty nor just out of DWARF
69  false
70}
71
72check_all()
73{
74  bt=$1
75  err=$2
76  testname=$3
77  check_main $bt $testname
78  check_gsignal $bt $testname
79  check_err $err $testname
80}
81
82check_unsupported()
83{
84  err=$1
85  testname=$2
86  if grep -q ': Unwinding not supported for this architecture$' $err; then
87    echo >&2 $testname: arch not supported
88    test_cleanup
89    exit 77
90  fi
91}
92
93check_native_unsupported()
94{
95  err=$1
96  testname=$2
97  check_unsupported $err $testname
98
99  # ARM is special. It is supported, but it doesn't use .eh_frame by default
100  # making the native tests fail unless debuginfo (for glibc) is installed
101  # and we can fall back on .debug_frame for the CFI.
102  case "`uname -m`" in
103    arm* )
104      if egrep 'dwfl_thread_getframes(.*)No DWARF information found' $err; then
105	echo >&2 $testname: arm needs debuginfo installed for all libraries
106	exit 77
107      fi
108    ;;
109  esac
110}
111
112check_core()
113{
114  arch=$1
115  testfiles backtrace.$arch.{exec,core}
116  tempfiles backtrace.$arch.{bt,err}
117  echo ./backtrace ./backtrace.$arch.{exec,core}
118  testrun ${abs_builddir}/backtrace -e ./backtrace.$arch.exec --core=./backtrace.$arch.core 1>backtrace.$arch.bt 2>backtrace.$arch.err || true
119  cat backtrace.$arch.{bt,err}
120  check_unsupported backtrace.$arch.err backtrace.$arch.core
121  check_all backtrace.$arch.{bt,err} backtrace.$arch.core
122  check_backtracegen backtrace.$arch.bt backtrace.$arch.core
123}
124
125# Backtrace live process.
126# Do not abort on non-zero exit code due to some warnings of ./backtrace
127# - see function check_err.
128check_native()
129{
130  child=$1
131  tempfiles $child.{bt,err}
132  (set +ex; testrun ${abs_builddir}/backtrace --backtrace-exec=${abs_builddir}/$child 1>$child.bt 2>$child.err; true)
133  cat $child.{bt,err}
134  check_native_unsupported $child.err $child
135  check_all $child.{bt,err} $child
136}
137
138# Backtrace core file.
139check_native_core()
140{
141# systemd-coredump/coredumpctl doesn't seem to like concurrent core dumps
142# use a lock file (fd 200) tests/core-dump-backtrace.lock
143(
144  child=$1
145
146  # Disable valgrind while dumping core.
147  SAVED_VALGRIND_CMD="$VALGRIND_CMD"
148  unset VALGRIND_CMD
149
150  # Wait for lock for 10 seconds or skip.
151  flock -x -w 10 200 || exit 77;
152
153  # Skip the test if we cannot adjust core ulimit.
154  pid="`ulimit -c unlimited || exit 77; set +ex; testrun ${abs_builddir}/$child --gencore; true`"
155  core="core.$pid"
156  # see if /proc/sys/kernel/core_uses_pid is set to 0
157  if [ -f core ]; then
158    mv core "$core"
159  fi
160  type -P coredumpctl && have_coredumpctl=1 || have_coredumpctl=0
161  if [ ! -f "$core" -a $have_coredumpctl -eq 1 ]; then
162    # Maybe systemd-coredump took it. But give it some time to dump first...
163    sleep 1
164    coredumpctl --output="$core" dump $pid || rm -f $core
165
166    # Try a couple of times after waiting some more if something went wrong...
167    if [ ! -f "$core" ]; then
168      sleep 2
169      coredumpctl --output="$core" dump $pid || rm -f $core
170    fi
171
172    if [ ! -f "$core" ]; then
173      sleep 3
174      coredumpctl --output="$core" dump $pid || rm -f $core
175    fi
176  fi
177  if [ ! -f "$core" ]; then
178    # In some containers our view of pids is confused. Since tests are
179    # run in a new fresh directory any core here is most like is ours.
180    if ls core.[0-9]* 1> /dev/null 2>&1; then
181      mv core.[0-9]* "$core"
182    fi
183  fi
184  if [ ! -f "$core" ]; then
185    echo "No $core file generated";
186    exit 77;
187  fi
188
189  if [ "x$SAVED_VALGRIND_CMD" != "x" ]; then
190    VALGRIND_CMD="$SAVED_VALGRIND_CMD"
191    export VALGRIND_CMD
192  fi
193
194  # Do not abort on non-zero exit code due to some warnings of ./backtrace
195  # - see function check_err.
196  tempfiles $core{,.{bt,err}}
197  (set +ex; testrun ${abs_builddir}/backtrace -e ${abs_builddir}/$child --core=$core 1>$core.bt 2>$core.err; true)
198  cat $core.{bt,err}
199  check_native_unsupported $core.err $child-$core
200  check_all $core.{bt,err} $child-$core
201  rm $core{,.{bt,err}}
202) 200>${abs_builddir}/core-dump-backtrace.lock
203}
204