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
32 #include <jeffpc/config.h>
33 #include <jeffpc/error.h>
38 static int assfail(const char *assertion
, const char *file
, int line
)
40 __assert(assertion
, file
, line
);
42 return 0; /* not reached */
45 extern int assfail(const char *a
, const char *f
, int l
);
48 void default_print(enum errlevel level
, const char *fmt
, va_list ap
)
66 vfprintf(out
, fmt
, ap
);
69 void jeffpc_print(enum errlevel level
, const char *fmt
, ...)
74 libops
.print(level
, fmt
, 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
, ...)
91 libops
.log(loglevel
, fmt
, 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",
100 print_stacktrace(CE_CRIT
, NULL
);
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 */
113 void default_assfail3(const char *a
, uintmax_t lv
, const char *op
, uintmax_t rv
,
114 const char *f
, int l
)
118 snprintf(msg
, sizeof(msg
), "%s (0x%"PRIx64
" %s 0x%"PRIx64
")", a
, lv
,
121 jeffpc_log(LOG_ALERT
, "assertion failed: %s, file: %s, line: %d",
124 print_stacktrace(CE_CRIT
, NULL
);
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 */
138 void cmn_verr(enum errlevel level
, const char *fmt
, va_list ap
)
140 const char *levelstr
;
146 tid
= (unsigned long) pthread_self();
152 loglevel
= LOG_DEBUG
;
160 loglevel
= LOG_WARNING
;
172 loglevel
= LOG_ALERT
;
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
);
196 print_stacktrace(CE_CRIT
, NULL
);
201 void cmn_err(enum errlevel level
, const char *fmt
, ...)
206 cmn_verr(level
, fmt
, ap
);
210 void panic(const char *fmt
, ...)
215 cmn_verr(CE_PANIC
, fmt
, ap
);
218 /* this is a hack to shut up gcc */
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
)
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
);
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
)
255 save_stacktrace(&here
);
259 for (i
= 0; i
< stack
->nframes
; i
++) {
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
275 #ifdef HAVE_SYS_DEBUG_H
276 #include <sys/debug.h>