1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 24 * Copyright (c) 2024, Klara Inc. 25 */ 26 27 #include <sys/backtrace.h> 28 #include <sys/types.h> 29 #include <sys/debug.h> 30 #include <unistd.h> 31 32 /* 33 * Output helpers. libspl_backtrace() must not block, must be thread-safe and 34 * must be safe to call from a signal handler. At least, that means not having 35 * printf, so we end up having to call write() directly on the fd. That's 36 * awkward, as we always have to pass through a length, and some systems will 37 * complain if we don't consume the return. So we have some macros to make 38 * things a little more palatable. 39 */ 40 #define spl_bt_write_n(fd, s, n) \ 41 do { ssize_t r __maybe_unused = write(fd, s, n); } while (0) 42 #define spl_bt_write(fd, s) spl_bt_write_n(fd, s, sizeof (s)-1) 43 44 #if defined(HAVE_LIBUNWIND) 45 #define UNW_LOCAL_ONLY 46 #include <libunwind.h> 47 48 /* 49 * Convert `v` to ASCII hex characters. The bottom `n` nybbles (4-bits ie one 50 * hex digit) will be written, up to `buflen`. The buffer will not be 51 * null-terminated. Returns the number of digits written. 52 */ 53 static size_t 54 spl_bt_u64_to_hex_str(uint64_t v, size_t n, char *buf, size_t buflen) 55 { 56 static const char hexdigits[] = { 57 '0', '1', '2', '3', '4', '5', '6', '7', 58 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 59 }; 60 61 size_t pos = 0; 62 boolean_t want = (n == 0); 63 for (int i = 15; i >= 0; i--) { 64 const uint64_t d = v >> (i * 4) & 0xf; 65 if (!want && (d != 0 || n > i)) 66 want = B_TRUE; 67 if (want) { 68 buf[pos++] = hexdigits[d]; 69 if (pos == buflen) 70 break; 71 } 72 } 73 return (pos); 74 } 75 76 void 77 libspl_backtrace(int fd) 78 { 79 unw_context_t uc; 80 unw_cursor_t cp; 81 unw_word_t v; 82 char buf[128]; 83 size_t n; 84 int err; 85 86 /* Snapshot the current frame and state. */ 87 unw_getcontext(&uc); 88 89 /* 90 * TODO: walk back to the frame that tripped the assertion / the place 91 * where the signal was recieved. 92 */ 93 94 /* 95 * Register dump. We're going to loop over all the registers in the 96 * top frame, and show them, with names, in a nice three-column 97 * layout, which keeps us within 80 columns. 98 */ 99 spl_bt_write(fd, "Registers:\n"); 100 101 /* Initialise a frame cursor, starting at the current frame */ 102 unw_init_local(&cp, &uc); 103 104 /* 105 * libunwind's list of possible registers for this architecture is an 106 * enum, unw_regnum_t. UNW_TDEP_LAST_REG is the highest-numbered 107 * register in that list, however, not all register numbers in this 108 * range are defined by the architecture, and not all defined registers 109 * will be present on every implementation of that architecture. 110 * Moreover, libunwind provides nice names for most, but not all 111 * registers, but these are hardcoded; a name being available does not 112 * mean that register is available. 113 * 114 * So, we have to pull this all together here. We try to get the value 115 * of every possible register. If we get a value for it, then the 116 * register must exist, and so we get its name. If libunwind has no 117 * name for it, we synthesize something. These cases should be rare, 118 * and they're usually for uninteresting or niche registers, so it 119 * shouldn't really matter. We can see the value, and that's the main 120 * thing. 121 */ 122 uint_t cols = 0; 123 for (uint_t regnum = 0; regnum <= UNW_TDEP_LAST_REG; regnum++) { 124 /* 125 * Get the value. Any error probably means the register 126 * doesn't exist, and we skip it. 127 */ 128 if (unw_get_reg(&cp, regnum, &v) < 0) 129 continue; 130 131 /* 132 * Register name. If libunwind doesn't have a name for it, 133 * it will return "???". As a shortcut, we just treat '?' 134 * is an alternate end-of-string character. 135 */ 136 const char *name = unw_regname(regnum); 137 for (n = 0; name[n] != '\0' && name[n] != '?'; n++) {} 138 if (n == 0) { 139 /* 140 * No valid name, so make one of the form "?xx", where 141 * "xx" is the two-char hex of libunwind's register 142 * number. 143 */ 144 buf[0] = '?'; 145 n = spl_bt_u64_to_hex_str(regnum, 2, 146 &buf[1], sizeof (buf)-1) + 1; 147 name = buf; 148 } 149 150 /* 151 * Two spaces of padding before each column, plus extra 152 * spaces to align register names shorter than three chars. 153 */ 154 spl_bt_write_n(fd, " ", 5-MIN(n, 3)); 155 156 /* Register name and column punctuation */ 157 spl_bt_write_n(fd, name, n); 158 spl_bt_write(fd, ": 0x"); 159 160 /* 161 * Convert register value (from unw_get_reg()) to hex. We're 162 * assuming that all registers are 64-bits wide, which is 163 * probably fine for any general-purpose registers on any 164 * machine currently in use. A more generic way would be to 165 * look at the width of unw_word_t, but that would also 166 * complicate the column code a bit. This is fine. 167 */ 168 n = spl_bt_u64_to_hex_str(v, 16, buf, sizeof (buf)); 169 spl_bt_write_n(fd, buf, n); 170 171 /* Every third column, emit a newline */ 172 if (!(++cols % 3)) 173 spl_bt_write(fd, "\n"); 174 } 175 176 /* If we finished before the third column, emit a newline. */ 177 if (cols % 3) 178 spl_bt_write(fd, "\n"); 179 180 /* Now the main event, the backtrace. */ 181 spl_bt_write(fd, "Call trace:\n"); 182 183 /* Reset the cursor to the top again. */ 184 unw_init_local(&cp, &uc); 185 186 do { 187 /* 188 * Getting the IP should never fail; libunwind handles it 189 * specially, because its used a lot internally. Still, no 190 * point being silly about it, as the last thing we want is 191 * our crash handler to crash. So if it ever does fail, we'll 192 * show an error line, but keep going to the next frame. 193 */ 194 if (unw_get_reg(&cp, UNW_REG_IP, &v) < 0) { 195 spl_bt_write(fd, " [couldn't get IP register; " 196 "corrupt frame?]"); 197 continue; 198 } 199 200 /* IP & punctuation */ 201 n = spl_bt_u64_to_hex_str(v, 16, buf, sizeof (buf)); 202 spl_bt_write(fd, " [0x"); 203 spl_bt_write_n(fd, buf, n); 204 spl_bt_write(fd, "] "); 205 206 /* 207 * Function ("procedure") name for the current frame. `v` 208 * receives the offset from the named function to the IP, which 209 * we show as a "+offset" suffix. 210 * 211 * If libunwind can't determine the name, we just show "???" 212 * instead. We've already displayed the IP above; that will 213 * have to do. 214 * 215 * unw_get_proc_name() will return ENOMEM if the buffer is too 216 * small, instead truncating the name. So we treat that as a 217 * success and use whatever is in the buffer. 218 */ 219 err = unw_get_proc_name(&cp, buf, sizeof (buf), &v); 220 if (err == 0 || err == -UNW_ENOMEM) { 221 for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {} 222 spl_bt_write_n(fd, buf, n); 223 224 /* Offset from proc name */ 225 spl_bt_write(fd, "+0x"); 226 n = spl_bt_u64_to_hex_str(v, 2, buf, sizeof (buf)); 227 spl_bt_write_n(fd, buf, n); 228 } else 229 spl_bt_write(fd, "???"); 230 231 #ifdef HAVE_LIBUNWIND_ELF 232 /* 233 * Newer libunwind has unw_get_elf_filename(), which gets 234 * the name of the ELF object that the frame was executing in. 235 * Like `unw_get_proc_name()`, `v` recieves the offset within 236 * the file, and UNW_ENOMEM indicates that a truncate filename 237 * was left in the buffer. 238 */ 239 err = unw_get_elf_filename(&cp, buf, sizeof (buf), &v); 240 if (err == 0 || err == -UNW_ENOMEM) { 241 for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {} 242 spl_bt_write(fd, " (in "); 243 spl_bt_write_n(fd, buf, n); 244 245 /* Offset within file */ 246 spl_bt_write(fd, " +0x"); 247 n = spl_bt_u64_to_hex_str(v, 2, buf, sizeof (buf)); 248 spl_bt_write_n(fd, buf, n); 249 spl_bt_write(fd, ")"); 250 } 251 #endif 252 spl_bt_write(fd, "\n"); 253 } while (unw_step(&cp) > 0); 254 } 255 #elif defined(HAVE_BACKTRACE) 256 #include <execinfo.h> 257 258 void 259 libspl_backtrace(int fd) 260 { 261 void *btptrs[64]; 262 size_t nptrs = backtrace(btptrs, 64); 263 spl_bt_write(fd, "Call trace:\n"); 264 backtrace_symbols_fd(btptrs, nptrs, fd); 265 } 266 #else 267 void 268 libspl_backtrace(int fd __maybe_unused) 269 { 270 } 271 #endif 272