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__) || defined(__APPLE__) 45 #if !defined(__APPLE__) 46 #include <pthread_np.h> 47 #define libspl_gettid() pthread_getthreadid_np() 48 #endif 49 #define libspl_getprogname() getprogname() 50 #define libspl_getthreadname(buf, len) \ 51 pthread_getname_np(pthread_self(), buf, len); 52 #endif 53 54 #if defined(HAVE_LIBUNWIND) 55 #define UNW_LOCAL_ONLY 56 #include <libunwind.h> 57 58 static inline void 59 libspl_dump_backtrace(void) 60 { 61 unw_context_t uc; 62 unw_cursor_t cp; 63 unw_word_t ip, off; 64 char funcname[128]; 65 #ifdef HAVE_LIBUNWIND_ELF 66 char objname[128]; 67 unw_word_t objoff; 68 #endif 69 70 fprintf(stderr, "Call trace:\n"); 71 unw_getcontext(&uc); 72 unw_init_local(&cp, &uc); 73 while (unw_step(&cp) > 0) { 74 unw_get_reg(&cp, UNW_REG_IP, &ip); 75 unw_get_proc_name(&cp, funcname, sizeof (funcname), &off); 76 #ifdef HAVE_LIBUNWIND_ELF 77 unw_get_elf_filename(&cp, objname, sizeof (objname), &objoff); 78 fprintf(stderr, " [0x%08lx] %s+0x%2lx (in %s +0x%2lx)\n", 79 ip, funcname, off, objname, objoff); 80 #else 81 fprintf(stderr, " [0x%08lx] %s+0x%2lx\n", ip, funcname, off); 82 #endif 83 } 84 } 85 #elif defined(HAVE_BACKTRACE) 86 #include <execinfo.h> 87 88 static inline void 89 libspl_dump_backtrace(void) 90 { 91 void *btptrs[100]; 92 size_t nptrs = backtrace(btptrs, 100); 93 char **bt = backtrace_symbols(btptrs, nptrs); 94 fprintf(stderr, "Call trace:\n"); 95 for (size_t i = 0; i < nptrs; i++) 96 fprintf(stderr, " %s\n", bt[i]); 97 free(bt); 98 } 99 #else 100 #define libspl_dump_backtrace() 101 #endif 102 103 #if defined(__APPLE__) 104 static inline uint64_t 105 libspl_gettid(void) 106 { 107 uint64_t tid; 108 109 if (pthread_threadid_np(NULL, &tid) != 0) 110 tid = 0; 111 112 return (tid); 113 } 114 #endif 115 116 static boolean_t libspl_assert_ok = B_FALSE; 117 118 void 119 libspl_set_assert_ok(boolean_t val) 120 { 121 libspl_assert_ok = val; 122 } 123 124 static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER; 125 126 /* printf version of libspl_assert */ 127 void 128 libspl_assertf(const char *file, const char *func, int line, 129 const char *format, ...) 130 { 131 pthread_mutex_lock(&assert_lock); 132 133 va_list args; 134 char tname[64]; 135 136 libspl_getthreadname(tname, sizeof (tname)); 137 138 fprintf(stderr, "ASSERT at %s:%d:%s()\n", file, line, func); 139 140 va_start(args, format); 141 vfprintf(stderr, format, args); 142 va_end(args); 143 144 fprintf(stderr, "\n" 145 " PID: %-8u COMM: %s\n" 146 #if defined(__APPLE__) 147 " TID: %-8" PRIu64 " NAME: %s\n", 148 #else 149 " TID: %-8u NAME: %s\n", 150 #endif 151 getpid(), libspl_getprogname(), 152 libspl_gettid(), tname); 153 154 libspl_dump_backtrace(); 155 156 #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__) 157 if (libspl_assert_ok) { 158 pthread_mutex_unlock(&assert_lock); 159 return; 160 } 161 #endif 162 abort(); 163 } 164