1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy /* 22eda14cbcSMatt Macy * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23eda14cbcSMatt Macy * Use is subject to license terms. 24eda14cbcSMatt Macy */ 25b985c9caSMartin Matuska /* 26b985c9caSMartin Matuska * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 27b985c9caSMartin Matuska */ 28eda14cbcSMatt Macy 29eda14cbcSMatt Macy #include <assert.h> 30b985c9caSMartin Matuska #include <pthread.h> 31b985c9caSMartin Matuska 32b985c9caSMartin Matuska #if defined(__linux__) 33b985c9caSMartin Matuska #include <errno.h> 34b985c9caSMartin Matuska #include <sys/prctl.h> 35b985c9caSMartin Matuska #ifdef HAVE_GETTID 36b985c9caSMartin Matuska #define libspl_gettid() gettid() 37b985c9caSMartin Matuska #else 38b985c9caSMartin Matuska #include <sys/syscall.h> 39b985c9caSMartin Matuska #define libspl_gettid() ((pid_t)syscall(__NR_gettid)) 40b985c9caSMartin Matuska #endif 41b985c9caSMartin Matuska #define libspl_getprogname() (program_invocation_short_name) 42b985c9caSMartin Matuska #define libspl_getthreadname(buf, len) \ 43b985c9caSMartin Matuska prctl(PR_GET_NAME, (unsigned long)(buf), 0, 0, 0) 44*3c1be0b2SMartin Matuska #elif defined(__FreeBSD__) || defined(__APPLE__) 45*3c1be0b2SMartin Matuska #if !defined(__APPLE__) 46b985c9caSMartin Matuska #include <pthread_np.h> 47b985c9caSMartin Matuska #define libspl_gettid() pthread_getthreadid_np() 48*3c1be0b2SMartin Matuska #endif 49b985c9caSMartin Matuska #define libspl_getprogname() getprogname() 50b985c9caSMartin Matuska #define libspl_getthreadname(buf, len) \ 51b985c9caSMartin Matuska pthread_getname_np(pthread_self(), buf, len); 52b985c9caSMartin Matuska #endif 53b985c9caSMartin Matuska 54b985c9caSMartin Matuska #if defined(HAVE_LIBUNWIND) 55b985c9caSMartin Matuska #define UNW_LOCAL_ONLY 56b985c9caSMartin Matuska #include <libunwind.h> 57b985c9caSMartin Matuska 58b985c9caSMartin Matuska static inline void 59b985c9caSMartin Matuska libspl_dump_backtrace(void) 60b985c9caSMartin Matuska { 61b985c9caSMartin Matuska unw_context_t uc; 62b985c9caSMartin Matuska unw_cursor_t cp; 63b985c9caSMartin Matuska unw_word_t ip, off; 64b985c9caSMartin Matuska char funcname[128]; 65b985c9caSMartin Matuska #ifdef HAVE_LIBUNWIND_ELF 66b985c9caSMartin Matuska char objname[128]; 67b985c9caSMartin Matuska unw_word_t objoff; 68b985c9caSMartin Matuska #endif 69b985c9caSMartin Matuska 70b985c9caSMartin Matuska fprintf(stderr, "Call trace:\n"); 71b985c9caSMartin Matuska unw_getcontext(&uc); 72b985c9caSMartin Matuska unw_init_local(&cp, &uc); 73b985c9caSMartin Matuska while (unw_step(&cp) > 0) { 74b985c9caSMartin Matuska unw_get_reg(&cp, UNW_REG_IP, &ip); 75b985c9caSMartin Matuska unw_get_proc_name(&cp, funcname, sizeof (funcname), &off); 76b985c9caSMartin Matuska #ifdef HAVE_LIBUNWIND_ELF 77b985c9caSMartin Matuska unw_get_elf_filename(&cp, objname, sizeof (objname), &objoff); 78b985c9caSMartin Matuska fprintf(stderr, " [0x%08lx] %s+0x%2lx (in %s +0x%2lx)\n", 79b985c9caSMartin Matuska ip, funcname, off, objname, objoff); 80b985c9caSMartin Matuska #else 81b985c9caSMartin Matuska fprintf(stderr, " [0x%08lx] %s+0x%2lx\n", ip, funcname, off); 82b985c9caSMartin Matuska #endif 83b985c9caSMartin Matuska } 84b985c9caSMartin Matuska } 85b985c9caSMartin Matuska #elif defined(HAVE_BACKTRACE) 86b985c9caSMartin Matuska #include <execinfo.h> 87b985c9caSMartin Matuska 88b985c9caSMartin Matuska static inline void 89b985c9caSMartin Matuska libspl_dump_backtrace(void) 90b985c9caSMartin Matuska { 91b985c9caSMartin Matuska void *btptrs[100]; 92b985c9caSMartin Matuska size_t nptrs = backtrace(btptrs, 100); 93b985c9caSMartin Matuska char **bt = backtrace_symbols(btptrs, nptrs); 94b985c9caSMartin Matuska fprintf(stderr, "Call trace:\n"); 95b985c9caSMartin Matuska for (size_t i = 0; i < nptrs; i++) 96b985c9caSMartin Matuska fprintf(stderr, " %s\n", bt[i]); 97b985c9caSMartin Matuska free(bt); 98b985c9caSMartin Matuska } 99b985c9caSMartin Matuska #else 100b985c9caSMartin Matuska #define libspl_dump_backtrace() 101b985c9caSMartin Matuska #endif 102eda14cbcSMatt Macy 103*3c1be0b2SMartin Matuska #if defined(__APPLE__) 104*3c1be0b2SMartin Matuska static inline uint64_t 105*3c1be0b2SMartin Matuska libspl_gettid(void) 106*3c1be0b2SMartin Matuska { 107*3c1be0b2SMartin Matuska uint64_t tid; 108*3c1be0b2SMartin Matuska 109*3c1be0b2SMartin Matuska if (pthread_threadid_np(NULL, &tid) != 0) 110*3c1be0b2SMartin Matuska tid = 0; 111*3c1be0b2SMartin Matuska 112*3c1be0b2SMartin Matuska return (tid); 113*3c1be0b2SMartin Matuska } 114*3c1be0b2SMartin Matuska #endif 115*3c1be0b2SMartin Matuska 116c03c5b1cSMartin Matuska static boolean_t libspl_assert_ok = B_FALSE; 117c03c5b1cSMartin Matuska 118c03c5b1cSMartin Matuska void 119c03c5b1cSMartin Matuska libspl_set_assert_ok(boolean_t val) 120c03c5b1cSMartin Matuska { 121c03c5b1cSMartin Matuska libspl_assert_ok = val; 122c03c5b1cSMartin Matuska } 123eda14cbcSMatt Macy 124b985c9caSMartin Matuska static pthread_mutex_t assert_lock = PTHREAD_MUTEX_INITIALIZER; 125b985c9caSMartin Matuska 126eda14cbcSMatt Macy /* printf version of libspl_assert */ 127eda14cbcSMatt Macy void 128eda14cbcSMatt Macy libspl_assertf(const char *file, const char *func, int line, 129eda14cbcSMatt Macy const char *format, ...) 130eda14cbcSMatt Macy { 131b985c9caSMartin Matuska pthread_mutex_lock(&assert_lock); 132b985c9caSMartin Matuska 133eda14cbcSMatt Macy va_list args; 134b985c9caSMartin Matuska char tname[64]; 135b985c9caSMartin Matuska 136b985c9caSMartin Matuska libspl_getthreadname(tname, sizeof (tname)); 137b985c9caSMartin Matuska 138b985c9caSMartin Matuska fprintf(stderr, "ASSERT at %s:%d:%s()\n", file, line, func); 139eda14cbcSMatt Macy 140eda14cbcSMatt Macy va_start(args, format); 141eda14cbcSMatt Macy vfprintf(stderr, format, args); 142eda14cbcSMatt Macy va_end(args); 143be181ee2SMartin Matuska 144b985c9caSMartin Matuska fprintf(stderr, "\n" 145b985c9caSMartin Matuska " PID: %-8u COMM: %s\n" 146*3c1be0b2SMartin Matuska #if defined(__APPLE__) 147*3c1be0b2SMartin Matuska " TID: %-8" PRIu64 " NAME: %s\n", 148*3c1be0b2SMartin Matuska #else 149b985c9caSMartin Matuska " TID: %-8u NAME: %s\n", 150*3c1be0b2SMartin Matuska #endif 151b985c9caSMartin Matuska getpid(), libspl_getprogname(), 152b985c9caSMartin Matuska libspl_gettid(), tname); 153b985c9caSMartin Matuska 154b985c9caSMartin Matuska libspl_dump_backtrace(); 155b985c9caSMartin Matuska 156be181ee2SMartin Matuska #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__) 15716038816SMartin Matuska if (libspl_assert_ok) { 158b985c9caSMartin Matuska pthread_mutex_unlock(&assert_lock); 159eda14cbcSMatt Macy return; 160eda14cbcSMatt Macy } 161be181ee2SMartin Matuska #endif 162eda14cbcSMatt Macy abort(); 163eda14cbcSMatt Macy } 164