Added stacktrace logging
authorTomasz Olszak <t.olszak@samsung.com>
Thu, 25 Jun 2015 13:45:35 +0000 (15:45 +0200)
committerLukasz Stanislawski <l.stanislaws@samsung.com>
Fri, 26 Jun 2015 15:47:23 +0000 (17:47 +0200)
Change-Id: Idb528084aca55b7166b9c872e50dedc5625ed478
Signed-off-by: Tomasz Olszak <t.olszak@samsung.com>
src/main.c

index 68bb334..decd757 100644 (file)
@@ -1,3 +1,7 @@
+#include <time.h>
+#include <signal.h>
+#include <err.h>
+#include <execinfo.h>
 #include <appcore-efl.h>
 #include <Elementary.h>
 #include <eldbus-1/Eldbus.h>
 #include "screen_reader.h"
 #include "screen_reader_gestures.h"
 
+#define MAX_STACK_FRAMES 64
+static void *stack_traces[MAX_STACK_FRAMES];
+
+void posix_print_stack_trace(FILE *log_file)
+{
+    int i, trace_size = 0;
+    char **messages = (char **)NULL;
+
+    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)
+    for (i = 0; i < trace_size; ++i) // we'll use this for now so you can see what's going on
+    {
+        fprintf(log_file, "  BACKTRACE LINE %i: %s\n",i, messages[i]);
+    }
+    if (messages) { free(messages); }
+}
+
+void print_warning(int sig, siginfo_t *siginfo, FILE *log_file)
+{
+    switch(sig)
+    {
+    case SIGSEGV:
+        fputs("Caught SIGSEGV: Segmentation Fault\n", log_file);
+        break;
+    case SIGINT:
+        fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n", log_file);
+        break;
+    case SIGFPE:
+        switch(siginfo->si_code)
+        {
+        case FPE_INTDIV:
+            fputs("Caught SIGFPE: (integer divide by zero)\n", log_file);
+            break;
+        case FPE_INTOVF:
+            fputs("Caught SIGFPE: (integer overflow)\n", log_file);
+            break;
+        case FPE_FLTDIV:
+            fputs("Caught SIGFPE: (floating-point divide by zero)\n", log_file);
+            break;
+        case FPE_FLTOVF:
+            fputs("Caught SIGFPE: (floating-point overflow)\n", log_file);
+            break;
+        case FPE_FLTUND:
+            fputs("Caught SIGFPE: (floating-point underflow)\n", log_file);
+            break;
+        case FPE_FLTRES:
+            fputs("Caught SIGFPE: (floating-point inexact result)\n", log_file);
+            break;
+        case FPE_FLTINV:
+            fputs("Caught SIGFPE: (floating-point invalid operation)\n", log_file);
+            break;
+        case FPE_FLTSUB:
+            fputs("Caught SIGFPE: (subscript out of range)\n", log_file);
+            break;
+        default:
+            fputs("Caught SIGFPE: Arithmetic Exception\n", log_file);
+            break;
+        }
+    case SIGILL:
+        switch(siginfo->si_code)
+        {
+        case ILL_ILLOPC:
+            fputs("Caught SIGILL: (illegal opcode)\n", log_file);
+            break;
+        case ILL_ILLOPN:
+            fputs("Caught SIGILL: (illegal operand)\n", log_file);
+            break;
+        case ILL_ILLADR:
+            fputs("Caught SIGILL: (illegal addressing mode)\n", log_file);
+            break;
+        case ILL_ILLTRP:
+            fputs("Caught SIGILL: (illegal trap)\n", log_file);
+            break;
+        case ILL_PRVOPC:
+            fputs("Caught SIGILL: (privileged opcode)\n", log_file);
+            break;
+        case ILL_PRVREG:
+            fputs("Caught SIGILL: (privileged register)\n", log_file);
+            break;
+        case ILL_COPROC:
+            fputs("Caught SIGILL: (coprocessor error)\n", log_file);
+            break;
+        case ILL_BADSTK:
+            fputs("Caught SIGILL: (internal stack error)\n", log_file);
+            break;
+        default:
+            fputs("Caught SIGILL: Illegal Instruction\n", log_file);
+            break;
+        }
+        break;
+    case SIGTERM:
+        fputs("Caught SIGTERM: a termination request was sent to the program\n", log_file);
+        break;
+    case SIGABRT:
+        fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", log_file);
+        break;
+    default:
+        break;
+    }
+}
+
+
+void posix_signal_handler(int sig, siginfo_t *siginfo, void *context)
+{
+    char file_name[256] = {0};
+    struct tm * timeinfo;
+    time_t rawtime = time(NULL);
+    timeinfo = localtime(&rawtime);
+    sprintf(file_name, "/tmp/screen_reader_crash_stacktrace_%i%i%i_%i:%i:%i_pid_%i.log", timeinfo->tm_year,
+            timeinfo->tm_mon, timeinfo->tm_mday,timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, getpid());
+    FILE * log_file = fopen(file_name, "w");
+    (void)context;
+    print_warning(sig, siginfo, stderr);
+    print_warning(sig, siginfo, log_file);
+    posix_print_stack_trace(log_file);
+    fclose(log_file);
+    log_file = NULL;
+    _Exit(1);
+}
+static uint8_t alternate_stack[SIGSTKSZ];
+void set_signal_handler()
+{
+    /* setup alternate stack */
+    {
+        stack_t ss = {};
+        /* malloc is usually used here, I'm not 100% sure my static allocation
+         is valid but it seems to work just fine. */
+        ss.ss_sp = (void*)alternate_stack;
+        ss.ss_size = SIGSTKSZ;
+        ss.ss_flags = 0;
+
+        if (sigaltstack(&ss, NULL) != 0) { err(1, "sigaltstack"); }
+    }
+
+    /* register our signal handlers */
+    {
+        struct sigaction sig_action = {};
+        sig_action.sa_sigaction = posix_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"); }
+    }
+}
 
 static int app_create(void *data)
 {
@@ -34,6 +192,7 @@ static int app_terminate(void *data)
 
 int main(int argc, char **argv)
 {
+   set_signal_handler();
    unsetenv("ELM_ATSPI_MODE");
 
    struct appcore_ops ops =