1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or https://opensource.org/licenses/CDDL-1.0. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 27 */ 28 29 #include <assert.h> 30 #include <pthread.h> 31 32 #if defined(__linux__) 33 #include <errno.h> 34 #include <sys/prctl.h> 35 #ifdef HAVE_GETTID 36 #define libspl_gettid() gettid() 37 #else 38 #include <sys/syscall.h> 39 #define libspl_gettid() ((pid_t)syscall(__NR_gettid)) 40 #endif 41 #define libspl_getprogname() (program_invocation_short_name) 42 #define libspl_getthreadname(buf, len) \ 43 prctl(PR_GET_NAME, (unsigned long)(buf), 0, 0, 0) 44 #elif defined(__FreeBSD__) 45 #include <pthread_np.h> 46 #define libspl_gettid() pthread_getthreadid_np() 47 #define libspl_getprogname() getprogname() 48 #define libspl_getthreadname(buf, len) \ 49 pthread_getname_np(pthread_self(), buf, len); 50 #endif 51 52 #if defined(HAVE_LIBUNWIND) 53 #define UNW_LOCAL_ONLY 54 #include <libunwind.h> 55 56 static inline void 57 libspl_dump_backtrace(void) 58 { 59 unw_context_t uc; 60 unw_cursor_t cp; 61 unw_word_t ip, off; 62 char funcname[128]; 63 #ifdef HAVE_LIBUNWIND_ELF 64 char objname[128]; 65 unw_word_t objoff; 66 #endif 67 68 fprintf(stderr, "Call trace:\n"); 69 unw_getcontext(&uc); 70 unw_init_local(&cp, &uc); 71 while (unw_step(&cp) > 0) { 72 unw_get_reg(&cp, UNW_REG_IP, &ip); 73 unw_get_proc_name(&cp, funcname, sizeof (funcname), &off); 74 #ifdef HAVE_LIBUNWIND_ELF 75 unw_get_elf_filename(&cp, objname, sizeof (objname), &objoff); 76 fprintf(stderr, " [0x%08lx] %s+0x%2lx (in %s +0x%2lx)\n", 77 ip, funcname, off, objname, objoff); 78 #else 79 fprintf(stderr, " [0x%08lx] %s+0x%2lx\n", ip, funcname, off); 80 #endif 81 } 82 } 83 #elif defined(HAVE_BACKTRACE) 84 #include <execinfo.h> 85 86 static inline void 87 libspl_dump_backtrace(void) 88 { 89 void *btptrs[100]; 90 size_t nptrs = backtrace(btptrs, 100); 91 char **bt = backtrace_symbols(btptrs, nptrs); 92 fprintf(stderr, "Call trace:\n"); 93 for (size_t i = 0; i < nptrs; i++) 94 fprintf(stderr, " %s\n", bt[i]); 95 free(bt); 96 } 97 #else 98 #define libspl_dump_backtrace() 99 #endif 100 101 static boolean_t libspl_assert_ok = B_FALSE; 102 103 void 104 libspl_set_assert_ok(boolean_t val) 105 { 106 libspl_assert_ok = val; 107 } 108 109 static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER; 110 111 /* printf version of libspl_assert */ 112 void 113 libspl_assertf(const char *file, const char *func, int line, 114 const char *format, ...) 115 { 116 pthread_mutex_lock(&assert_lock); 117 118 va_list args; 119 char tname[64]; 120 121 libspl_getthreadname(tname, sizeof (tname)); 122 123 fprintf(stderr, "ASSERT at %s:%d:%s()\n", file, line, func); 124 125 va_start(args, format); 126 vfprintf(stderr, format, args); 127 va_end(args); 128 129 fprintf(stderr, "\n" 130 " PID: %-8u COMM: %s\n" 131 " TID: %-8u NAME: %s\n", 132 getpid(), libspl_getprogname(), 133 libspl_gettid(), tname); 134 135 libspl_dump_backtrace(); 136 137 #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__) 138 if (libspl_assert_ok) { 139 pthread_mutex_unlock(&assert_lock); 140 return; 141 } 142 #endif 143 abort(); 144 } 145