1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12 /*
13 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
14 * Use is subject to license terms.
15 */
16 /*
17 * Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
18 */
19
20 #include <assert.h>
21 #include <pthread.h>
22 #include <sys/backtrace.h>
23
24 #if defined(__linux__)
25 #include <errno.h>
26 #include <sys/prctl.h>
27 #ifdef HAVE_GETTID
28 #define libspl_gettid() gettid()
29 #else
30 #include <sys/syscall.h>
31 #define libspl_gettid() ((pid_t)syscall(__NR_gettid))
32 #endif
33 #define libspl_getprogname() (program_invocation_short_name)
34 #define libspl_getthreadname(buf, len) \
35 prctl(PR_GET_NAME, (unsigned long)(buf), 0, 0, 0)
36 #elif defined(__FreeBSD__) || defined(__APPLE__)
37 #if !defined(__APPLE__)
38 #include <pthread_np.h>
39 #define libspl_gettid() pthread_getthreadid_np()
40 #endif
41 #define libspl_getprogname() getprogname()
42 #define libspl_getthreadname(buf, len) \
43 pthread_getname_np(pthread_self(), buf, len);
44 #endif
45
46 #if defined(__APPLE__)
47 static inline uint64_t
libspl_gettid(void)48 libspl_gettid(void)
49 {
50 uint64_t tid;
51
52 if (pthread_threadid_np(NULL, &tid) != 0)
53 tid = 0;
54
55 return (tid);
56 }
57 #endif
58
59 static boolean_t libspl_assert_ok = B_FALSE;
60
61 void
libspl_set_assert_ok(boolean_t val)62 libspl_set_assert_ok(boolean_t val)
63 {
64 libspl_assert_ok = val;
65 }
66
67 static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER;
68
69 /* printf version of libspl_assert */
70 void
libspl_assertf(const char * file,const char * func,int line,const char * format,...)71 libspl_assertf(const char *file, const char *func, int line,
72 const char *format, ...)
73 {
74 pthread_mutex_lock(&assert_lock);
75
76 va_list args;
77 char tname[64];
78
79 libspl_getthreadname(tname, sizeof (tname));
80
81 fprintf(stderr, "ASSERT at %s:%d:%s()\n", file, line, func);
82
83 va_start(args, format);
84 vfprintf(stderr, format, args);
85 va_end(args);
86
87 fprintf(stderr, "\n"
88 " PID: %-8u COMM: %s\n"
89 #if defined(__APPLE__)
90 " TID: %-8" PRIu64 " NAME: %s\n",
91 #else
92 " TID: %-8u NAME: %s\n",
93 #endif
94 getpid(), libspl_getprogname(),
95 libspl_gettid(), tname);
96
97 libspl_backtrace(STDERR_FILENO);
98
99 #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__)
100 if (libspl_assert_ok) {
101 pthread_mutex_unlock(&assert_lock);
102 return;
103 }
104 #endif
105 abort();
106 }
107