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 #include <sys/backtrace.h> 32 33 #if defined(__linux__) 34 #include <errno.h> 35 #include <sys/prctl.h> 36 #ifdef HAVE_GETTID 37 #define libspl_gettid() gettid() 38 #else 39 #include <sys/syscall.h> 40 #define libspl_gettid() ((pid_t)syscall(__NR_gettid)) 41 #endif 42 #define libspl_getprogname() (program_invocation_short_name) 43 #define libspl_getthreadname(buf, len) \ 44 prctl(PR_GET_NAME, (unsigned long)(buf), 0, 0, 0) 45 #elif defined(__FreeBSD__) || defined(__APPLE__) 46 #if !defined(__APPLE__) 47 #include <pthread_np.h> 48 #define libspl_gettid() pthread_getthreadid_np() 49 #endif 50 #define libspl_getprogname() getprogname() 51 #define libspl_getthreadname(buf, len) \ 52 pthread_getname_np(pthread_self(), buf, len); 53 #endif 54 55 #if defined(__APPLE__) 56 static inline uint64_t 57 libspl_gettid(void) 58 { 59 uint64_t tid; 60 61 if (pthread_threadid_np(NULL, &tid) != 0) 62 tid = 0; 63 64 return (tid); 65 } 66 #endif 67 68 static boolean_t libspl_assert_ok = B_FALSE; 69 70 void 71 libspl_set_assert_ok(boolean_t val) 72 { 73 libspl_assert_ok = val; 74 } 75 76 static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER; 77 78 /* printf version of libspl_assert */ 79 void 80 libspl_assertf(const char *file, const char *func, int line, 81 const char *format, ...) 82 { 83 pthread_mutex_lock(&assert_lock); 84 85 va_list args; 86 char tname[64]; 87 88 libspl_getthreadname(tname, sizeof (tname)); 89 90 fprintf(stderr, "ASSERT at %s:%d:%s()\n", file, line, func); 91 92 va_start(args, format); 93 vfprintf(stderr, format, args); 94 va_end(args); 95 96 fprintf(stderr, "\n" 97 " PID: %-8u COMM: %s\n" 98 #if defined(__APPLE__) 99 " TID: %-8" PRIu64 " NAME: %s\n", 100 #else 101 " TID: %-8u NAME: %s\n", 102 #endif 103 getpid(), libspl_getprogname(), 104 libspl_gettid(), tname); 105 106 libspl_backtrace(STDERR_FILENO); 107 108 #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__) 109 if (libspl_assert_ok) { 110 pthread_mutex_unlock(&assert_lock); 111 return; 112 } 113 #endif 114 abort(); 115 } 116