0efcd352e2
rte_dump_stack() needs to be usable in situations when a bug is encountered and from signal handlers (such as SEGV). Glibc backtrace_symbols() calls malloc which makes it dangerous in a signal handler that is handling errors that maybe due to memory corruption. Additionally, rte_log() is unsafe because syslog() is not signal safe; printf() is also documented as not being safe. This version formats message and uses writev for each line in a manner similar to what glibc version of backtrace_symbols_fd() does. The FreeBSD version of backtrace_symbols_fd() is not signal safe. Sample output: 0: ./build/app/dpdk-testpmd (rte_dump_stack+0x2b) [560a6e9c002b] 1: ./build/app/dpdk-testpmd (main+0xad) [560a6decd5ad] 2: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xcd) [7fd43d3e27fd] 3: ./build/app/dpdk-testpmd (_start+0x2a) [560a6e83628a] Bugzilla ID: 929 Acked-by: Morten Brørup <mb@smartsharesystems.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Reviewed-by: David Marchand <david.marchand@redhat.com>
128 lines
2.8 KiB
C
128 lines
2.8 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2010-2014 Intel Corporation
|
|
*/
|
|
|
|
#include <rte_debug.h>
|
|
|
|
#ifdef RTE_BACKTRACE
|
|
|
|
#include <dlfcn.h>
|
|
#include <execinfo.h>
|
|
#include <string.h>
|
|
#include <sys/uio.h>
|
|
#include <unistd.h>
|
|
|
|
#define BACKTRACE_SIZE 256
|
|
|
|
/*
|
|
* Convert number to string and return start of string.
|
|
* Note: string does not start at beginning of buffer.
|
|
*/
|
|
static char *safe_itoa(long val, char *buf, size_t len, unsigned int radix)
|
|
{
|
|
char *bp = buf + len;
|
|
static const char hexdigit[] = "0123456789abcdef";
|
|
|
|
*--bp = '\0'; /* Null terminate the string */
|
|
do {
|
|
/* if buffer is not big enough, then truncate */
|
|
if (bp == buf)
|
|
return bp;
|
|
|
|
*--bp = hexdigit[val % radix];
|
|
val /= radix;
|
|
} while (val != 0);
|
|
|
|
return bp;
|
|
}
|
|
|
|
/*
|
|
* Dump the stack of the calling core
|
|
*
|
|
* To be safe in signal handler requires limiting what functions are
|
|
* used in this code since may be called from inside libc or
|
|
* when malloc poll is corrupt.
|
|
*
|
|
* Most of libc is therefore not safe, include RTE_LOG (calls syslog);
|
|
* backtrace_symbols (calls malloc), etc.
|
|
*/
|
|
void rte_dump_stack(void)
|
|
{
|
|
void *func[BACKTRACE_SIZE];
|
|
Dl_info info;
|
|
char buf1[8], buf2[32], buf3[32], buf4[32];
|
|
struct iovec iov[10];
|
|
int i, size;
|
|
|
|
size = backtrace(func, BACKTRACE_SIZE);
|
|
|
|
for (i = 0; i < size; i++) {
|
|
struct iovec *io = iov;
|
|
char *str;
|
|
uintptr_t base;
|
|
long offset;
|
|
void *pc = func[i];
|
|
|
|
/*
|
|
* Macro to put string onto set of iovecs.
|
|
* cast is to suppress warnings about lose of const qualifier.
|
|
*/
|
|
#define PUSH_IOV(io, str) { \
|
|
(io)->iov_base = (char *)(uintptr_t)str; \
|
|
(io)->iov_len = strlen(str); \
|
|
++io; }
|
|
|
|
/* output stack frame number */
|
|
str = safe_itoa(i, buf1, sizeof(buf1), 10);
|
|
PUSH_IOV(io, str); /* iov[0] */
|
|
PUSH_IOV(io, ": "); /* iov[1] */
|
|
|
|
/* Lookup the symbol information */
|
|
if (dladdr(pc, &info) == 0) {
|
|
PUSH_IOV(io, "?? [");
|
|
} else {
|
|
const char *fname;
|
|
|
|
if (info.dli_fname && *info.dli_fname)
|
|
fname = info.dli_fname;
|
|
else
|
|
fname = "(vdso)";
|
|
PUSH_IOV(io, fname); /* iov[2] */
|
|
PUSH_IOV(io, " ("); /* iov[3] */
|
|
|
|
if (info.dli_saddr != NULL) {
|
|
PUSH_IOV(io, info.dli_sname); /* iov[4] */
|
|
base = (uintptr_t)info.dli_saddr;
|
|
} else {
|
|
str = safe_itoa((unsigned long)info.dli_fbase,
|
|
buf3, sizeof(buf3), 16);
|
|
PUSH_IOV(io, str);
|
|
base = (uintptr_t)info.dli_fbase;
|
|
}
|
|
|
|
PUSH_IOV(io, "+0x"); /* iov[5] */
|
|
|
|
offset = (uintptr_t)pc - base;
|
|
str = safe_itoa(offset, buf4, sizeof(buf4), 16);
|
|
PUSH_IOV(io, str); /* iov[6] */
|
|
|
|
PUSH_IOV(io, ") ["); /* iov[7] */
|
|
}
|
|
|
|
str = safe_itoa((unsigned long)pc, buf2, sizeof(buf2), 16);
|
|
PUSH_IOV(io, str); /* iov[8] */
|
|
PUSH_IOV(io, "]\n"); /* iov[9] */
|
|
|
|
if (writev(STDERR_FILENO, iov, io - iov) < 0)
|
|
break;
|
|
#undef PUSH_IOV
|
|
}
|
|
}
|
|
|
|
#else /* !RTE_BACKTRACE */
|
|
|
|
/* stub if not enabled */
|
|
void rte_dump_stack(void) { }
|
|
|
|
#endif /* RTE_BACKTRACE */
|