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__)
56static inline uint64_t
57libspl_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
68static boolean_t libspl_assert_ok = B_FALSE;
69
70void
71libspl_set_assert_ok(boolean_t val)
72{
73	libspl_assert_ok = val;
74}
75
76static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER;
77
78/* printf version of libspl_assert */
79void
80libspl_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