mirror of
https://github.com/libunwind/libunwind.git
synced 2026-01-12 00:04:03 +08:00
Fix tdep_trace() returning bad count on aarch64.
`tdep_trace()` did not return the right count value when it did not complete successfully. Also rewrote tests/Gtest-trace to (a) add more tests of `unw_backtrace2()`, (2) give more meaningful verbose output for the poor humans trying to figure out why it's failing, and (iii) iterate the signal callback several times to detect cache-related edge cases.
This commit is contained in:
committed by
Stephen M. Webb
parent
3c47821d68
commit
7aadfa552f
4
.github/workflows/CI-unix.yml
vendored
4
.github/workflows/CI-unix.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
autoreconf -i
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --build=x86_64-pc-linux-gnu --host=${{ matrix.target.triple }}
|
||||
../configure --build=x86_64-pc-linux-gnu --host=${{ matrix.target.triple }} --enable-debug
|
||||
env:
|
||||
CC: ${{ matrix.toolchain.CC }}
|
||||
CXX: ${{ matrix.toolchain.CXX }}
|
||||
@@ -74,6 +74,8 @@ jobs:
|
||||
sudo bash -c 'echo core.%p.%p > /proc/sys/kernel/core_pattern'
|
||||
ulimit -c unlimited
|
||||
make -C build check -j8
|
||||
env:
|
||||
UNW_DEBUG_LEVEL: 4
|
||||
|
||||
- name: Show Logs
|
||||
if: ${{ failure() }}
|
||||
|
||||
@@ -505,6 +505,8 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||
else
|
||||
{
|
||||
/* Cached frame has no LR and neither do we. */
|
||||
Debug (1, "returning -UNW_ESTOPUNWIND, depth %d\n", depth);
|
||||
*size = depth;
|
||||
return -UNW_ESTOPUNWIND;
|
||||
}
|
||||
if (likely(ret >= 0) && likely(f->fp_cfa_offset != -1))
|
||||
@@ -542,6 +544,8 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||
/* We cannot trace through this frame, give up and tell the
|
||||
caller we had to stop. Data collected so far may still be
|
||||
useful to the caller, so let it know how far we got. */
|
||||
Debug (1, "returning -UNW_ESTOPUNWIND, depth %d\n", depth);
|
||||
*size = depth;
|
||||
ret = -UNW_ESTOPUNWIND;
|
||||
break;
|
||||
}
|
||||
@@ -557,9 +561,7 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||
buffer[depth++] = (void *) (pc - d->use_prev_instr);
|
||||
}
|
||||
|
||||
#if UNW_DEBUG
|
||||
Debug (1, "returning %d, depth %d\n", ret, depth);
|
||||
#endif
|
||||
*size = depth;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -538,7 +538,10 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||
/* We cannot trace through this frame, give up and tell the
|
||||
caller we had to stop. Data collected so far may still be
|
||||
useful to the caller, so let it know how far we got. */
|
||||
Debug (1, "returning UNW_ESTOPUNWIND, depth %d\n", depth);
|
||||
*size = depth;
|
||||
ret = -UNW_ESTOPUNWIND;
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -553,9 +556,7 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||
buffer[depth++] = (void *) rip;
|
||||
}
|
||||
|
||||
#if UNW_DEBUG
|
||||
Debug (1, "returning %d, depth %d\n", ret, depth);
|
||||
#endif
|
||||
*size = depth;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
/* libunwind - a platform-independent unwind library
|
||||
Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY
|
||||
|
||||
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. */
|
||||
/**
|
||||
* @file tests/Gtest-trace.c
|
||||
*
|
||||
* Exercise the unw_backtrace*() functions and ensire they produce expected
|
||||
* results.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY
|
||||
* Copyright 2024 Stephen M. Webb <stephen.webb@bregmasoft.ca>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
@@ -47,156 +56,204 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#define SIG_STACK_SIZE 0x100000
|
||||
|
||||
int verbose;
|
||||
int num_errors;
|
||||
int verbose; /**< enable verbose mode? */
|
||||
int repeat_count = 9; /**< number of times to exercise the signal handler */
|
||||
int num_errors = 0; /**< cumulatiove error count */
|
||||
|
||||
/* These variables are global because they
|
||||
* cause the signal stack to overflow */
|
||||
char buf[512], name[256];
|
||||
void *addresses[3][128];
|
||||
* can cause the signal stack to overflow */
|
||||
enum test_id {
|
||||
TEST_UNW_STEP,
|
||||
TEST_BACKTRACE,
|
||||
TEST_UNW_BACKTRACE,
|
||||
TEST_UNW_BACKTRACE2
|
||||
};
|
||||
enum { MAX_BACKTRACE_SIZE = 128 };
|
||||
|
||||
struct {
|
||||
char const *name;
|
||||
void *addresses[MAX_BACKTRACE_SIZE];
|
||||
} trace[] = {
|
||||
{ "unw_step" },
|
||||
{ "backtrace" },
|
||||
{ "unw_backtrace" },
|
||||
{ "unw_backtrace2" }
|
||||
};
|
||||
|
||||
unw_cursor_t cursor;
|
||||
unw_context_t uc;
|
||||
|
||||
/**
|
||||
* Dump a backtrace (in verbose mode).
|
||||
*/
|
||||
static void
|
||||
dump_backtrace(int bt_count, enum test_id id)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf ("\t%s() [depth is %d]:\n", trace[id].name, bt_count);
|
||||
for (int i = 0; i < bt_count; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, trace[id].addresses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a backtrace from a backtrace call with a backtrace from unw_step().
|
||||
*/
|
||||
static void
|
||||
compare_backtraces(int step_count, int backtrace_count, enum test_id id)
|
||||
{
|
||||
if (step_count != backtrace_count)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and %s() depths differ: %d vs. %d\n",
|
||||
trace[id].name,
|
||||
step_count,
|
||||
backtrace_count);
|
||||
++num_errors;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < step_count; ++i)
|
||||
{
|
||||
if (labs (trace[TEST_UNW_STEP].addresses[i] - trace[id].addresses[i]) > 1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and %s() addresses differ at %d: %p vs. %p\n",
|
||||
trace[id].name, i,
|
||||
trace[TEST_UNW_STEP].addresses[i],
|
||||
trace[id].addresses[i]);
|
||||
++num_errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exercises `unw_backtrace()`. Compares the result of a raw `unw_step()` loop
|
||||
* with the result of calling the system-supplied `backtrace()` (if any) with the
|
||||
* result of the `unw_backtrace()` call, which may have taken the "fast path"
|
||||
* (using cached data).
|
||||
*
|
||||
* If there is no system-supplied `backtrace()` call its just an alias for
|
||||
* `unw_backtrace()` so the result better match.
|
||||
*
|
||||
* Also exercises `unw_backtrace2()` using the same context, since the code
|
||||
* differs from `unw_backtrace()`.
|
||||
*/
|
||||
static void
|
||||
do_backtrace (void)
|
||||
{
|
||||
unw_word_t ip;
|
||||
int ret = -UNW_ENOINFO;
|
||||
int depth = 0;
|
||||
int i, n, m;
|
||||
int unw_step_depth = 0;
|
||||
int backtrace_depth = 0;
|
||||
int unw_backtrace_depth = 0;
|
||||
|
||||
if (verbose)
|
||||
printf ("\tnormal trace:\n");
|
||||
{
|
||||
printf ("\nBacktrace with implicit context:\n");
|
||||
}
|
||||
|
||||
unw_getcontext (&uc);
|
||||
/**
|
||||
* Perform a naked `unw_step()` loop on the current context and save the IPs.
|
||||
*/
|
||||
ret = unw_getcontext (&uc);
|
||||
if (ret != 0)
|
||||
panic ("unw_getcontext failed\n");
|
||||
if (unw_init_local (&cursor, &uc) < 0)
|
||||
panic ("unw_init_local failed!\n");
|
||||
|
||||
do
|
||||
{
|
||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||
addresses[0][depth] = (void *) ip;
|
||||
trace[TEST_UNW_STEP].addresses[unw_step_depth++] = (void *) ip;
|
||||
}
|
||||
while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
|
||||
|
||||
while ((ret = unw_step (&cursor)) > 0 && unw_step_depth < MAX_BACKTRACE_SIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||
printf ("FAILURE: unw_step() returned %d for ip=%#010lx\n", ret, (long) ip);
|
||||
++num_errors;
|
||||
}
|
||||
dump_backtrace(unw_step_depth, TEST_UNW_STEP);
|
||||
|
||||
if (verbose)
|
||||
for (i = 0; i < depth; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
|
||||
/*
|
||||
* Call the system-supplied `backtrace()` (maybe) and compare with the
|
||||
* `unw_step()`results. They should be identical.
|
||||
*/
|
||||
backtrace_depth = backtrace (trace[TEST_BACKTRACE].addresses, MAX_BACKTRACE_SIZE);
|
||||
dump_backtrace(backtrace_depth, TEST_BACKTRACE);
|
||||
compare_backtraces(unw_step_depth, backtrace_depth, TEST_BACKTRACE);
|
||||
|
||||
if (verbose)
|
||||
printf ("\n\tvia backtrace():\n");
|
||||
/*
|
||||
* Call `unw_backtrace()` and compare with the `unw_step()`results. They
|
||||
* should be identical.
|
||||
*/
|
||||
unw_backtrace_depth = unw_backtrace (trace[TEST_UNW_BACKTRACE].addresses,
|
||||
MAX_BACKTRACE_SIZE);
|
||||
dump_backtrace(unw_backtrace_depth, TEST_UNW_BACKTRACE);
|
||||
compare_backtraces(unw_step_depth, unw_backtrace_depth, TEST_UNW_BACKTRACE);
|
||||
|
||||
n = backtrace (addresses[1], 128);
|
||||
|
||||
if (verbose)
|
||||
for (i = 0; i < n; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
|
||||
|
||||
if (verbose)
|
||||
printf ("\n\tvia unw_backtrace():\n");
|
||||
|
||||
m = unw_backtrace (addresses[2], 128);
|
||||
|
||||
if (verbose)
|
||||
for (i = 0; i < m; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, addresses[2][i]);
|
||||
|
||||
if (m != depth+1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m);
|
||||
++num_errors;
|
||||
}
|
||||
|
||||
if (n != depth+1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n);
|
||||
++num_errors;
|
||||
}
|
||||
|
||||
if (n == m)
|
||||
for (i = 1; i < n; ++i)
|
||||
/* Allow one in difference in comparison, trace returns adjusted addresses. */
|
||||
if (labs (addresses[1][i] - addresses[2][i]) > 1)
|
||||
{
|
||||
printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n",
|
||||
i, addresses[1][i], addresses[2][i]);
|
||||
++num_errors;
|
||||
}
|
||||
|
||||
if (n == depth+1)
|
||||
for (i = 1; i < depth; ++i)
|
||||
/* Allow one in difference in comparison, trace returns adjusted addresses. */
|
||||
if (labs (addresses[0][i] - addresses[1][i]) > 1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n",
|
||||
i, addresses[0][i], addresses[1][i]);
|
||||
++num_errors;
|
||||
}
|
||||
/*
|
||||
* Call `unw_backtrace2()` on the current context and compare with the
|
||||
* `unw_step()`results. They should be identical.
|
||||
*/
|
||||
int unw_backtrace2_depth = unw_backtrace2 (trace[TEST_UNW_BACKTRACE2].addresses,
|
||||
MAX_BACKTRACE_SIZE,
|
||||
&uc,
|
||||
0);
|
||||
dump_backtrace(unw_backtrace2_depth, TEST_UNW_BACKTRACE2);
|
||||
compare_backtraces(unw_step_depth, unw_backtrace2_depth, TEST_UNW_BACKTRACE2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exercises `unw_backtrace2()` using the context passed in to a signal
|
||||
* handler. Compares the result of a raw `unw_step()` loop with the result of
|
||||
* the `unw_backtrace2()` call, which may have taken the "fast path" (using
|
||||
* cached data).
|
||||
*/
|
||||
void
|
||||
do_backtrace_with_context(void *context)
|
||||
{
|
||||
unw_word_t ip;
|
||||
int ret = -UNW_ENOINFO;
|
||||
int depth = 0;
|
||||
int i, m;
|
||||
int unw_step_depth = 0;
|
||||
int unw_backtrace2_depth;
|
||||
|
||||
if (verbose)
|
||||
printf ("\tnormal trace:\n");
|
||||
{
|
||||
printf ("\nbacktrace with explicit context:\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a naked `unw_step()` loop on the passed context and save the IPs.
|
||||
*/
|
||||
if (unw_init_local2 (&cursor, (unw_context_t*)context, UNW_INIT_SIGNAL_FRAME) < 0)
|
||||
panic ("unw_init_local2 failed!\n");
|
||||
|
||||
do
|
||||
{
|
||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||
addresses[0][depth] = (void *) ip;
|
||||
trace[TEST_UNW_STEP].addresses[unw_step_depth++] = (void *) ip;
|
||||
}
|
||||
while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
|
||||
|
||||
while ((ret = unw_step (&cursor)) > 0 && unw_step_depth < MAX_BACKTRACE_SIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||
printf ("FAILURE: unw_step() returned %d for ip=%#010lx\n", ret, (long) ip);
|
||||
++num_errors;
|
||||
}
|
||||
dump_backtrace(unw_step_depth, TEST_UNW_STEP);
|
||||
|
||||
if (verbose)
|
||||
for (i = 0; i < depth; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
|
||||
|
||||
if (verbose)
|
||||
printf ("\n\tvia unw_backtrace2():\n");
|
||||
|
||||
m = unw_backtrace2 (addresses[1], 128, (unw_context_t*)context, UNW_INIT_SIGNAL_FRAME);
|
||||
|
||||
if (verbose)
|
||||
for (i = 0; i < m; ++i)
|
||||
printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
|
||||
|
||||
if (m != depth+1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and unw_backtrace2() depths differ: %d vs. %d\n", depth, m);
|
||||
++num_errors;
|
||||
}
|
||||
|
||||
if (m == depth + 1)
|
||||
for (i = 0; i < depth; ++i)
|
||||
/* Allow one in difference in comparison, trace returns adjusted addresses. */
|
||||
if ( labs(addresses[0][i] - addresses[1][i]) > 1)
|
||||
{
|
||||
printf ("FAILURE: unw_step() loop and unw_backtrace2() addresses differ at %d: %p vs. %p\n",
|
||||
i, addresses[0][i], addresses[1][i]);
|
||||
++num_errors;
|
||||
}
|
||||
/*
|
||||
* Call `unw_backtrace2()` on the passed context and compare with the
|
||||
* `unw_step()`results. They should be identical.
|
||||
*/
|
||||
unw_backtrace2_depth = unw_backtrace2 (trace[TEST_UNW_BACKTRACE2].addresses,
|
||||
MAX_BACKTRACE_SIZE,
|
||||
(unw_context_t*)context,
|
||||
UNW_INIT_SIGNAL_FRAME);
|
||||
dump_backtrace(unw_backtrace2_depth, TEST_UNW_BACKTRACE2);
|
||||
compare_backtraces(unw_step_depth, unw_backtrace2_depth, TEST_UNW_BACKTRACE2);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -239,48 +296,47 @@ bar (long v)
|
||||
void
|
||||
sighandler (int signal, siginfo_t *siginfo UNUSED, void *context)
|
||||
{
|
||||
ucontext_t *uc UNUSED;
|
||||
int sp;
|
||||
|
||||
uc = context;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int sp;
|
||||
ucontext_t *ctxt UNUSED = context;
|
||||
|
||||
printf ("sighandler: got signal %d, sp=%p", signal, (void *)&sp);
|
||||
#if UNW_TARGET_IA64
|
||||
# if defined(__linux__)
|
||||
printf (" @ %#010lx", uc->uc_mcontext.sc_ip);
|
||||
printf (" @ %#010lx", ctxt->uc_mcontext.sc_ip);
|
||||
# else
|
||||
{
|
||||
uint16_t reason;
|
||||
uint64_t ip;
|
||||
uint16_t reason;
|
||||
uint64_t ip;
|
||||
|
||||
__uc_get_reason (uc, &reason);
|
||||
__uc_get_ip (uc, &ip);
|
||||
printf (" @ %#010lx (reason=%d)", ip, reason);
|
||||
__uc_get_reason (ctxt, &reason);
|
||||
__uc_get_ip (ctxt, &ip);
|
||||
printf (" @ %#010lx (reason=%d)", ip, reason);
|
||||
}
|
||||
# endif
|
||||
#elif UNW_TARGET_X86
|
||||
#if defined __linux__
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined __FreeBSD__
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.mc_eip);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.mc_eip);
|
||||
#endif
|
||||
#elif UNW_TARGET_X86_64
|
||||
#if defined __linux__ || defined __sun
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.gregs[REG_RIP]);
|
||||
#elif defined __FreeBSD__
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.mc_rip);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.mc_rip);
|
||||
#endif
|
||||
#elif defined UNW_TARGET_ARM
|
||||
#if defined __linux__
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.arm_pc);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.arm_pc);
|
||||
#elif defined __FreeBSD__
|
||||
printf (" @ %#010lx", (unsigned long) uc->uc_mcontext.__gregs[_REG_PC]);
|
||||
printf (" @ %#010lx", (unsigned long) ctxt->uc_mcontext.__gregs[_REG_PC]);
|
||||
#endif
|
||||
#endif
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
do_backtrace();
|
||||
do_backtrace_with_context(context);
|
||||
}
|
||||
@@ -306,9 +362,16 @@ main (int argc, char **argv UNUSED)
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
panic ("sigaction: %s\n", strerror (errno));
|
||||
|
||||
if (verbose)
|
||||
printf ("\nBacktrace across signal handler:\n");
|
||||
kill (getpid (), SIGTERM);
|
||||
/*
|
||||
* Repeatedly invoke the signal hander to make sure any global cache does not
|
||||
* get corrupted.
|
||||
*/
|
||||
for (int i = 0; i < repeat_count; ++i)
|
||||
{
|
||||
if (verbose)
|
||||
printf ("\nBacktrace across signal handler (iteration %d):\n", i+1);
|
||||
kill (getpid (), SIGTERM);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGALTSTACK
|
||||
if (verbose)
|
||||
@@ -326,6 +389,7 @@ main (int argc, char **argv UNUSED)
|
||||
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
panic ("sigaction: %s\n", strerror (errno));
|
||||
|
||||
kill (getpid (), SIGTERM);
|
||||
#endif /* HAVE_SIGALTSTACK */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user