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
38static volatile int umem_exiting = 0;
39#define	UMEM_EXIT_ABORT	1
40
41static mutex_t umem_exit_lock = DEFAULTMUTEX; /* protects umem_exiting */
42
43static int
44firstexit(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 */
67static void __NORETURN
68umem_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
83static void
84print_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
104void
105umem_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
121void
122umem_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
139int
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