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