Commit 7cdd1ebe authored by Ell's avatar Ell

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.
parent 2c8e3f8e
......@@ -181,6 +181,7 @@ gimpconsoleldadd = \
$(Z_LIBS) \
$(JSON_C_LIBS) \
$(LIBMYPAINT_LIBS) \
$(LIBBACKTRACE_LIBS) \
$(LIBUNWIND_LIBS) \
$(INTLLIBS) \
$(RT_LIBS) \
......
......@@ -44,6 +44,10 @@
#include <string.h>
#include <stdio.h>
#ifdef HAVE_LIBBACKTRACE
#include <backtrace.h>
#endif
#ifdef HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
......@@ -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;
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';
}
info->object_name[0] = '\0';
info->symbol_name[0] = '\0';
info->symbol_address = 0;
info->source_file[0] = '\0';
info->source_line = 0;
if (dl_info.dli_sname)
if (dladdr ((gpointer) address, &dl_info))
{
g_strlcpy (info->symbol_name, dl_info.dli_sname,
sizeof (info->symbol_name));
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;
}
else
#ifdef HAVE_LIBBACKTRACE
if (backtrace_state)
{
info->symbol_name[0] = '\0';
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 */
info->symbol_address = (guintptr) dl_info.dli_saddr;
#endif
#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;
info->source_file[0] = '\0';
info->source_line = 0;
result = TRUE;
}
}
#endif /* HAVE_LIBUNWIND */
return TRUE;
return result;
}
......
......@@ -138,6 +138,7 @@ LDADD = \
$(Z_LIBS) \
$(JSON_C_LIBS) \
$(LIBMYPAINT_LIBS) \
$(LIBBACKTRACE_LIBS) \
$(LIBUNWIND_LIBS) \
$(INTLLIBS) \
$(RT_LIBS) \
......
......@@ -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 <stddef.h>
#include <backtrace.h>
#include <backtrace-supported.h>
#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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment