Home | History | Annotate | Download | only in common
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Failure routines for libumem (not standalone)
     29  */
     30 
     31 #include <sys/types.h>
     32 #include <signal.h>
     33 #include <stdarg.h>
     34 #include <string.h>
     35 
     36 #include "misc.h"
     37 
     38 static volatile int umem_exiting = 0;
     39 #define	UMEM_EXIT_ABORT	1
     40 
     41 static mutex_t umem_exit_lock = DEFAULTMUTEX; /* protects umem_exiting */
     42 
     43 static int
     44 firstexit(int type)
     45 {
     46 	if (umem_exiting)
     47 		return (0);
     48 
     49 	(void) mutex_lock(&umem_exit_lock);
     50 	if (umem_exiting) {
     51 		(void) mutex_unlock(&umem_exit_lock);
     52 		return (0);
     53 	}
     54 	umem_exiting = type;
     55 	(void) mutex_unlock(&umem_exit_lock);
     56 
     57 	return (1);
     58 }
     59 
     60 /*
     61  * We can't use abort(3C), since it closes all of the standard library
     62  * FILEs, which can call free().
     63  *
     64  * In addition, we can't just raise(SIGABRT), since the current handler
     65  * might do allocation.  We give them once chance, though.
     66  */
     67 static void __NORETURN
     68 umem_do_abort(void)
     69 {
     70 	if (firstexit(UMEM_EXIT_ABORT))
     71 		(void) raise(SIGABRT);
     72 
     73 	for (;;) {
     74 		(void) signal(SIGABRT, SIG_DFL);
     75 		(void) sigrelse(SIGABRT);
     76 		(void) raise(SIGABRT);
     77 	}
     78 }
     79 
     80 #define	SKIP_FRAMES		1	/* skip the panic frame */
     81 #define	ERR_STACK_FRAMES	128
     82 
     83 static void
     84 print_stacktrace(void)
     85 {
     86 	uintptr_t cur_stack[ERR_STACK_FRAMES];
     87 
     88 	/*
     89 	 * if we are in a signal context, checking for it will recurse
     90 	 */
     91 	uint_t nframes = getpcstack(cur_stack, ERR_STACK_FRAMES, 0);
     92 	uint_t idx;
     93 
     94 	if (nframes > SKIP_FRAMES) {
     95 		umem_printf("stack trace:\n");
     96 
     97 		for (idx = SKIP_FRAMES; idx < nframes; idx++) {
     98 			(void) print_sym((void *)cur_stack[idx]);
     99 			umem_printf("\n");
    100 		}
    101 	}
    102 }
    103 
    104 void
    105 umem_panic(const char *format, ...)
    106 {
    107 	va_list va;
    108 
    109 	va_start(va, format);
    110 	umem_vprintf(format, va);
    111 	va_end(va);
    112 
    113 	if (format[strlen(format)-1] != '\n')
    114 		umem_error_enter("\n");
    115 
    116 	print_stacktrace();
    117 
    118 	umem_do_abort();
    119 }
    120 
    121 void
    122 umem_err_recoverable(const char *format, ...)
    123 {
    124 	va_list va;
    125 
    126 	va_start(va, format);
    127 	umem_vprintf(format, va);
    128 	va_end(va);
    129 
    130 	if (format[strlen(format)-1] != '\n')
    131 		umem_error_enter("\n");
    132 
    133 	print_stacktrace();
    134 
    135 	if (umem_abort > 0)
    136 		umem_do_abort();
    137 }
    138 
    139 int
    140 __umem_assert_failed(const char *assertion, const char *file, int line)
    141 {
    142 	umem_panic("Assertion failed: %s, file %s, line %d\n",
    143 	    assertion, file, line);
    144 	/*NOTREACHED*/
    145 	return (0);
    146 }
    147