Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_signals.c
Go to the documentation of this file.
1
9#include <signal.h>
10#include <stdio.h>
11#include <assert.h>
12#include <stdlib.h>
13#include <stdbool.h>
14#include <stdint.h>
15#include <stdbool.h>
16#include <errno.h>
17#include <string.h>
18
19#include "nilorea/n_log.h"
20#include "nilorea/n_signals.h"
21#include "nilorea/n_str.h"
22
24#define LOGFPRT(...) fprintf(stderr, "Error: " __VA_ARGS__)
25
27#define LOGNLOG(...) n_log(LOG_ERR, __VA_ARGS__)
28
30#define LOGSIG LOGNLOG
31
34
35#ifdef __windows__
36#include <windows.h>
37#include <imagehlp.h>
38#else
39#include <err.h>
40#include <execinfo.h>
41#endif
42
43// void almost_c99_signal_handler(int sig)
44// {
45// switch(sig)
46// {
47// case SIGABRT:
48// LOGSIG("Caught SIGABRT: usually caused by an abort() or assert()" );
49// break;
50// case SIGFPE:
51// LOGSIG("Caught SIGFPE: arithmetic exception, such as divide by zero" );
52// break;
53// case SIGILL:
54// LOGSIG("Caught SIGILL: illegal instruction" );
55// break;
56// case SIGINT:
57// LOGSIG("Caught SIGINT: interactive attention signal, probably a ctrl+c" );
58// break;
59// case SIGSEGV:
60// LOGSIG("Caught SIGSEGV: segfault" );
61// break;
62// case SIGTERM:
63// default:
64// LOGSIG("Caught SIGTERM: a termination request was sent to the program" );
65// break;
66// }
67// _Exit(1);
68// }
69
70// void set_signal_handler()
71// {
72// signal(SIGABRT, almost_c99_signal_handler);
73// signal(SIGFPE, almost_c99_signal_handler);
74// signal(SIGILL, almost_c99_signal_handler);
75// signal(SIGINT, almost_c99_signal_handler);
76// signal(SIGSEGV, almost_c99_signal_handler);
77// signal(SIGTERM, almost_c99_signal_handler);
78// }
79
86int addr2line(char const* const program_name, void const* const addr) {
87 char addr2line_cmd[4093] = "";
88
89 /* have addr2line map the address to the relent line in the code */
90#ifdef __APPLE__
91 /* apple does things differently... */
92 sprintf(addr2line_cmd, "atos -o %.256s ./%p", program_name, addr);
93#else
94#ifdef __windows__
95 sprintf(addr2line_cmd, "addr2line -f -p -e ./%s %p", program_name, addr);
96 LOGSIG("%s", addr2line_cmd);
97 return 0;
98#else
99 sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
100#endif
101#endif
102 N_STR* output = NULL;
103 int ret = -1;
104 n_popen(addr2line_cmd, 1024, (void**)&output, &ret);
105 LOGSIG("%s", output->data);
106 free_nstr(&output);
107 return ret;
108} /* addr2line(...) */
109
110#ifdef __windows__
115void windows_print_stacktrace(CONTEXT* context) {
116 SymInitialize(GetCurrentProcess(), 0, true);
117
118 STACKFRAME frame = {0};
119
120 /* setup initial stack frame */
121#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
122 /* Wrong values for W10 ? */
123 frame.AddrPC.Offset = context->Eip;
124 frame.AddrPC.Mode = AddrModeFlat;
125 frame.AddrStack.Offset = context->Esp;
126 frame.AddrStack.Mode = AddrModeFlat;
127 frame.AddrFrame.Offset = context->Ebp;
128 frame.AddrFrame.Mode = AddrModeFlat;
129#else
130 frame.AddrPC.Offset = context->Rip;
131 frame.AddrPC.Mode = AddrModeFlat;
132 frame.AddrStack.Offset = context->Rsp;
133 frame.AddrStack.Mode = AddrModeFlat;
134 frame.AddrFrame.Offset = context->Rbp;
135 frame.AddrFrame.Mode = AddrModeFlat;
136#endif
137
138 while (StackWalk(IMAGE_FILE_MACHINE_I386,
139 GetCurrentProcess(),
140 GetCurrentThread(),
141 &frame,
142 context,
143 0,
144 SymFunctionTableAccess,
145 SymGetModuleBase,
146 0)) {
147 addr2line(__n_stack_traced_progam_name, (void*)frame.AddrPC.Offset);
148 }
149
150 SymCleanup(GetCurrentProcess());
151} /* windows_print_stacktrace(...) */
152
158LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS* ExceptionInfo) {
159 switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
160 case EXCEPTION_ACCESS_VIOLATION:
161 LOGSIG("Error: EXCEPTION_ACCESS_VIOLATION");
162 break;
163 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
164 LOGSIG("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
165 break;
166 case EXCEPTION_BREAKPOINT:
167 LOGSIG("Error: EXCEPTION_BREAKPOINT");
168 break;
169 case EXCEPTION_DATATYPE_MISALIGNMENT:
170 LOGSIG("Error: EXCEPTION_DATATYPE_MISALIGNMENT");
171 break;
172 case EXCEPTION_FLT_DENORMAL_OPERAND:
173 LOGSIG("Error: EXCEPTION_FLT_DENORMAL_OPERAND");
174 break;
175 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
176 LOGSIG("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO");
177 break;
178 case EXCEPTION_FLT_INEXACT_RESULT:
179 LOGSIG("Error: EXCEPTION_FLT_INEXACT_RESULT");
180 break;
181 case EXCEPTION_FLT_INVALID_OPERATION:
182 LOGSIG("Error: EXCEPTION_FLT_INVALID_OPERATION");
183 break;
184 case EXCEPTION_FLT_OVERFLOW:
185 LOGSIG("Error: EXCEPTION_FLT_OVERFLOW");
186 break;
187 case EXCEPTION_FLT_STACK_CHECK:
188 LOGSIG("Error: EXCEPTION_FLT_STACK_CHECK");
189 break;
190 case EXCEPTION_FLT_UNDERFLOW:
191 LOGSIG("Error: EXCEPTION_FLT_UNDERFLOW");
192 break;
193 case EXCEPTION_ILLEGAL_INSTRUCTION:
194 LOGSIG("Error: EXCEPTION_ILLEGAL_INSTRUCTION");
195 break;
196 case EXCEPTION_IN_PAGE_ERROR:
197 LOGSIG("Error: EXCEPTION_IN_PAGE_ERROR");
198 break;
199 case EXCEPTION_INT_DIVIDE_BY_ZERO:
200 LOGSIG("Error: EXCEPTION_INT_DIVIDE_BY_ZERO");
201 break;
202 case EXCEPTION_INT_OVERFLOW:
203 LOGSIG("Error: EXCEPTION_INT_OVERFLOW");
204 break;
205 case EXCEPTION_INVALID_DISPOSITION:
206 LOGSIG("Error: EXCEPTION_INVALID_DISPOSITION");
207 break;
208 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
209 LOGSIG("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION");
210 break;
211 case EXCEPTION_PRIV_INSTRUCTION:
212 LOGSIG("Error: EXCEPTION_PRIV_INSTRUCTION");
213 break;
214 case EXCEPTION_SINGLE_STEP:
215 LOGSIG("Error: EXCEPTION_SINGLE_STEP");
216 break;
217 case EXCEPTION_STACK_OVERFLOW:
218 LOGSIG("Error: EXCEPTION_STACK_OVERFLOW");
219 break;
220 default:
221 LOGSIG("Error: Unrecognized Exception");
222 break;
223 }
224 /* If this is a stack overflow then we can't walk the stack, so just show
225 where the error happened */
226 if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
227 windows_print_stacktrace(ExceptionInfo->ContextRecord);
228 } else {
229 addr2line(__n_stack_traced_progam_name, (void*)ExceptionInfo->ContextRecord->Rip);
230 }
231 fflush(stdout);
232 fflush(stderr);
233 return EXCEPTION_EXECUTE_HANDLER;
234} /* windows_exception_handler( ... ) */
235
240void set_signal_handler(const char* progname) {
242 SetUnhandledExceptionFilter(windows_exception_handler);
243}
244#else
247
252 int i, trace_size = 0;
253 char** messages = (char**)NULL;
254
255 memset(stack_traces, 0, MAX_STACK_FRAMES * sizeof(void*));
256
257 trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
258 messages = backtrace_symbols(stack_traces, trace_size);
259
260 /* skip the first couple stack frames (as they are this function and
261 our handler) and also skip the last frame as it's (always?) junk. */
262 // for (i = 3; i < (trace_size - 1); ++i)
263 for (i = 0; i < trace_size; ++i) // we'll use this for now so you can see what's going on
264 {
266 LOGSIG(" error determining line # for: %s", messages[i]);
267 }
268 }
269 if (messages) {
270 free(messages);
271 }
272}
273
280void posix_signal_handler(int sig, siginfo_t* siginfo, void* context) {
281 (void)context;
282 switch (sig) {
283 case SIGSEGV:
284 LOGSIG("Caught SIGSEGV: Segmentation Fault");
285 break;
286 case SIGINT:
287 LOGSIG("Caught SIGINT: Interactive attention signal, (usually ctrl+c)");
288 break;
289 case SIGFPE:
290 switch (siginfo->si_code) {
291 case FPE_INTDIV:
292 LOGSIG("Caught SIGFPE: (integer divide by zero)");
293 break;
294 case FPE_INTOVF:
295 LOGSIG("Caught SIGFPE: (integer overflow)");
296 break;
297 case FPE_FLTDIV:
298 LOGSIG("Caught SIGFPE: (floating-point divide by zero)");
299 break;
300 case FPE_FLTOVF:
301 LOGSIG("Caught SIGFPE: (floating-point overflow)");
302 break;
303 case FPE_FLTUND:
304 LOGSIG("Caught SIGFPE: (floating-point underflow)");
305 break;
306 case FPE_FLTRES:
307 LOGSIG("Caught SIGFPE: (floating-point inexact result)");
308 break;
309 case FPE_FLTINV:
310 LOGSIG("Caught SIGFPE: (floating-point invalid operation)");
311 break;
312 case FPE_FLTSUB:
313 LOGSIG("Caught SIGFPE: (subscript out of range)");
314 break;
315 default:
316 LOGSIG("Caught SIGFPE: Arithmetic Exception");
317 break;
318 }
319 break;
320 case SIGILL:
321 switch (siginfo->si_code) {
322 case ILL_ILLOPC:
323 LOGSIG("Caught SIGILL: (illegal opcode)");
324 break;
325 case ILL_ILLOPN:
326 LOGSIG("Caught SIGILL: (illegal operand)");
327 break;
328 case ILL_ILLADR:
329 LOGSIG("Caught SIGILL: (illegal addressing mode)");
330 break;
331 case ILL_ILLTRP:
332 LOGSIG("Caught SIGILL: (illegal trap)");
333 break;
334 case ILL_PRVOPC:
335 LOGSIG("Caught SIGILL: (privileged opcode)");
336 break;
337 case ILL_PRVREG:
338 LOGSIG("Caught SIGILL: (privileged register)");
339 break;
340 case ILL_COPROC:
341 LOGSIG("Caught SIGILL: (coprocessor error)");
342 break;
343 case ILL_BADSTK:
344 LOGSIG("Caught SIGILL: (internal stack error)");
345 break;
346 default:
347 LOGSIG("Caught SIGILL: Illegal Instruction");
348 break;
349 }
350 break;
351 case SIGTERM:
352 LOGSIG("Caught SIGTERM: a termination request was sent to the program");
353 break;
354 case SIGABRT:
355 LOGSIG("Caught SIGABRT: usually caused by an abort() or assert()");
356 break;
357 default:
358 break;
359 }
361 _Exit(1);
362}
363
368void set_signal_handler(const char* progname) {
370
371#ifdef RLIMIT_STACK
372 /* Before starting the endless recursion, try to be friendly to the user's
373 machine. On some Linux 2.2.x systems, there is no stack limit for user
374 processes at all. We don't want to kill such systems. */
375 struct rlimit rl;
376 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
377 setrlimit(RLIMIT_STACK, &rl);
378#endif
379
380#ifdef __linux__
381 /* setup alternate stack */
382 {
384 static uint8_t alternate_stack[SIGALTSTACK_SIZE];
385 stack_t ss;
386
387 /* malloc is usually used here, I'm not 100% sure my static allocation
388 is valid but it seems to work just fine. */
389 ss.ss_sp = alternate_stack;
390 ss.ss_size = sizeof(alternate_stack);
391 ss.ss_flags = SS_ONSTACK;
392
393 if (sigaltstack(&ss, NULL) != 0) {
394 err(1, "sigaltstack");
395 }
396 }
397#endif
398 /* register our signal handlers */
399 {
400 struct sigaction sig_action;
401 sigemptyset(&sig_action.sa_mask);
402 sig_action.sa_sigaction = posix_signal_handler;
403
404#ifdef __APPLE__
405 /* for some reason we backtrace() doesn't work on osx
406 when we use an alternate stack */
407 sig_action.sa_flags = SA_SIGINFO;
408#else
409 sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
410#endif
411
412 if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
413 err(1, "sigaction");
414 }
415 if (sigaction(SIGFPE, &sig_action, NULL) != 0) {
416 err(1, "sigaction");
417 }
418 if (sigaction(SIGINT, &sig_action, NULL) != 0) {
419 err(1, "sigaction");
420 }
421 if (sigaction(SIGILL, &sig_action, NULL) != 0) {
422 err(1, "sigaction");
423 }
424 /* No TERM catch
425 if (sigaction(SIGTERM, &sig_action, NULL) != 0) { err(1, "sigaction"); } */
426 if (sigaction(SIGABRT, &sig_action, NULL) != 0) {
427 err(1, "sigaction");
428 }
429 }
430}
431#endif
char * addr
char * progname
Definition ex_signals.c:31
int n_popen(char *cmd, size_t read_buf_size, void **nstr_output, int *ret)
launch a command abd return output and status
Definition n_common.c:163
char * data
the string
Definition n_str.h:41
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:176
A box including a string and his lenght.
Definition n_str.h:39
#define SIGALTSTACK_SIZE
Size of the signal handler alternate stack.
Definition n_signals.h:21
#define MAX_STACK_FRAMES
Number of backtrace log lines.
Definition n_signals.h:23
void set_signal_handler(const char *progname)
Install a signal handler for progname.
Definition n_signals.c:368
Generic log system.
static void * stack_traces[32]
static frame list
Definition n_signals.c:246
static const char * __n_stack_traced_progam_name
name of program to debug (addr2line & co)
Definition n_signals.c:33
int addr2line(char const *const program_name, void const *const addr)
Resolve symbol name and source location given the path to the executable and an address.
Definition n_signals.c:86
#define LOGSIG
internal: output to syslog
Definition n_signals.c:30
void posix_print_stack_trace()
print current stack
Definition n_signals.c:251
void posix_signal_handler(int sig, siginfo_t *siginfo, void *context)
decode a signal and call stack print
Definition n_signals.c:280
Signals general handling with stack printing, from https://gist.github.com/jvranish/4441299.
N_STR and string function declaration.