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 http://www.opensolaris.org/os/licensing. 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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright (c) 2012, 2014 by Delphix. All rights reserved. 28 * Copyright 2015 Joyent, Inc. 29 * Copyright 2020 Oxide Computer Company 30 */ 31 32 #include "lint.h" 33 #include "libc.h" 34 #include "thr_uberdata.h" 35 #include <upanic.h> 36 37 const char *panicstr; 38 ulwp_t *panic_thread; 39 40 static mutex_t assert_lock = DEFAULTMUTEX; 41 static ulwp_t *assert_thread = NULL; 42 43 mutex_t *panic_mutex = NULL; 44 45 static void Abort(const char *, size_t) __NORETURN; 46 47 /* 48 * Called from __assert() to set panicstr and panic_thread. 49 */ 50 void 51 __set_panicstr(const char *msg) 52 { 53 panicstr = msg; 54 panic_thread = __curthread(); 55 } 56 57 /* 58 * Called from exit() (atexit function) to give precedence 59 * to assertion failures and a core dump over _exit(). 60 */ 61 void 62 grab_assert_lock() 63 { 64 (void) _lwp_mutex_lock(&assert_lock); 65 } 66 67 static void 68 Abort(const char *msg, size_t buflen) 69 { 70 ulwp_t *self; 71 72 /* to help with core file debugging */ 73 panicstr = msg; 74 if ((self = __curthread()) != NULL) { 75 panic_thread = self; 76 } 77 78 upanic(msg, buflen); 79 } 80 81 /* 82 * Write a panic message w/o grabbing any locks other than assert_lock. 83 * We have no idea what locks are held at this point. 84 */ 85 void 86 common_panic(const char *head, const char *why) 87 { 88 char msg[400]; /* no panic() message in the library is this long */ 89 ulwp_t *self; 90 size_t len1, len2; 91 92 if ((self = __curthread()) != NULL) 93 enter_critical(self); 94 (void) _lwp_mutex_lock(&assert_lock); 95 96 (void) memset(msg, 0, sizeof (msg)); 97 (void) strcpy(msg, head); 98 len1 = strlen(msg); 99 len2 = strlen(why); 100 if (len1 + len2 >= sizeof (msg)) 101 len2 = sizeof (msg) - len1 - 1; 102 (void) strncat(msg, why, len2); 103 len1 = strlen(msg); 104 if (msg[len1 - 1] != '\n') 105 msg[len1++] = '\n'; 106 (void) __write(2, msg, len1); 107 Abort(msg, sizeof (msg)); 108 } 109 110 void 111 thr_panic(const char *why) 112 { 113 common_panic("*** libc thread failure: ", why); 114 } 115 116 void 117 aio_panic(const char *why) 118 { 119 common_panic("*** libc aio system failure: ", why); 120 } 121 122 void 123 mutex_panic(mutex_t *mp, const char *why) 124 { 125 panic_mutex = mp; 126 common_panic("*** libc mutex system failure: ", why); 127 } 128 129 /* 130 * Utility function for converting a long integer to a string, avoiding stdio. 131 * 'base' must be one of 10 or 16 132 */ 133 void 134 ultos(uint64_t n, int base, char *s) 135 { 136 char lbuf[24]; /* 64 bits fits in 16 hex digits, 20 decimal */ 137 char *cp = lbuf; 138 139 do { 140 *cp++ = "0123456789abcdef"[n%base]; 141 n /= base; 142 } while (n); 143 if (base == 16) { 144 *s++ = '0'; 145 *s++ = 'x'; 146 } 147 do { 148 *s++ = *--cp; 149 } while (cp > lbuf); 150 *s = '\0'; 151 } 152 153 /* 154 * Report application lock usage error for mutexes and condvars. 155 * Not called if _THREAD_ERROR_DETECTION=0. 156 * Continue execution if _THREAD_ERROR_DETECTION=1. 157 * Dump core if _THREAD_ERROR_DETECTION=2. 158 */ 159 void 160 lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg) 161 { 162 mutex_t mcopy; 163 char buf[800]; 164 uberdata_t *udp; 165 ulwp_t *self; 166 lwpid_t lwpid; 167 pid_t pid; 168 169 /* 170 * Take a snapshot of the mutex before it changes (we hope!). 171 * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned. 172 */ 173 (void) memcpy(&mcopy, mp, sizeof (mcopy)); 174 175 /* avoid recursion deadlock */ 176 if ((self = __curthread()) != NULL) { 177 if (assert_thread == self) 178 _exit(127); 179 enter_critical(self); 180 (void) _lwp_mutex_lock(&assert_lock); 181 assert_thread = self; 182 lwpid = self->ul_lwpid; 183 udp = self->ul_uberdata; 184 pid = udp->pid; 185 } else { 186 self = NULL; 187 (void) _lwp_mutex_lock(&assert_lock); 188 lwpid = _lwp_self(); 189 udp = &__uberdata; 190 pid = getpid(); 191 } 192 193 (void) strcpy(buf, 194 "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 195 (void) strcat(buf, who); 196 (void) strcat(buf, "("); 197 if (cv != NULL) { 198 ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf)); 199 (void) strcat(buf, ", "); 200 } 201 ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf)); 202 (void) strcat(buf, ")"); 203 if (msg != NULL) { 204 (void) strcat(buf, ": "); 205 (void) strcat(buf, msg); 206 } else if (!mutex_held(&mcopy)) { 207 (void) strcat(buf, ": calling thread does not own the lock"); 208 } else if (mcopy.mutex_rcount) { 209 (void) strcat(buf, ": mutex rcount = "); 210 ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf)); 211 } else { 212 (void) strcat(buf, ": calling thread already owns the lock"); 213 } 214 (void) strcat(buf, "\ncalling thread is "); 215 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 216 (void) strcat(buf, " thread-id "); 217 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 218 if (msg != NULL || mutex_held(&mcopy)) 219 /* EMPTY */; 220 else if (mcopy.mutex_lockw == 0) 221 (void) strcat(buf, "\nthe lock is unowned"); 222 else if (!(mcopy.mutex_type & USYNC_PROCESS)) { 223 (void) strcat(buf, "\nthe lock owner is "); 224 ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 225 } else { 226 (void) strcat(buf, " in process "); 227 ultos((uint64_t)pid, 10, buf + strlen(buf)); 228 (void) strcat(buf, "\nthe lock owner is "); 229 ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 230 (void) strcat(buf, " in process "); 231 ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf)); 232 } 233 (void) strcat(buf, "\n\n"); 234 (void) __write(2, buf, strlen(buf)); 235 if (udp->uberflags.uf_thread_error_detection >= 2) 236 Abort(buf, sizeof (buf)); 237 assert_thread = NULL; 238 (void) _lwp_mutex_unlock(&assert_lock); 239 if (self != NULL) 240 exit_critical(self); 241 } 242 243 /* 244 * Report application lock usage error for rwlocks. 245 * Not called if _THREAD_ERROR_DETECTION=0. 246 * Continue execution if _THREAD_ERROR_DETECTION=1. 247 * Dump core if _THREAD_ERROR_DETECTION=2. 248 */ 249 void 250 rwlock_error(const rwlock_t *rp, const char *who, const char *msg) 251 { 252 rwlock_t rcopy; 253 uint32_t rwstate; 254 char buf[800]; 255 uberdata_t *udp; 256 ulwp_t *self; 257 lwpid_t lwpid; 258 pid_t pid; 259 int process; 260 261 /* 262 * Take a snapshot of the rwlock before it changes (we hope!). 263 * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned. 264 */ 265 (void) memcpy(&rcopy, rp, sizeof (rcopy)); 266 267 /* avoid recursion deadlock */ 268 if ((self = __curthread()) != NULL) { 269 if (assert_thread == self) 270 _exit(127); 271 enter_critical(self); 272 (void) _lwp_mutex_lock(&assert_lock); 273 assert_thread = self; 274 lwpid = self->ul_lwpid; 275 udp = self->ul_uberdata; 276 pid = udp->pid; 277 } else { 278 self = NULL; 279 (void) _lwp_mutex_lock(&assert_lock); 280 lwpid = _lwp_self(); 281 udp = &__uberdata; 282 pid = getpid(); 283 } 284 285 rwstate = (uint32_t)rcopy.rwlock_readers; 286 process = (rcopy.rwlock_type & USYNC_PROCESS); 287 288 (void) strcpy(buf, 289 "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 290 (void) strcat(buf, who); 291 (void) strcat(buf, "("); 292 ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf)); 293 (void) strcat(buf, "): "); 294 (void) strcat(buf, msg); 295 (void) strcat(buf, "\ncalling thread is "); 296 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 297 (void) strcat(buf, " thread-id "); 298 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 299 if (process) { 300 (void) strcat(buf, " in process "); 301 ultos((uint64_t)pid, 10, buf + strlen(buf)); 302 } 303 if (rwstate & URW_WRITE_LOCKED) { 304 (void) strcat(buf, "\nthe writer lock owner is "); 305 ultos((uint64_t)rcopy.rwlock_owner, 16, 306 buf + strlen(buf)); 307 if (process) { 308 (void) strcat(buf, " in process "); 309 ultos((uint64_t)rcopy.rwlock_ownerpid, 10, 310 buf + strlen(buf)); 311 } 312 } else if (rwstate & URW_READERS_MASK) { 313 (void) strcat(buf, "\nthe reader lock is held by "); 314 ultos((uint64_t)(rwstate & URW_READERS_MASK), 10, 315 buf + strlen(buf)); 316 (void) strcat(buf, " readers"); 317 } else { 318 (void) strcat(buf, "\nthe lock is unowned"); 319 } 320 if (rwstate & URW_HAS_WAITERS) 321 (void) strcat(buf, "\nand the lock appears to have waiters"); 322 (void) strcat(buf, "\n\n"); 323 (void) __write(2, buf, strlen(buf)); 324 if (udp->uberflags.uf_thread_error_detection >= 2) 325 Abort(buf, sizeof (buf)); 326 assert_thread = NULL; 327 (void) _lwp_mutex_unlock(&assert_lock); 328 if (self != NULL) 329 exit_critical(self); 330 } 331 332 /* 333 * Report a thread usage error. 334 * Not called if _THREAD_ERROR_DETECTION=0. 335 * Writes message and continues execution if _THREAD_ERROR_DETECTION=1. 336 * Writes message and dumps core if _THREAD_ERROR_DETECTION=2. 337 */ 338 void 339 thread_error(const char *msg) 340 { 341 char buf[800]; 342 uberdata_t *udp; 343 ulwp_t *self; 344 lwpid_t lwpid; 345 346 /* avoid recursion deadlock */ 347 if ((self = __curthread()) != NULL) { 348 if (assert_thread == self) 349 _exit(127); 350 enter_critical(self); 351 (void) _lwp_mutex_lock(&assert_lock); 352 assert_thread = self; 353 lwpid = self->ul_lwpid; 354 udp = self->ul_uberdata; 355 } else { 356 self = NULL; 357 (void) _lwp_mutex_lock(&assert_lock); 358 lwpid = _lwp_self(); 359 udp = &__uberdata; 360 } 361 362 (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: " 363 "thread usage error detected ***\n*** "); 364 (void) strcat(buf, msg); 365 366 (void) strcat(buf, "\n*** calling thread is "); 367 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 368 (void) strcat(buf, " thread-id "); 369 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 370 (void) strcat(buf, "\n\n"); 371 (void) __write(2, buf, strlen(buf)); 372 if (udp->uberflags.uf_thread_error_detection >= 2) 373 Abort(buf, sizeof (buf)); 374 assert_thread = NULL; 375 (void) _lwp_mutex_unlock(&assert_lock); 376 if (self != NULL) 377 exit_critical(self); 378 } 379 380 /* 381 * We use __assfail() because the libc __assert() calls 382 * gettext() which calls malloc() which grabs a mutex. 383 * We do everything without calling standard i/o. 384 * assfail() and _assfail() are exported functions; 385 * __assfail() is private to libc. 386 */ 387 #pragma weak _assfail = __assfail 388 void 389 __assfail(const char *assertion, const char *filename, int line_num) 390 { 391 char buf[800]; /* no assert() message in the library is this long */ 392 ulwp_t *self; 393 lwpid_t lwpid; 394 395 /* avoid recursion deadlock */ 396 if ((self = __curthread()) != NULL) { 397 if (assert_thread == self) 398 _exit(127); 399 enter_critical(self); 400 (void) _lwp_mutex_lock(&assert_lock); 401 assert_thread = self; 402 lwpid = self->ul_lwpid; 403 } else { 404 self = NULL; 405 (void) _lwp_mutex_lock(&assert_lock); 406 lwpid = _lwp_self(); 407 } 408 409 /* 410 * This is a hack, but since the Abort function isn't exported 411 * to outside consumers, libzpool's vpanic() function calls 412 * assfail() with a filename set to NULL. In that case, it'd be 413 * best not to print "assertion failed" since it was a panic and 414 * not an assertion failure. 415 */ 416 if (filename == NULL) { 417 (void) strcpy(buf, "failure for thread "); 418 } else { 419 (void) strcpy(buf, "assertion failed for thread "); 420 } 421 422 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 423 (void) strcat(buf, ", thread-id "); 424 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 425 (void) strcat(buf, ": "); 426 (void) strcat(buf, assertion); 427 428 if (filename != NULL) { 429 (void) strcat(buf, ", file "); 430 (void) strcat(buf, filename); 431 (void) strcat(buf, ", line "); 432 ultos((uint64_t)line_num, 10, buf + strlen(buf)); 433 } 434 435 (void) strcat(buf, "\n"); 436 (void) __write(2, buf, strlen(buf)); 437 /* 438 * We could replace the call to Abort() with the following code 439 * if we want just to issue a warning message and not die. 440 * assert_thread = NULL; 441 * _lwp_mutex_unlock(&assert_lock); 442 * if (self != NULL) 443 * exit_critical(self); 444 */ 445 Abort(buf, sizeof (buf)); 446 } 447 448 /* 449 * We define and export this version of assfail() just because libaio 450 * used to define and export it, needlessly. Now that libaio is folded 451 * into libc, we need to continue this for ABI/version reasons. 452 * We don't use "#pragma weak assfail __assfail" in order to avoid 453 * warnings from the check_fnames utility at build time for libraries 454 * that define their own version of assfail(). 455 * 456 * Additionally, ASSERT() and VERIFY() in <sys/debug.h> can invoke assfail(). 457 * 458 * We would like this to be declared _NORETURN, but some caution is in order 459 * as alternate implementations of assfail() exist -- notably the one in 460 * libfakekernel -- which can return under some circumstances. 461 */ 462 void 463 assfail(const char *assertion, const char *filename, int line_num) 464 { 465 __assfail(assertion, filename, line_num); 466 /* NOTREACHED */ 467 } 468 469 void 470 assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv, 471 const char *filename, int line_num) 472 { 473 char buf[1000]; 474 (void) strcpy(buf, assertion); 475 (void) strcat(buf, " ("); 476 ultos((uint64_t)lv, 16, buf + strlen(buf)); 477 (void) strcat(buf, " "); 478 (void) strcat(buf, op); 479 (void) strcat(buf, " "); 480 ultos((uint64_t)rv, 16, buf + strlen(buf)); 481 (void) strcat(buf, ")"); 482 __assfail(buf, filename, line_num); 483 } 484