1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <rte_debug.h> 6 7 #ifdef RTE_BACKTRACE 8 9 #include <dlfcn.h> 10 #include <execinfo.h> 11 #include <string.h> 12 #include <sys/uio.h> 13 #include <unistd.h> 14 15 #define BACKTRACE_SIZE 256 16 17 /* 18 * Convert number to string and return start of string. 19 * Note: string does not start at beginning of buffer. 20 */ 21 static char *safe_itoa(long val, char *buf, size_t len, unsigned int radix) 22 { 23 char *bp = buf + len; 24 static const char hexdigit[] = "0123456789abcdef"; 25 26 *--bp = '\0'; /* Null terminate the string */ 27 do { 28 /* if buffer is not big enough, then truncate */ 29 if (bp == buf) 30 return bp; 31 32 *--bp = hexdigit[val % radix]; 33 val /= radix; 34 } while (val != 0); 35 36 return bp; 37 } 38 39 /* 40 * Dump the stack of the calling core 41 * 42 * To be safe in signal handler requires limiting what functions are 43 * used in this code since may be called from inside libc or 44 * when malloc poll is corrupt. 45 * 46 * Most of libc is therefore not safe, include RTE_LOG (calls syslog); 47 * backtrace_symbols (calls malloc), etc. 48 */ 49 void rte_dump_stack(void) 50 { 51 void *func[BACKTRACE_SIZE]; 52 Dl_info info; 53 char buf1[8], buf2[32], buf3[32], buf4[32]; 54 struct iovec iov[10]; 55 int i, size; 56 57 size = backtrace(func, BACKTRACE_SIZE); 58 59 for (i = 0; i < size; i++) { 60 struct iovec *io = iov; 61 char *str; 62 uintptr_t base; 63 long offset; 64 void *pc = func[i]; 65 66 /* 67 * Macro to put string onto set of iovecs. 68 * cast is to suppress warnings about lose of const qualifier. 69 */ 70 #define PUSH_IOV(io, str) { \ 71 (io)->iov_base = (char *)(uintptr_t)str; \ 72 (io)->iov_len = strlen(str); \ 73 ++io; } 74 75 /* output stack frame number */ 76 str = safe_itoa(i, buf1, sizeof(buf1), 10); 77 PUSH_IOV(io, str); /* iov[0] */ 78 PUSH_IOV(io, ": "); /* iov[1] */ 79 80 /* Lookup the symbol information */ 81 if (dladdr(pc, &info) == 0) { 82 PUSH_IOV(io, "?? ["); 83 } else { 84 const char *fname; 85 86 if (info.dli_fname && *info.dli_fname) 87 fname = info.dli_fname; 88 else 89 fname = "(vdso)"; 90 PUSH_IOV(io, fname); /* iov[2] */ 91 PUSH_IOV(io, " ("); /* iov[3] */ 92 93 if (info.dli_saddr != NULL) { 94 PUSH_IOV(io, info.dli_sname); /* iov[4] */ 95 base = (uintptr_t)info.dli_saddr; 96 } else { 97 str = safe_itoa((unsigned long)info.dli_fbase, 98 buf3, sizeof(buf3), 16); 99 PUSH_IOV(io, str); 100 base = (uintptr_t)info.dli_fbase; 101 } 102 103 PUSH_IOV(io, "+0x"); /* iov[5] */ 104 105 offset = (uintptr_t)pc - base; 106 str = safe_itoa(offset, buf4, sizeof(buf4), 16); 107 PUSH_IOV(io, str); /* iov[6] */ 108 109 PUSH_IOV(io, ") ["); /* iov[7] */ 110 } 111 112 str = safe_itoa((unsigned long)pc, buf2, sizeof(buf2), 16); 113 PUSH_IOV(io, str); /* iov[8] */ 114 PUSH_IOV(io, "]\n"); /* iov[9] */ 115 116 if (writev(STDERR_FILENO, iov, io - iov) < 0) 117 break; 118 #undef PUSH_IOV 119 } 120 } 121 122 #else /* !RTE_BACKTRACE */ 123 124 /* stub if not enabled */ 125 void rte_dump_stack(void) { } 126 127 #endif /* RTE_BACKTRACE */ 128