Seg fault handler
authorColin Clark <colin.clark@cclark.uk>
Fri, 10 Mar 2023 15:56:13 +0000 (15:56 +0000)
committerColin Clark <colin.clark@cclark.uk>
Fri, 10 Mar 2023 15:56:13 +0000 (15:56 +0000)
- Local handler for seg. fault
- Stack dump on seg. fault
- Stack dump option in meson_options.txt
- Bug fix in DEBUG_BT()

meson.build
meson_options.txt
src/debug.cc
src/main.cc

index 01137a7..2091bde 100644 (file)
@@ -45,7 +45,7 @@ project(
     version : run_command('./version.sh', check : true).stdout().strip(),
     license : ['GPL-2.0-or-later'],
     meson_version : '>=0.53.0',
-    default_options : ['warning_level=3', 'buildtype=debugoptimized']
+    default_options : ['warning_level=3', 'buildtype=debugoptimized', 'cpp_link_args=-rdynamic']
 )
 
 # To inhibit warnings from the generated files icons_inline.h and ui_icons.h
@@ -213,6 +213,20 @@ else
     summary({'print preview' : ['disabled - print preview supported:', false]}, section : 'Configuration', bool_yn : true)
 endif
 
+# Required only for seg. fault stacktrace and backtrace debugging
+option = get_option('execinfo')
+if not option.disabled()
+    result = cc.check_header('execinfo.h')
+    if result
+        conf_data.set('HAVE_EXECINFO_H', 1)
+        summary({'execinfo' : ['stacktrace supported:', true]}, section : 'Configuration', bool_yn : true)
+    else
+        summary({'execinfo' : ['stacktrace supported:', false]}, section : 'Configuration', bool_yn : true)
+    endif
+else
+    summary({'execinfo' : ['stacktrace supported:', false]}, section : 'Configuration', bool_yn : true)
+endif
+
 exiv2_dep = []
 req_version = '>=0.11'
 option = get_option('exiv2')
@@ -501,12 +515,6 @@ else
     summary({'nl_langinfo' : ['nl_langinfo not found - first weekday depends on locale:', false, 'first weekday defaults to Monday']}, section : 'Documentation', bool_yn : true)
 endif
 
-# Required only for backtrace debugging
-result = cc.check_header('execinfo.h')
-if result
-    conf_data.set('HAVE_EXECINFO_H', 1)
-endif
-
 conf_data.set_quoted('GETTEXT_PACKAGE', meson.project_name())
 conf_data.set_quoted('GQ_APPDIR', gq_appdir)
 conf_data.set_quoted('GQ_BINDIR', gq_bindir)
