From 7cdd1ebeefcbc9e7f48fa4bdeee7ce9c2a7cb436 Mon Sep 17 00:00:00 2001 From: Ell Date: Sat, 22 Sep 2018 22:33:44 -0400 Subject: [PATCH] app: add source location information to the Linux GimpBacktrace backend When libbacktrace is available, use it to retrieve source location information in the Linux GimpBacktrace backend. --- app/Makefile.am | 1 + app/core/gimpbacktrace-linux.c | 165 +++++++++++++++++++++------------ app/tests/Makefile.am | 1 + configure.ac | 43 ++++++++- 4 files changed, 152 insertions(+), 58 deletions(-) diff --git a/app/Makefile.am b/app/Makefile.am index 114a809caf..fda2e5fafb 100644 --- a/app/Makefile.am +++ b/app/Makefile.am @@ -181,6 +181,7 @@ gimpconsoleldadd = \ $(Z_LIBS) \ $(JSON_C_LIBS) \ $(LIBMYPAINT_LIBS) \ + $(LIBBACKTRACE_LIBS) \ $(LIBUNWIND_LIBS) \ $(INTLLIBS) \ $(RT_LIBS) \ diff --git a/app/core/gimpbacktrace-linux.c b/app/core/gimpbacktrace-linux.c index 477aa0a096..cef207a43a 100644 --- a/app/core/gimpbacktrace-linux.c +++ b/app/core/gimpbacktrace-linux.c @@ -44,6 +44,10 @@ #include #include +#ifdef HAVE_LIBBACKTRACE +#include +#endif + #ifdef HAVE_LIBUNWIND #define UNW_LOCAL_ONLY #include @@ -110,6 +114,10 @@ static pid_t blacklisted_threads[MAX_N_THREADS]; static gint n_blacklisted_threads; static GimpBacktrace *handler_backtrace; +#ifdef HAVE_LIBBACKTRACE +static struct backtrace_state *backtrace_state; +#endif + static const gchar *blacklisted_thread_names[] = { "gmain" @@ -271,6 +279,9 @@ gimp_backtrace_signal_handler (gint signum) void gimp_backtrace_init (void) { +#ifdef HAVE_LIBBACKTRACE + backtrace_state = backtrace_create_state (NULL, 0, NULL, NULL); +#endif } gboolean @@ -565,75 +576,115 @@ gimp_backtrace_get_frame_address (GimpBacktrace *backtrace, return backtrace->threads[thread].frames[frame]; } +#ifdef HAVE_LIBBACKTRACE +static void +gimp_backtrace_syminfo_callback (GimpBacktraceAddressInfo *info, + guintptr pc, + const gchar *symname, + guintptr symval, + guintptr symsize) +{ + if (symname) + g_strlcpy (info->symbol_name, symname, sizeof (info->symbol_name)); + + info->symbol_address = symval; +} + +static gint +gimp_backtrace_pcinfo_callback (GimpBacktraceAddressInfo *info, + guintptr pc, + const gchar *filename, + gint lineno, + const gchar *function) +{ + if (function) + g_strlcpy (info->symbol_name, function, sizeof (info->symbol_name)); + + if (filename) + g_strlcpy (info->source_file, filename, sizeof (info->source_file)); + + info->source_line = lineno; + + return 0; +} +#endif /* HAVE_LIBBACKTRACE */ + gboolean gimp_backtrace_get_address_info (guintptr address, GimpBacktraceAddressInfo *info) { - Dl_info dl_info; + Dl_info dl_info; + gboolean result = FALSE; g_return_val_if_fail (info != NULL, FALSE); -#ifdef HAVE_LIBUNWIND - { - unw_context_t context = {}; - unw_cursor_t cursor; - unw_word_t offset; + info->object_name[0] = '\0'; - if (dladdr ((gpointer) address, &dl_info) && dl_info.dli_fname) - { - g_strlcpy (info->object_name, dl_info.dli_fname, - sizeof (info->object_name)); - } - else - { - info->object_name[0] = '\0'; - } - - if (unw_init_local (&cursor, &context) == 0 && - unw_set_reg (&cursor, UNW_REG_IP, address) == 0 && - unw_get_proc_name (&cursor, - info->symbol_name, sizeof (info->symbol_name), - &offset) == 0) - { - info->symbol_address = address - offset; - } - else - { - info->symbol_name[0] = '\0'; - info->symbol_address = 0; - } - } -#else - if (! dladdr ((gpointer) address, &dl_info)) - return FALSE; - - if (dl_info.dli_fname) - { - g_strlcpy (info->object_name, dl_info.dli_fname, - sizeof (info->object_name)); - } - else - { - info->object_name[0] = '\0'; - } - - if (dl_info.dli_sname) - { - g_strlcpy (info->symbol_name, dl_info.dli_sname, - sizeof (info->symbol_name)); - } - else - { - info->symbol_name[0] = '\0'; - } - - info->symbol_address = (guintptr) dl_info.dli_saddr; -#endif + info->symbol_name[0] = '\0'; + info->symbol_address = 0; info->source_file[0] = '\0'; info->source_line = 0; - return TRUE; + if (dladdr ((gpointer) address, &dl_info)) + { + if (dl_info.dli_fname) + { + g_strlcpy (info->object_name, dl_info.dli_fname, + sizeof (info->object_name)); + } + + if (dl_info.dli_sname) + { + g_strlcpy (info->symbol_name, dl_info.dli_sname, + sizeof (info->symbol_name)); + } + + info->symbol_address = (guintptr) dl_info.dli_saddr; + + result = TRUE; + } + +#ifdef HAVE_LIBBACKTRACE + if (backtrace_state) + { + backtrace_syminfo ( + backtrace_state, address, + (backtrace_syminfo_callback) gimp_backtrace_syminfo_callback, + NULL, + info); + + backtrace_pcinfo ( + backtrace_state, address, + (backtrace_full_callback) gimp_backtrace_pcinfo_callback, + NULL, + info); + + result = TRUE; + } +#endif /* HAVE_LIBBACKTRACE */ + +#ifdef HAVE_LIBUNWIND + if (! info->symbol_name[0]) + { + unw_context_t context = {}; + unw_cursor_t cursor; + unw_word_t offset; + + if (unw_init_local (&cursor, &context) == 0 && + unw_set_reg (&cursor, UNW_REG_IP, address) == 0 && + unw_get_proc_name (&cursor, + info->symbol_name, sizeof (info->symbol_name), + &offset) == 0) + { + info->symbol_address = address - offset; + + result = TRUE; + } + } +#endif /* HAVE_LIBUNWIND */ + + return result; } diff --git a/app/tests/Makefile.am b/app/tests/Makefile.am index 55dd04c2c7..3b6076f7c4 100644 --- a/app/tests/Makefile.am +++ b/app/tests/Makefile.am @@ -138,6 +138,7 @@ LDADD = \ $(Z_LIBS) \ $(JSON_C_LIBS) \ $(LIBMYPAINT_LIBS) \ + $(LIBBACKTRACE_LIBS) \ $(LIBUNWIND_LIBS) \ $(INTLLIBS) \ $(RT_LIBS) \ diff --git a/configure.ac b/configure.ac index ed6cd74652..6cff17fa28 100644 --- a/configure.ac +++ b/configure.ac @@ -1791,6 +1791,43 @@ AC_SUBST(FILE_HEIF) AM_CONDITIONAL(HAVE_LIBHEIF, test "x$have_libheif" = xyes) +######################## +# Check for libbacktrace +######################## + +AC_ARG_WITH(libbacktrace, [ --without-libbacktrace build without libbacktrace support]) + +have_libbacktrace=no +if test "x$with_libbacktrace" != xno; then + gimp_save_LIBS=$LIBS + LIBS="$LIBS -lbacktrace" + + AC_MSG_CHECKING([for LIBBACKTRACE]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #include + #include + + #if ! BACKTRACE_SUPPORTED + #error ! BACKTRACE_SUPPORTED + #endif + ]], + [[(void) backtrace_create_state (NULL, 0, NULL, NULL);]])], + [AC_MSG_RESULT([yes]); LIBBACKTRACE_LIBS='-lbacktrace'], + [AC_MSG_RESULT([no]); have_libbacktrace='no (libbacktrace is not found or not supported)']) + + LIBS=$gimp_save_LIBS + + AC_SUBST(LIBBACKTRACE_LIBS) +fi + +if test "x$have_libbacktrace" = xyes; then + AC_DEFINE(HAVE_LIBBACKTRACE, 1, + [Define to 1 if libbacktrace is available]) +fi + + ##################### # Check for libunwind ##################### @@ -1817,7 +1854,11 @@ fi detailed_backtraces=no if test "x$platform_linux" = xyes; then - detailed_backtraces=$have_libunwind + if test "x$have_libbacktrace" = xyes -o "x$have_libunwind" = xyes; then + detailed_backtraces=yes + else + detailed_backtraces='no (libbacktrace and libunwind are not found or not supported)' + fi elif test "x$platform_win32" = xyes; then detailed_backtraces=$enable_drmingw fi