- // Based on https://gist.github.com/jvranish/4441299 
-   
- #if defined(__linux__) || defined(__FreeBSD__) // Pierre-Marie Baty -- added compile guard 
-   
- #define _GNU_SOURCE 
- #include "harness/os.h" 
- #include <assert.h> 
- #include <ctype.h> 
- #include <dirent.h> 
- #include <err.h> 
- #include <errno.h> 
- #include <execinfo.h> 
- #include <fcntl.h> 
- #include <libgen.h> 
- #include <limits.h> 
- #include <link.h> 
- #include <signal.h> 
- #include <stdbool.h> 
- #include <stdint.h> 
- #include <stdio.h> 
- #include <stdlib.h> 
- #include <string.h> 
- #include <sys/stat.h> 
- #include <sys/types.h> 
- #include <termios.h> 
- #include <time.h> 
- #include <unistd.h> 
-   
- #define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0])) 
- #define MAX_STACK_FRAMES 64 
- #define TRACER_PID_STRING "TracerPid:" 
-   
- static int stack_nbr = 0; 
- static char _program_name[1024]; 
-   
- static void* stack_traces[MAX_STACK_FRAMES]; 
- static char name_buf[4096]; 
-   
- struct dl_iterate_callback_data { 
-     int initialized; 
-     intptr_t start; 
- } dethrace_dl_data; 
-   
- static int dl_iterate_callback(struct dl_phdr_info* info, size_t size, void* data) { 
-     struct dl_iterate_callback_data* callback_data = data; 
-   
-     if (strcmp(- info ->- dlpi_name , "") == 0) {
 
-         callback_data->start = info->dlpi_addr; 
-     } 
-     return 0; 
- } 
-   
- static intptr_t get_dethrace_offset(void) { 
-     if (!dethrace_dl_data.initialized) { 
-         dethrace_dl_data.initialized = 1; 
-         dl_iterate_phdr(dl_iterate_callback, &dethrace_dl_data); 
-     } 
-     return dethrace_dl_data.start; 
- } 
-   
- // Resolve symbol name and source location given the path to the executable and an address 
- int addr2line(char const* const program_name, void const* const addr) { 
-     char addr2line_cmd[512]; 
-   
-     /* have addr2line map the address to the related line in the code */ 
-     sprintf(- addr2line_cmd , "addr2line -f -p -e \"%s\" %p",-  program_name ,-  addr  --  get_dethrace_offset ()); // Pierre-Marie Baty -- support pathnames containing spaces
 
-   
-     fprintf(- stderr , "%d: ",-  stack_nbr ++);
 
- } 
-   
- static void print_stack_trace(void) { 
-     int i, trace_size = 0; 
-     char** messages = (char**)NULL; 
-   
-     fputs("\nStack trace:\n",-  stderr );
 
-   
-     trace_size = backtrace(stack_traces, MAX_STACK_FRAMES); 
-     messages = backtrace_symbols(stack_traces, trace_size); 
-   
-     /* skip the first couple stack frames (as they are this function and 
-      our handler) and also skip the last frame as it's (always?) junk. */ 
-     for (i = 3; i < (trace_size - 1); ++i) { 
-         if (addr2line(_program_name, stack_traces[i]) != 0) { 
-             printf("  error determining line # for: %s\n",-  messages [- i ]);
 
-         } 
-     } 
-     if (messages) { 
-     } 
- } 
-   
- static void signal_handler(int sig, siginfo_t* siginfo, void* context) { 
-     (void)context; 
-     fputs("\n******************\n",-  stderr );
 
-   
-     switch (sig) { 
-     case SIGSEGV: 
-         fputs("Caught SIGSEGV\n",-  stderr );
 
-         break; 
-     case SIGINT: 
-         fputs("Caught SIGINT\n",-  stderr );
 
-         break; 
-     case SIGFPE: 
-         switch (siginfo->si_code) { 
-         case FPE_INTDIV: 
-             fputs("Caught SIGFPE: FPE_INTDIV\n",-  stderr );
 
-             break; 
-         case FPE_INTOVF: 
-             fputs("Caught SIGFPE: FPE_INTOVF\n",-  stderr );
 
-             break; 
-         case FPE_FLTDIV: 
-             fputs("Caught SIGFPE: FPE_FLTDIV\n",-  stderr );
 
-             break; 
-         case FPE_FLTOVF: 
-             fputs("Caught SIGFPE: FPE_FLTOVF\n",-  stderr );
 
-             break; 
-         case FPE_FLTUND: 
-             fputs("Caught SIGFPE: FPE_FLTUND\n",-  stderr );
 
-             break; 
-         case FPE_FLTRES: 
-             fputs("Caught SIGFPE: FPE_FLTRES\n",-  stderr );
 
-             break; 
-         case FPE_FLTINV: 
-             fputs("Caught SIGFPE: FPE_FLTINV\n",-  stderr );
 
-             break; 
-         case FPE_FLTSUB: 
-             fputs("Caught SIGFPE: FPE_FLTSUB\n",-  stderr );
 
-             break; 
-         default: 
-             fputs("Caught SIGFPE: Arithmetic Exception\n",-  stderr );
 
-             break; 
-         } 
-         break; 
-     case SIGILL: 
-         switch (siginfo->si_code) { 
-         case ILL_ILLOPC: 
-             fputs("Caught SIGILL: ILL_ILLOPC\n",-  stderr );
 
-             break; 
-         case ILL_ILLOPN: 
-             fputs("Caught SIGILL: ILL_ILLOPN\n",-  stderr );
 
-             break; 
-         case ILL_ILLADR: 
-             fputs("Caught SIGILL: ILL_ILLADR\n",-  stderr );
 
-             break; 
-         case ILL_ILLTRP: 
-             fputs("Caught SIGILL: ILL_ILLTRP\n",-  stderr );
 
-             break; 
-         case ILL_PRVOPC: 
-             fputs("Caught SIGILL: ILL_PRVOPC\n",-  stderr );
 
-             break; 
-         case ILL_PRVREG: 
-             fputs("Caught SIGILL: ILL_PRVREG\n",-  stderr );
 
-             break; 
-         case ILL_COPROC: 
-             fputs("Caught SIGILL: ILL_COPROC\n",-  stderr );
 
-             break; 
-         case ILL_BADSTK: 
-             fputs("Caught SIGILL: ILL_BADSTK\n",-  stderr );
 
-             break; 
-         default: 
-             fputs("Caught SIGILL: Illegal Instruction\n",-  stderr );
 
-             break; 
-         } 
-         break; 
-     case SIGTERM: 
-         fputs("Caught SIGTERM\n",-  stderr );
 
-         break; 
-     case SIGABRT: 
-         fputs("Caught SIGABRT\n",-  stderr );
 
-         break; 
-     default: 
-         break; 
-     } 
-     fputs("******************\n",-  stderr );
 
-     print_stack_trace(); 
- } 
-   
- void resolve_full_path(char* path, const char* argv0) { 
-     if (argv0[0] == '/') { // run with absolute path 
-     } else {               // run with relative path 
-         if (NULL == getcwd(path, PATH_MAX)) { 
-             return; 
-         } 
-     } 
- } 
-   
- void OS_InstallSignalHandler(char* program_name) { 
-     resolve_full_path(_program_name, program_name); 
-   
-     /* setup alternate stack */ 
-     { 
-         stack_t ss = {}; 
-         ss. ss_sp = malloc(2 *-  MINSIGSTKSZ );
-         if (ss.ss_sp == NULL) { 
-             err(1, "malloc"); 
-         } 
-         ss.ss_size = 2 * MINSIGSTKSZ; 
-         ss.ss_flags = 0; 
-   
-         if (sigaltstack(&ss, NULL) != 0) { 
-             err(1, "sigaltstack"); 
-         } 
-     } 
-   
-     /* register our signal handlers */ 
-     { 
-         struct sigaction sig_action = {}; 
-         sig_action.sa_sigaction = signal_handler; 
-         sigemptyset(&sig_action.sa_mask); 
-   
-         sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK; 
-   
-         if (sigaction(SIGSEGV, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-         if (sigaction(SIGFPE, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-         if (sigaction(SIGINT, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-         if (sigaction(SIGILL, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-         if (sigaction(SIGTERM, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-         if (sigaction(SIGABRT, &sig_action, NULL) != 0) { 
-             err(1, "sigaction"); 
-         } 
-     } 
- } 
-   
- FILE* OS_fopen(const char* pathname, const char* mode) { 
-     FILE *-  f  = fopen(- pathname ,-  mode );
-     if (f != NULL) { 
-         return f; 
-     } 
-     char buffer[512]; 
-     char buffer2[512]; 
-     char* pDirName = dirname(buffer); 
-     char* pBaseName = basename(buffer2); 
-     DIR* pDir = opendir(pDirName); 
-     if (pDir == NULL) { 
-         return NULL; 
-     } 
-     for (struct dirent* pDirent = readdir(pDir); pDirent != NULL; pDirent = readdir(pDir)) { 
-         if (strcasecmp(pBaseName, pDirent->d_name) == 0) { 
-             strcat(- pDirName ,-  pDirent ->- d_name );
 
-             f  = fopen(- pDirName ,-  mode );
-             break; 
-         } 
-     } 
-     closedir(pDir); 
-     if (f == NULL) { 
-         fprintf(- stderr , "Failed to open \"%s\" (%s)\n",-  pathname , strerror(- errno ));
 
-     } 
-     return f; 
- } 
-   
- size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) { 
-     struct termios old, new; 
-     char c; 
-     size_t len; 
-   
-     tcgetattr(STDIN_FILENO, &old); 
-     new = old; 
-     new.c_lflag &= ~(ICANON | ECHO); 
-     tcsetattr(STDIN_FILENO, TCSAFLUSH, &new); 
-   
-     len = 0; 
-     pBuffer[len] = '\0'; 
-     while (1) { 
-         if (read(STDIN_FILENO, &c, 1) == 1) { 
-             if (c == 0x7f) { 
-                 if (len > 0) { 
-                     len--; 
-                     pBuffer[len] = '\0'; 
-                     continue; 
-                 } 
-             } else if (c == '\r' || c == '\n') { 
-                 break; 
-             } else if (len < pBufferLen - 1) { 
-                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { 
-                     pBuffer[len] = c; 
-                     len++; 
-                     pBuffer[len] = '\0'; 
-                 } 
-             } 
-         } 
-     } 
-   
-     tcsetattr(STDIN_FILENO, TCSANOW, &old); 
-     return len; 
- } 
-   
- char* OS_Dirname(const char* path) { 
-     return dirname(name_buf); 
- } 
-   
- char* OS_Basename(const char* path) { 
-     return basename(name_buf); 
- } 
-   
- #endif // __linux__ 
-