tsort: replace with openbsd version
[unleashed.git] / contrib / libjeffpc / error.c
blobee41ef15e98a8b321c981e50e1a1b1f8bfc47770
1 /*
2 * Copyright (c) 2013-2016 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
23 #include <inttypes.h>
24 #include <syslog.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <assert.h>
28 #include <pthread.h>
29 #include <execinfo.h>
30 #include <ucontext.h>
32 #include <jeffpc/config.h>
33 #include <jeffpc/error.h>
35 #include "init.h"
37 #ifndef HAVE_ASSFAIL
38 static int assfail(const char *assertion, const char *file, int line)
40 __assert(assertion, file, line);
42 return 0; /* not reached */
44 #else
45 extern int assfail(const char *a, const char *f, int l);
46 #endif
48 void default_print(enum errlevel level, const char *fmt, va_list ap)
50 FILE *out;
52 switch (level) {
53 case CE_DEBUG:
54 case CE_INFO:
55 out = stdout;
56 break;
57 case CE_WARN:
58 case CE_ERROR:
59 case CE_CRIT:
60 case CE_PANIC:
61 default:
62 out = stderr;
63 break;
66 vfprintf(out, fmt, ap);
69 void jeffpc_print(enum errlevel level, const char *fmt, ...)
71 va_list ap;
73 va_start(ap, fmt);
74 libops.print(level, fmt, ap);
75 va_end(ap);
78 void default_log(int loglevel, const char *fmt, va_list ap)
81 * This function is a no-op but it exists to allow consumers of
82 * libjeffpc to override it with their own log implementation.
86 void jeffpc_log(int loglevel, const char *fmt, ...)
88 va_list ap;
90 va_start(ap, fmt);
91 libops.log(loglevel, fmt, ap);
92 va_end(ap);
95 void default_assfail(const char *a, const char *f, int l)
97 jeffpc_log(LOG_ALERT, "assertion failed: %s, file: %s, line: %d",
98 a, f, l);
100 print_stacktrace(CE_CRIT, NULL);
102 assfail(a, f, l);
105 void jeffpc_assfail(const char *a, const char *f, int l)
107 libops.assfail(a, f, l);
109 /* this is a hack to shut up gcc */
110 abort();
113 void default_assfail3(const char *a, uintmax_t lv, const char *op, uintmax_t rv,
114 const char *f, int l)
116 char msg[512];
118 snprintf(msg, sizeof(msg), "%s (0x%"PRIx64" %s 0x%"PRIx64")", a, lv,
119 op, rv);
121 jeffpc_log(LOG_ALERT, "assertion failed: %s, file: %s, line: %d",
122 msg, f, l);
124 print_stacktrace(CE_CRIT, NULL);
126 assfail(msg, f, l);
129 void jeffpc_assfail3(const char *a, uintmax_t lv, const char *op, uintmax_t rv,
130 const char *f, int l)
132 libops.assfail3(a, lv, op, rv, f, l);
134 /* this is a hack to shut up gcc */
135 abort();
138 void cmn_verr(enum errlevel level, const char *fmt, va_list ap)
140 const char *levelstr;
141 unsigned long tid;
142 int loglevel;
143 bool panic;
144 char buf[256];
146 tid = (unsigned long) pthread_self();
147 panic = false;
149 switch (level) {
150 case CE_DEBUG:
151 levelstr = "DEBUG";
152 loglevel = LOG_DEBUG;
153 break;
154 case CE_INFO:
155 levelstr = "INFO";
156 loglevel = LOG_INFO;
157 break;
158 case CE_WARN:
159 levelstr = "WARN";
160 loglevel = LOG_WARNING;
161 break;
162 case CE_ERROR:
163 levelstr = "ERROR";
164 loglevel = LOG_ERR;
165 break;
166 case CE_CRIT:
167 levelstr = "CRIT";
168 loglevel = LOG_CRIT;
169 break;
170 case CE_PANIC:
171 levelstr = "PANIC";
172 loglevel = LOG_ALERT;
173 panic = true;
174 break;
175 default:
176 levelstr = "?????";
177 loglevel = LOG_CRIT;
178 panic = true;
179 break;
182 vsnprintf(buf, sizeof(buf), fmt, ap);
185 * We are printing the thread ID as a 4-digit number. This will
186 * allow systems that use small integers (e.g., Illumos) to have
187 * short IDs. Systems that use large integers (e.g., Linux) will
188 * use more digits. Since on those systems the IDs will be
189 * clustered around some big integer, they will very likely always
190 * print as the same number of digits.
192 jeffpc_log(loglevel, "[%04lx] %-5s %s\n", tid, levelstr, buf);
193 jeffpc_print(level, "[%04lx] %-5s %s\n", tid, levelstr, buf);
195 if (panic) {
196 print_stacktrace(CE_CRIT, NULL);
197 abort();
201 void cmn_err(enum errlevel level, const char *fmt, ...)
203 va_list ap;
205 va_start(ap, fmt);
206 cmn_verr(level, fmt, ap);
207 va_end(ap);
210 void panic(const char *fmt, ...)
212 va_list ap;
214 va_start(ap, fmt);
215 cmn_verr(CE_PANIC, fmt, ap);
216 va_end(ap);
218 /* this is a hack to shut up gcc */
219 abort();
223 * Note: We must not allocate any memory, etc. because we want this function
224 * to be callable from any context.
226 void save_stacktrace(struct stack *stack)
228 size_t nframes;
230 nframes = backtrace(stack->frames, ERROR_STACK_FRAMES);
231 stack->nframes = nframes;
233 /* NULL-out any unused frames */
234 while (nframes < ERROR_STACK_FRAMES)
235 stack->frames[nframes++] = NULL;
238 #ifndef HAVE_ADDRTOSYMSTR
239 static void addrtosymstr(void *pc, char *buf, size_t buflen)
241 snprintf(buf, buflen, "[%p]", pc);
243 #endif
246 * Note: We must not allocate any memory, etc. because we want this function
247 * to be callable from any context.
249 void print_stacktrace(enum errlevel level, struct stack *stack)
251 struct stack here;
252 size_t i;
254 if (!stack) {
255 save_stacktrace(&here);
256 stack = &here;
259 for (i = 0; i < stack->nframes; i++) {
260 char tmp[256];
262 addrtosymstr(stack->frames[i], tmp, sizeof(tmp));
264 cmn_err(level, " %s", tmp);
269 * If we have sys/debug.h, let's include it so that the assfail function
270 * signature gets checked to be what we expect.
272 * This include is at the end of this file because it polutes the namespace
273 * big time.
275 #ifdef HAVE_SYS_DEBUG_H
276 #include <sys/debug.h>
277 #endif