1*aca928a5SMartin Matuska /* 2*aca928a5SMartin Matuska * CDDL HEADER START 3*aca928a5SMartin Matuska * 4*aca928a5SMartin Matuska * The contents of this file are subject to the terms of the 5*aca928a5SMartin Matuska * Common Development and Distribution License (the "License"). 6*aca928a5SMartin Matuska * You may not use this file except in compliance with the License. 7*aca928a5SMartin Matuska * 8*aca928a5SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*aca928a5SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10*aca928a5SMartin Matuska * See the License for the specific language governing permissions 11*aca928a5SMartin Matuska * and limitations under the License. 12*aca928a5SMartin Matuska * 13*aca928a5SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 14*aca928a5SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*aca928a5SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 16*aca928a5SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 17*aca928a5SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 18*aca928a5SMartin Matuska * 19*aca928a5SMartin Matuska * CDDL HEADER END 20*aca928a5SMartin Matuska */ 21*aca928a5SMartin Matuska /* 22*aca928a5SMartin Matuska * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 23*aca928a5SMartin Matuska * Copyright (c) 2024, Klara Inc. 24*aca928a5SMartin Matuska */ 25*aca928a5SMartin Matuska 26*aca928a5SMartin Matuska #include <sys/backtrace.h> 27*aca928a5SMartin Matuska #include <sys/types.h> 28*aca928a5SMartin Matuska #include <unistd.h> 29*aca928a5SMartin Matuska 30*aca928a5SMartin Matuska /* 31*aca928a5SMartin Matuska * libspl_backtrace() must be safe to call from inside a signal hander. This 32*aca928a5SMartin Matuska * mostly means it must not allocate, and so we can't use things like printf. 33*aca928a5SMartin Matuska */ 34*aca928a5SMartin Matuska 35*aca928a5SMartin Matuska #if defined(HAVE_LIBUNWIND) 36*aca928a5SMartin Matuska #define UNW_LOCAL_ONLY 37*aca928a5SMartin Matuska #include <libunwind.h> 38*aca928a5SMartin Matuska 39*aca928a5SMartin Matuska static size_t 40*aca928a5SMartin Matuska libspl_u64_to_hex_str(uint64_t v, size_t digits, char *buf, size_t buflen) 41*aca928a5SMartin Matuska { 42*aca928a5SMartin Matuska static const char hexdigits[] = { 43*aca928a5SMartin Matuska '0', '1', '2', '3', '4', '5', '6', '7', 44*aca928a5SMartin Matuska '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 45*aca928a5SMartin Matuska }; 46*aca928a5SMartin Matuska 47*aca928a5SMartin Matuska size_t pos = 0; 48*aca928a5SMartin Matuska boolean_t want = (digits == 0); 49*aca928a5SMartin Matuska for (int i = 15; i >= 0; i--) { 50*aca928a5SMartin Matuska const uint64_t d = v >> (i * 4) & 0xf; 51*aca928a5SMartin Matuska if (!want && (d != 0 || digits > i)) 52*aca928a5SMartin Matuska want = B_TRUE; 53*aca928a5SMartin Matuska if (want) { 54*aca928a5SMartin Matuska buf[pos++] = hexdigits[d]; 55*aca928a5SMartin Matuska if (pos == buflen) 56*aca928a5SMartin Matuska break; 57*aca928a5SMartin Matuska } 58*aca928a5SMartin Matuska } 59*aca928a5SMartin Matuska return (pos); 60*aca928a5SMartin Matuska } 61*aca928a5SMartin Matuska 62*aca928a5SMartin Matuska void 63*aca928a5SMartin Matuska libspl_backtrace(int fd) 64*aca928a5SMartin Matuska { 65*aca928a5SMartin Matuska ssize_t ret __attribute__((unused)); 66*aca928a5SMartin Matuska unw_context_t uc; 67*aca928a5SMartin Matuska unw_cursor_t cp; 68*aca928a5SMartin Matuska unw_word_t loc; 69*aca928a5SMartin Matuska char buf[128]; 70*aca928a5SMartin Matuska size_t n; 71*aca928a5SMartin Matuska 72*aca928a5SMartin Matuska ret = write(fd, "Call trace:\n", 12); 73*aca928a5SMartin Matuska unw_getcontext(&uc); 74*aca928a5SMartin Matuska unw_init_local(&cp, &uc); 75*aca928a5SMartin Matuska while (unw_step(&cp) > 0) { 76*aca928a5SMartin Matuska unw_get_reg(&cp, UNW_REG_IP, &loc); 77*aca928a5SMartin Matuska ret = write(fd, " [0x", 5); 78*aca928a5SMartin Matuska n = libspl_u64_to_hex_str(loc, 10, buf, sizeof (buf)); 79*aca928a5SMartin Matuska ret = write(fd, buf, n); 80*aca928a5SMartin Matuska ret = write(fd, "] ", 2); 81*aca928a5SMartin Matuska unw_get_proc_name(&cp, buf, sizeof (buf), &loc); 82*aca928a5SMartin Matuska for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {} 83*aca928a5SMartin Matuska ret = write(fd, buf, n); 84*aca928a5SMartin Matuska ret = write(fd, "+0x", 3); 85*aca928a5SMartin Matuska n = libspl_u64_to_hex_str(loc, 2, buf, sizeof (buf)); 86*aca928a5SMartin Matuska ret = write(fd, buf, n); 87*aca928a5SMartin Matuska #ifdef HAVE_LIBUNWIND_ELF 88*aca928a5SMartin Matuska ret = write(fd, " (in ", 5); 89*aca928a5SMartin Matuska unw_get_elf_filename(&cp, buf, sizeof (buf), &loc); 90*aca928a5SMartin Matuska for (n = 0; n < sizeof (buf) && buf[n] != '\0'; n++) {} 91*aca928a5SMartin Matuska ret = write(fd, buf, n); 92*aca928a5SMartin Matuska ret = write(fd, " +0x", 4); 93*aca928a5SMartin Matuska n = libspl_u64_to_hex_str(loc, 2, buf, sizeof (buf)); 94*aca928a5SMartin Matuska ret = write(fd, buf, n); 95*aca928a5SMartin Matuska ret = write(fd, ")", 1); 96*aca928a5SMartin Matuska #endif 97*aca928a5SMartin Matuska ret = write(fd, "\n", 1); 98*aca928a5SMartin Matuska } 99*aca928a5SMartin Matuska } 100*aca928a5SMartin Matuska #elif defined(HAVE_BACKTRACE) 101*aca928a5SMartin Matuska #include <execinfo.h> 102*aca928a5SMartin Matuska 103*aca928a5SMartin Matuska void 104*aca928a5SMartin Matuska libspl_backtrace(int fd) 105*aca928a5SMartin Matuska { 106*aca928a5SMartin Matuska ssize_t ret __attribute__((unused)); 107*aca928a5SMartin Matuska void *btptrs[64]; 108*aca928a5SMartin Matuska size_t nptrs = backtrace(btptrs, 64); 109*aca928a5SMartin Matuska ret = write(fd, "Call trace:\n", 12); 110*aca928a5SMartin Matuska backtrace_symbols_fd(btptrs, nptrs, fd); 111*aca928a5SMartin Matuska } 112*aca928a5SMartin Matuska #else 113*aca928a5SMartin Matuska #include <sys/debug.h> 114*aca928a5SMartin Matuska 115*aca928a5SMartin Matuska void 116*aca928a5SMartin Matuska libspl_backtrace(int fd __maybe_unused) 117*aca928a5SMartin Matuska { 118*aca928a5SMartin Matuska } 119*aca928a5SMartin Matuska #endif 120