xref: /dpdk/lib/eal/unix/eal_debug.c (revision 0efcd352e257ae88a16667b8b6d5dcf0319a4192)
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  */
safe_itoa(long val,char * buf,size_t len,unsigned int radix)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  */
rte_dump_stack(void)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 */
rte_dump_stack(void)125 void rte_dump_stack(void) { }
126 
127 #endif /* RTE_BACKTRACE */
128