For the sake of completeness, here is a link to the SIGSEGV handler code example and an explanation. I think I should have RTFM, but sometimes I get flying in a direction toward a goal and time, and the momentum keeps me from slowing down to browse the documentation on the way by. It isn't a good way, but sometimes you just have to cut your way through to a solution, and then go back and clean up the side effects.
#ifndef SIGSEGV_NO_AUTO_INIT static void __attribute((constructor)) init(void) { setup_sigsegv(); } #endif
The section above is something that I realized while making the example my own. I had been initializing setup_sigsegv() in main and after studying the code, I realized that SIGSEGV_NO_AUTO_INIT was not defined and as such it would initialize itself. I was mangling the perror information and creating a SIGSEGV by accessing a NULL pointer. In this case, I am interested in establishing a method by which the program determines it has failed horribly and done something bad which implies it is a failed combination. When I first found this example I used it and ignored the things I didn't understand. It was years ago and now I can say that I get the complete structure of how it acts, how it is initialized and where it links to produce the effect. At the time, it was a bit of voodoo which worked and things like that give me an uneasy feeling about my code and I will delete them to avoid undue stress when I worry about the determinant and reliability of the final product. It is good to know and experiment with each and every part, as it reduces my anxiety.
Another thing that bothers me is the use of if or for without braces {}. It is something that scares me and can bite you later when you are making changes to the code.I will make those changes in this code now. The problem is that you can add a line, thinking it is executed on the if or whatever and it actually changes the entire structure of the action. I just consider that too easy to goof up and I avoid it.
I also learned there is something going on down under the code that interests me and I will find out why perror() reports an error sometimes when I would not suspect an error should be present.
#include <stdio.h> #include <stdlib.h> #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include <memory.h> #include <signal.h> #include <ucontext.h> #include <dlfcn.h> #include <execinfo.h> #define NO_CPP_DEMANGLE #ifndef NO_CPP_DEMANGLE #include <cxxabi.h> #endif #if defined(REG_RIP) # define SIGSEGV_STACK_IA64 # define REGFORMAT "%016lx" #elif defined(REG_EIP) # define SIGSEGV_STACK_X86 # define REGFORMAT "%08x" #else # define SIGSEGV_STACK_GENERIC # define REGFORMAT "%x" #endif static void signal_segv(int signum, siginfo_t* info, void*ptr) { static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; char syscom[256]; size_t i; ucontext_t *ucontext = (ucontext_t*)ptr; #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) int f = 0; Dl_info dlinfo; void **bp = 0; void *ip = 0; #else void *bt[20]; char **strings; size_t sz; #endif fprintf(stderr, "Segmentation Fault!\n"); fprintf(stderr, "info.si_signo = %d\n", signum); fprintf(stderr, "info.si_errno = %d\n", info->si_errno); fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]); fprintf(stderr, "info.si_addr = %p\n", info->si_addr); /* for(i = 0; i < NGREG; i++) */ i=0; fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n",(int)i, (unsigned int)ucontext->uc_mcontext.gregs[i]); #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) # if defined(SIGSEGV_STACK_IA64) ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; # elif defined(SIGSEGV_STACK_X86) ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; # endif fprintf(stderr, "Stack trace:\n"); while(bp && ip) { if(!dladdr(ip, &dlinfo)) break; const char *symname = dlinfo.dli_sname; #ifndef NO_CPP_DEMANGLE int status; char *tmp = __cxa_demangle(symname, NULL, 0, &status); if(status == 0 && tmp) symname = tmp; #endif fprintf(stderr, "% 2d: %p <%s+%u> (%s)\n", ++f, ip, symname, (unsigned)(ip - dlinfo.dli_saddr), dlinfo.dli_fname); #ifndef NO_CPP_DEMANGLE if(tmp) free(tmp); #endif if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main")) break; ip = bp[1]; bp = (void**)bp[0]; } #else /* fprintf(stderr, "Stack trace (non-dedicated):\n"); */ sz = backtrace(bt, 20); strings = backtrace_symbols(bt, sz); /* for(i = 0; i < sz; ++i){ fprintf(stderr, "%s\n", strings[i]);} */ for (i=0; i < sz; i++) { if ( bt[i] < (void *)0x420000 && bt[i] > (void *)0x400000) { sprintf(syscom,"addr2line %p -f -e solver",bt[i]); system(syscom); }; } printf("Apoptosis is advised!\n"); #endif /* fprintf(stderr, "End of stack trace\n"); */ exit (-1); } int setup_sigsegv() { struct sigaction action; perror("NO ERROR, sigaction\n"); memset(&action, 0, sizeof(action)); action.sa_sigaction = signal_segv; action.sa_flags = SA_SIGINFO; if(sigaction(SIGSEGV, &action, NULL) < 0) { perror("sigaction"); return 0; } return 1; } #ifndef SIGSEGV_NO_AUTO_INIT static void __attribute((constructor)) init(void) { setup_sigsegv(); } #endif
0 comments:
Post a Comment