index 32a089f..3b272f2 100644 (file)
@@ -28,6 +28,7 @@ option('cms', type : 'feature', value : 'auto', description : 'color management
 option('doxygen', type : 'feature', value : 'auto', description : 'lua api help file')
 option('djvu', type : 'feature', value : 'auto', description : 'djvu')
 option('evince', type : 'feature', value : 'auto', description : 'print preview')
+option('execinfo', type : 'feature', value : 'auto', description : 'execinfo.h')
 option('exiv2', type : 'feature', value : 'auto', description : 'exiv2')
 option('git', type : 'feature', value : 'auto', description : 'lua-api and changelog.html')
 option('gps-map', type : 'feature', value : 'auto', description : 'gps map')
index 940c352..5fb2ee2 100644 (file)
@@ -279,7 +279,7 @@ void log_print_backtrace(const gchar *file, const gchar *function, gint line)
        gchar *address_offset;
        gchar *cmd_line;
        gchar *exe_path;
-       gchar *function_name;
+       gchar *function_name = NULL;
        gchar *paren_end;
        gchar *paren_start;
        gint bt_size;
@@ -318,8 +318,10 @@ void log_print_backtrace(const gchar *file, const gchar *function, gint line)
                                                /* Remove redundant newline */
                                                path[strlen(path) - 1] = '\0';
 
-                                               function_name = g_strndup(path, g_strstr_len(path, strlen(path), "(") - path);
-
+                                               if (g_strstr_len(path, strlen(path), "(") != NULL)
+                                                       {
+                                                       function_name = g_strndup(path, g_strstr_len(path, strlen(path), "(") - path);
+                                                       }
                                                log_printf("%s %s", g_strstr_len(path, -1, "at ") + 3, function_name);
 
                                                g_free(function_name);
index 70308a4..9113612 100644 (file)
 #include <clutter-gtk/clutter-gtk.h>
 #endif
 
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
 gboolean thumb_format_changed = FALSE;
 static RemoteConnection *remote_connection = NULL;
 
@@ -71,6 +75,92 @@ gchar *gq_executable_path;
 gchar *desktop_file_template;
 gchar *instance_identifier;
 
+#if defined(SA_SIGINFO)
+void sigsegv_handler_cb(int UNUSED(signo), siginfo_t *info, void *UNUSED(context))
+{
+       gchar hex_char[16];
+       gint i;
+       guint64 addr;
+       guint64 char_index;
+#ifdef HAVE_EXECINFO_H
+       gint bt_size;
+       void *bt[1024];
+#endif
+
+       hex_char[0] = '0';
+       hex_char[1] = '1';
+       hex_char[2] = '2';
+       hex_char[3] = '3';
+       hex_char[4] = '4';
+       hex_char[5] = '5';
+       hex_char[6] = '6';
+       hex_char[7] = '7';
+       hex_char[8] = '8';
+       hex_char[9] = '9';
+       hex_char[10] = 'a';
+       hex_char[11] = 'b';
+       hex_char[12] = 'c';
+       hex_char[13] = 'd';
+       hex_char[14] = 'e';
+       hex_char[15] = 'f';
+
+       write(STDOUT_FILENO, "Geeqie fatal error\n", 19);
+       write(STDOUT_FILENO, "Signal: Segmentation fault\n", 27);
+
+       write(STDOUT_FILENO, "Code: ", 6);
+       write(STDOUT_FILENO,  (info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions", strlen((info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions"));
+       write(STDOUT_FILENO, "\n", 1);
+
+       write(STDOUT_FILENO, "Address: ", 9);
+
+       if (info->si_addr == 0)
+               {
+               write(STDOUT_FILENO, "0x0\n", 4);
+               }
+       else
+               {
+               /* Assume the address is 64-bit */
+               write(STDOUT_FILENO, "0x", 2);
+               addr = info->si_addr;
+
+               for (i = 0; i < 16; i++)
+                       {
+                       char_index = addr & 0xf000000000000000;
+                       char_index = char_index >> 60;
+                       addr = addr << 4;
+
+                       write(STDOUT_FILENO, &hex_char[char_index], 1);
+                       }
+               write(STDOUT_FILENO, "\n", 1);
+               }
+
+#ifdef HAVE_EXECINFO_H
+       bt_size = backtrace(bt, 1024);
+       backtrace_symbols_fd(bt, bt_size, STDOUT_FILENO);
+#endif
+
+       exit(EXIT_FAILURE);
+}
+#else /* defined(SA_SIGINFO) */
+void sigsegv_handler_cb(int UNUSED(signo))
+{
+#ifdef HAVE_EXECINFO_H
+       gint bt_size;
+       void *bt[1024];
+#endif
+
+       write(STDOUT_FILENO, "Geeqie fatal error\n", 19);
+       write(STDOUT_FILENO, "Signal: Segmentation fault\n", 27);
+
+#ifdef HAVE_EXECINFO_H
+       bt_size = backtrace(bt, 1024);
+       backtrace_symbols_fd(bt, bt_size, STDOUT_FILENO);
+#endif
+
+       exit(EXIT_FAILURE);
+}
+#endif /* defined(SA_SIGINFO) */
+
 /*
  *-----------------------------------------------------------------------------
  * keyboard functions
@@ -1048,6 +1138,16 @@ static void setup_sigbus_handler(void)
 #endif
 }
 
+static void setup_sigsegv_handler(void)
+{
+       struct sigaction sigsegv_action;
+       sigfillset(&sigsegv_action.sa_mask);
+       sigsegv_action.sa_sigaction = sigsegv_handler_cb;
+       sigsegv_action.sa_flags = SA_SIGINFO;
+
+       sigaction(SIGSEGV, &sigsegv_action, NULL);
+}
+
 static void set_theme_bg_color()
 {
        GdkRGBA bg_color;
@@ -1205,6 +1305,9 @@ gint main(gint argc, gchar *argv[])
        /* setup random seed for random slideshow */
        srand(time(NULL));
 
+       /* seg. fault handler */
+       setup_sigsegv_handler();
+
 #if 0
        /* See later comment; this handler leads to UB. */
        setup_sigbus_handler();