xref: /freebsd-src/sys/contrib/openzfs/lib/libspl/backtrace.c (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
1aca928a5SMartin Matuska /*
2aca928a5SMartin Matuska  * CDDL HEADER START
3aca928a5SMartin Matuska  *
4aca928a5SMartin Matuska  * The contents of this file are subject to the terms of the
5aca928a5SMartin Matuska  * Common Development and Distribution License (the "License").
6aca928a5SMartin Matuska  * You may not use this file except in compliance with the License.
7aca928a5SMartin Matuska  *
8aca928a5SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9aca928a5SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10aca928a5SMartin Matuska  * See the License for the specific language governing permissions
11aca928a5SMartin Matuska  * and limitations under the License.
12aca928a5SMartin Matuska  *
13aca928a5SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14aca928a5SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15aca928a5SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16aca928a5SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17aca928a5SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18aca928a5SMartin Matuska  *
19aca928a5SMartin Matuska  * CDDL HEADER END
20aca928a5SMartin Matuska  */
21aca928a5SMartin Matuska /*
22aca928a5SMartin Matuska  * Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
23aca928a5SMartin Matuska  * Copyright (c) 2024, Klara Inc.
24aca928a5SMartin Matuska  */
25aca928a5SMartin Matuska 
26aca928a5SMartin Matuska #include <sys/backtrace.h>
27aca928a5SMartin Matuska #include <sys/types.h>
2887bf66d4SMartin Matuska #include <sys/debug.h>
29aca928a5SMartin Matuska #include <unistd.h>
30aca928a5SMartin Matuska 
31aca928a5SMartin Matuska /*
3287bf66d4SMartin Matuska  * Output helpers. libspl_backtrace() must not block, must be thread-safe and
3387bf66d4SMartin Matuska  * must be safe to call from a signal handler. At least, that means not having
3487bf66d4SMartin Matuska  * printf, so we end up having to call write() directly on the fd. That's
3587bf66d4SMartin Matuska  * awkward, as we always have to pass through a length, and some systems will
3687bf66d4SMartin Matuska  * complain if we don't consume the return. So we have some macros to make
3787bf66d4SMartin Matuska  * things a little more palatable.
38aca928a5SMartin Matuska  */
3987bf66d4SMartin Matuska #define	spl_bt_write_n(fd, s, n) \
4087bf66d4SMartin Matuska 	do { ssize_t r __maybe_unused = write(fd, s, n); } while (0)
41*dd215568SMartin Matuska #define	spl_bt_write(fd, s)		spl_bt_write_n(fd, s, sizeof (s)-1)
42aca928a5SMartin Matuska 
43aca928a5SMartin Matuska #if defined(HAVE_LIBUNWIND)
44aca928a5SMartin Matuska #define	UNW_LOCAL_ONLY
45aca928a5SMartin Matuska #include <libunwind.h>
46aca928a5SMartin Matuska 
4787bf66d4SMartin Matuska /*
4887bf66d4SMartin Matuska  * Convert `v` to ASCII hex characters. The bottom `n` nybbles (4-bits ie one
4987bf66d4SMartin Matuska  * hex digit) will be written, up to `buflen`. The buffer will not be
5087bf66d4SMartin Matuska  * null-terminated. Returns the number of digits written.
5187bf66d4SMartin Matuska  */
52aca928a5SMartin Matuska static size_t
5387bf66d4SMartin Matuska spl_bt_u64_to_hex_str(uint64_t v, size_t n, char *buf, size_t buflen)
54aca928a5SMartin Matuska {
55aca928a5SMartin Matuska 	static const char hexdigits[] = {
56aca928a5SMartin Matuska 	    '0', '1', '2', '3', '4', '5', '6', '7',
57aca928a5SMartin Matuska 	    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
58aca928a5SMartin Matuska 	};
59aca928a5SMartin Matuska 
60aca928a5SMartin Matuska 	size_t pos = 0;
6187bf66d4SMartin Matuska 	boolean_t want = (n == 0);
62aca928a5SMartin Matuska 	for (int i = 15; i >= 0; i--) {
63aca928a5SMartin Matuska 		const uint64_t d = v >> (i * 4) & 0xf;
6487bf66d4SMartin Matuska 		if (!want && (d != 0 || n > i))
65aca928a5SMartin Matuska 			want = B_TRUE;
66aca928a5SMartin Matuska 		if (want) {
67aca928a5SMartin Matuska 			buf[pos++] = hexdigits[d];
68aca928a5SMartin Matuska 			if (pos == buflen)
69aca928a5SMartin Matuska 				break;
70aca928a5SMartin Matuska 		}
71aca928a5SMartin Matuska 	}
72aca928a5SMartin Matuska 	return (pos);
73aca928a5SMartin Matuska }
74aca928a5SMartin Matuska 
75aca928a5SMartin Matuska void
76aca928a5SMartin Matuska libspl_backtrace(int fd)
77aca928a5SMartin Matuska {
78aca928a5SMartin Matuska 	unw_context_t uc;
79aca928a5SMartin Matuska 	unw_cursor_t cp;
8087bf66d4SMartin Matuska 	unw_word_t v;
81aca928a5SMartin Matuska 	char buf[128];
82aca928a5SMartin Matuska 	size_t n;
8387bf66d4SMartin Matuska 	int err;
84aca928a5SMartin Matuska 
8587bf66d4SMartin Matuska 	/* Snapshot the current frame and state. */
86aca928a5SMartin Matuska 	unw_getcontext(&uc);
8787bf66d4SMartin Matuska 
8887bf66d4SMartin Matuska 	/*
8987bf66d4SMartin Matuska 	 * TODO: walk back to the frame that tripped the assertion / the place
9087bf66d4SMartin Matuska 	 *       where the signal was recieved.
9187bf66d4SMartin Matuska 	 */
9287bf66d4SMartin Matuska 
9387bf66d4SMartin Matuska 	/*
9487bf66d4SMartin Matuska 	 * Register dump. We're going to loop over all the registers in the
9587bf66d4SMartin Matuska 	 * top frame, and show them, with names, in a nice three-column
9687bf66d4SMartin Matuska 	 * layout, which keeps us within 80 columns.
9787bf66d4SMartin Matuska 	 */
9887bf66d4SMartin Matuska 	spl_bt_write(fd, "Registers:\n");
9987bf66d4SMartin Matuska 
10087bf66d4SMartin Matuska 	/* Initialise a frame cursor, starting at the current frame */
101aca928a5SMartin Matuska 	unw_init_local(&cp, &uc);
10287bf66d4SMartin Matuska 
10387bf66d4SMartin Matuska 	/*
10487bf66d4SMartin Matuska 	 * libunwind's list of possible registers for this architecture is an
10587bf66d4SMartin Matuska 	 * enum, unw_regnum_t. UNW_TDEP_LAST_REG is the highest-numbered
10687bf66d4SMartin Matuska 	 * register in that list, however, not all register numbers in this
10787bf66d4SMartin Matuska 	 * range are defined by the architecture, and not all defined registers
10887bf66d4SMartin Matuska 	 * will be present on every implementation of that architecture.
10987bf66d4SMartin Matuska 	 * Moreover, libunwind provides nice names for most, but not all
11087bf66d4SMartin Matuska 	 * registers, but these are hardcoded; a name being available does not
11187bf66d4SMartin Matuska 	 * mean that register is available.
11287bf66d4SMartin Matuska 	 *
11387bf66d4SMartin Matuska 	 * So, we have to pull this all together here. We try to get the value
11487bf66d4SMartin Matuska 	 * of every possible register. If we get a value for it, then the
11587bf66d4SMartin Matuska 	 * register must exist, and so we get its name. If libunwind has no
11687bf66d4SMartin Matuska 	 * name for it, we synthesize something. These cases should be rare,
11787bf66d4SMartin Matuska 	 * and they're usually for uninteresting or niche registers, so it
11887bf66d4SMartin Matuska 	 * shouldn't really matter. We can see the value, and that's the main
11987bf66d4SMartin Matuska 	 * thing.
12087bf66d4SMartin Matuska 	 */
12187bf66d4SMartin Matuska 	uint_t cols = 0;
12287bf66d4SMartin Matuska 	for (uint_t regnum = 0; regnum <= UNW_TDEP_LAST_REG; regnum++) {
12387bf66d4SMartin Matuska 		/*
12487bf66d4SMartin Matuska 		 * Get the value. Any error probably means the register
12587bf66d4SMartin Matuska 		 * doesn't exist, and we skip it.
12687bf66d4SMartin Matuska 		 */
12787bf66d4SMartin Matuska 		if (unw_get_reg(&cp, regnum, &v) < 0)
12887bf66d4SMartin Matuska 			continue;
12987bf66d4SMartin Matuska 
13087bf66d4SMartin Matuska 		/*
13187bf66d4SMartin Matuska 		 * Register name. If libunwind doesn't have a name for it,
13287bf66d4SMartin Matuska 		 * it will return "???". As a shortcut, we just treat '?'
13387bf66d4SMartin Matuska 		 * is an alternate end-of-string character.
13487bf66d4SMartin Matuska 		 */
13587bf66d4SMartin Matuska 		const char *name = unw_regname(regnum);
13687bf66d4SMartin Matuska 		for (n = 0; name[n] != '\0' && name[n] != '?'; n++) {}
13787bf66d4SMartin Matuska 		if (n == 0) {
13887bf66d4SMartin Matuska 			/*
13987bf66d4SMartin Matuska 			 * No valid name, so make one of the form "?xx", where
14087bf66d4SMartin Matuska 			 * "xx" is the two-char hex of libunwind's register
14187bf66d4SMartin Matuska 			 * number.
14287bf66d4SMartin Matuska 			 */
14387bf66d4SMartin Matuska 			buf[0] = '?';
14487bf66d4SMartin Matuska 			n = spl_bt_u64_to_hex_str(regnum, 2,
14587bf66d4SMartin Matuska 			    &buf[1], sizeof (buf)-1) + 1;
14687bf66d4SMartin Matuska 			name = buf;
147aca928a5SMartin Matuska 		}
14887bf66d4SMartin Matuska 
14987bf66d4SMartin Matuska 		/*
15087bf66d4SMartin Matuska 		 * Two spaces of padding before each column, plus extra
15187bf66d4SMartin Matuska 		 * spaces to align register names shorter than three chars.
15287bf66d4SMartin Matuska 		 */
15387bf66d4SMartin Matuska 		spl_bt_write_n(fd, "      ", 5-MIN(n, 3));
15487bf66d4SMartin Matuska 
15587bf66d4SMartin Matuska 		/* Register name and column punctuation */
15687bf66d4SMartin Matuska 		spl_bt_write_n(fd, name, n);
15787bf66d4SMartin Matuska 		spl_bt_write(fd, ": 0x");
15887bf66d4SMartin Matuska 
15987bf66d4SMartin Matuska 		/*
16087bf66d4SMartin Matuska 		 * Convert register value (from unw_get_reg()) to hex. We're
16187bf66d4SMartin Matuska 		 * assuming that all registers are 64-bits wide, which is
16287bf66d4SMartin Matuska 		 * probably fine for any general-purpose registers on any
16387bf66d4SMartin Matuska 		 * machine currently in use. A more generic way would be to
16487bf66d4SMartin Matuska 		 * look at the width of unw_word_t, but that would also
16587bf66d4SMartin Matuska 		 * complicate the column code a bit. This is fine.
16687bf66d4SMartin Matuska 		 */
16787bf66d4SMartin Matuska 		n = spl_bt_u64_to_hex_str(v, 16, buf, sizeof (buf));
16887bf66d4SMartin Matuska 		spl_bt_write_n(fd, buf, n);
16987bf66d4SMartin Matuska 
17087bf66d4SMartin Matuska 		/* Every third column, emit a newline */
17187bf66d4SMartin Matuska 		if (!(++cols % 3))
17287bf66d4SMartin Matuska 			spl_bt_write(fd, "\n");
17387bf66d4SMartin Matuska 	}
17487bf66d4SMartin Matuska 
17587bf66d4SMartin Matuska 	/* If we finished before the third column, emit a newline. */
17687bf66d4SMartin Matuska 	if (cols % 3)
17787bf66d4SMartin Matuska 		spl_bt_write(fd, "\n");
17887bf66d4SMartin Matuska 
17987bf66d4SMartin Matuska 	/* Now the main event, the backtrace. */
18087bf66d4SMartin Matuska 	spl_bt_write(fd, "Call trace:\n");
18187bf66d4SMartin Matuska 
18287bf66d4SMartin Matuska 	/* Reset the cursor to the top again. */
18387bf66d4SMartin Matuska 	unw_init_local(&cp, &uc);
18487bf66d4SMartin Matuska 
18587bf66d4SMartin Matuska 	do {
18687bf66d4SMartin Matuska 		/*
18787bf66d4SMartin Matuska 		 * Getting the IP should never fail; libunwind handles it
18887bf66d4SMartin Matuska 		 * specially, because its used a lot internally. Still, no
18987bf66d4SMartin Matuska 		 * point being silly about it, as the last thing we want is
19087bf66d4SMartin Matuska 		 * our crash handler to crash. So if it ever does fail, we'll
19187bf66d4SMartin Matuska 		 * show an error line, but keep going to the next frame.
19287bf66d4SMartin Matuska 		 */
19387bf66d4SMartin Matuska 		if (unw_get_reg(&cp, UNW_REG_IP, &v) < 0) {
19487bf66d4SMartin Matuska 			spl_bt_write(fd, "  [couldn't get IP register; "
19587bf66d4SMartin Matuska 			    "corrupt frame?]");
19687bf66d4SMartin Matuska 			continue;
19787bf66d4SMartin Matuska 		}
19887bf66d4SMartin Matuska 
19987bf66d4SMartin Matuska 		/* IP & punctuation */
20087bf66d4SMartin Matuska 		n = spl_bt_u64_to_hex_str(v, 16, buf, sizeof (buf));
20187bf66d4SMartin Matuska 		spl_bt_write(fd, "  [0x");
20287bf66d4SMartin Matuska 		spl_bt_write_n(fd, buf, n);
20387bf66d4SMartin Matuska 		spl_bt_write(fd, "] ");
20487bf66d4SMartin Matuska 
20587bf66d4SMartin Matuska 		/*
20687bf66d4SMartin Matuska 		 * Function ("procedure") name for the current frame. `v`
20787bf66d4SMartin Matuska 		 * receives the offset from the named function to the IP, which
20887bf66d4SMartin Matuska 		 * we show as a "+offset" suffix.
20987bf66d4SMartin Matuska 		 *
21087bf66d4SMartin Matuska 		 * If libunwind can't determine the name, we just show "???"
21187bf66d4SMartin Matuska 		 * instead. We've already displayed the IP above; that will
21287bf66d4SMartin Matuska 		 * have to do.
21387bf66d4SMartin Matuska 		 *
21487bf66d4SMartin Matuska 		 * unw_get_proc_name() will return ENOMEM if the buffer is too
21587bf66d4SMartin Matuska 		 * small, instead truncating the name. So we treat that as a
21687bf66d4SMartin Matuska 		 * success and use whatever is in the buffer.
21787bf66d4SMartin Matuska 		 */
21887bf66d4SMartin Matuska 		err = unw_get_proc_name(&cp, buf, sizeof (buf), &v);
21987bf66d4SMartin Matuska 		if (err == 0 || err == -UNW_ENOMEM) {
22087bf66d4SMartin Matuska 			for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {}
22187bf66d4SMartin Matuska 			spl_bt_write_n(fd, buf, n);
22287bf66d4SMartin Matuska 
22387bf66d4SMartin Matuska 			/* Offset from proc name */
22487bf66d4SMartin Matuska 			spl_bt_write(fd, "+0x");
22587bf66d4SMartin Matuska 			n = spl_bt_u64_to_hex_str(v, 2, buf, sizeof (buf));
22687bf66d4SMartin Matuska 			spl_bt_write_n(fd, buf, n);
22787bf66d4SMartin Matuska 		} else
22887bf66d4SMartin Matuska 			spl_bt_write(fd, "???");
22987bf66d4SMartin Matuska 
23087bf66d4SMartin Matuska #ifdef HAVE_LIBUNWIND_ELF
23187bf66d4SMartin Matuska 		/*
23287bf66d4SMartin Matuska 		 * Newer libunwind has unw_get_elf_filename(), which gets
23387bf66d4SMartin Matuska 		 * the name of the ELF object that the frame was executing in.
23487bf66d4SMartin Matuska 		 * Like `unw_get_proc_name()`, `v` recieves the offset within
23587bf66d4SMartin Matuska 		 * the file, and UNW_ENOMEM indicates that a truncate filename
23687bf66d4SMartin Matuska 		 * was left in the buffer.
23787bf66d4SMartin Matuska 		 */
23887bf66d4SMartin Matuska 		err = unw_get_elf_filename(&cp, buf, sizeof (buf), &v);
23987bf66d4SMartin Matuska 		if (err == 0 || err == -UNW_ENOMEM) {
24087bf66d4SMartin Matuska 			for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {}
24187bf66d4SMartin Matuska 			spl_bt_write(fd, " (in ");
24287bf66d4SMartin Matuska 			spl_bt_write_n(fd, buf, n);
24387bf66d4SMartin Matuska 
24487bf66d4SMartin Matuska 			/* Offset within file */
24587bf66d4SMartin Matuska 			spl_bt_write(fd, " +0x");
24687bf66d4SMartin Matuska 			n = spl_bt_u64_to_hex_str(v, 2, buf, sizeof (buf));
24787bf66d4SMartin Matuska 			spl_bt_write_n(fd, buf, n);
24887bf66d4SMartin Matuska 			spl_bt_write(fd, ")");
24987bf66d4SMartin Matuska 		}
25087bf66d4SMartin Matuska #endif
25187bf66d4SMartin Matuska 		spl_bt_write(fd, "\n");
25287bf66d4SMartin Matuska 	} while (unw_step(&cp) > 0);
253aca928a5SMartin Matuska }
254aca928a5SMartin Matuska #elif defined(HAVE_BACKTRACE)
255aca928a5SMartin Matuska #include <execinfo.h>
256aca928a5SMartin Matuska 
257aca928a5SMartin Matuska void
258aca928a5SMartin Matuska libspl_backtrace(int fd)
259aca928a5SMartin Matuska {
260aca928a5SMartin Matuska 	void *btptrs[64];
261aca928a5SMartin Matuska 	size_t nptrs = backtrace(btptrs, 64);
26287bf66d4SMartin Matuska 	spl_bt_write(fd, "Call trace:\n");
263aca928a5SMartin Matuska 	backtrace_symbols_fd(btptrs, nptrs, fd);
264aca928a5SMartin Matuska }
265aca928a5SMartin Matuska #else
266aca928a5SMartin Matuska void
267aca928a5SMartin Matuska libspl_backtrace(int fd __maybe_unused)
268aca928a5SMartin Matuska {
269aca928a5SMartin Matuska }
270aca928a5SMartin Matuska #endif
271