mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 02:00:33 +00:00
gst: Use libunwind/libdw to generate backtraces if avalaible
Making the gst_debug_print_trace function more generally useful. API: + gst_debug_get_trace https://bugzilla.gnome.org/show_bug.cgi?id=772555
This commit is contained in:
parent
050f486d10
commit
a8d4857555
9 changed files with 223 additions and 26 deletions
|
@ -438,3 +438,6 @@
|
|||
#mesondefine HAVE_DECL_STRSIGNAL
|
||||
#mesondefine HAVE_GETRUSAGE
|
||||
#mesondefine HAVE_SYS_RESOURCE_H
|
||||
#mesondefine HAVE_UNWIND
|
||||
#mesondefine HAVE_DW
|
||||
#mesondefine HAVE_BACKTRACE
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -828,6 +828,15 @@ AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes")
|
|||
|
||||
dnl libunwind is optionally used by the leaks tracer
|
||||
PKG_CHECK_MODULES(UNWIND, libunwind, HAVE_UNWIND=yes, HAVE_UNWIND=no)
|
||||
if test "x$HAVE_UNWIND" = "xyes"; then
|
||||
AC_DEFINE(HAVE_UNWIND, 1, [libunwind available])
|
||||
fi
|
||||
|
||||
dnl libdw is optionally used to add source lines and numbers to backtraces
|
||||
PKG_CHECK_MODULES(DW, libdw, HAVE_DW=yes, HAVE_DW=no)
|
||||
if test "x$HAVE_DW" = "xyes"; then
|
||||
AC_DEFINE(HAVE_DW, 1, [libdw available])
|
||||
fi
|
||||
|
||||
dnl Check for backtrace() from libc
|
||||
AC_CHECK_FUNC(backtrace, [
|
||||
|
@ -836,10 +845,6 @@ AC_CHECK_FUNC(backtrace, [
|
|||
], [], [])
|
||||
])
|
||||
|
||||
if test "x$HAVE_UNWIND" = "xyes"; then
|
||||
AC_DEFINE(HAVE_UNWIND, 1, [libunwind available])
|
||||
fi
|
||||
|
||||
dnl building of unit test libraries
|
||||
AC_ARG_ENABLE(check,
|
||||
AS_HELP_STRING([--disable-check],[disable building unit test libraries]),
|
||||
|
@ -1161,6 +1166,7 @@ Configuration
|
|||
Unit testing support : ${BUILD_CHECK}
|
||||
PTP clock support : ${HAVE_PTP}
|
||||
libunwind support : ${HAVE_UNWIND}
|
||||
libdw support : ${HAVE_DW}
|
||||
|
||||
Debug : ${USE_DEBUG}
|
||||
Profiling : ${USE_PROFILING}
|
||||
|
|
|
@ -1379,6 +1379,7 @@ GST_DEBUG_FUNCPTR_NAME
|
|||
GST_DEBUG_BIN_TO_DOT_FILE
|
||||
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
|
||||
gst_debug_print_stack_trace
|
||||
gst_debug_get_stack_trace
|
||||
GST_TIME_FORMAT
|
||||
GST_TIME_ARGS
|
||||
GST_STIME_FORMAT
|
||||
|
|
|
@ -141,6 +141,8 @@ libgstreamer_@GST_API_VERSION@_la_CFLAGS = \
|
|||
-DGST_API_VERSION=\""$(GST_API_VERSION)"\" \
|
||||
-DGST_DISABLE_DEPRECATED \
|
||||
$(VALGRIND_CFLAGS) \
|
||||
$(UNWIND_CFLAGS) \
|
||||
$(DW_CFLAGS) \
|
||||
$(GST_ALL_CFLAGS)
|
||||
|
||||
libgstreamer_@GST_API_VERSION@_la_LIBADD = \
|
||||
|
@ -149,6 +151,8 @@ libgstreamer_@GST_API_VERSION@_la_LIBADD = \
|
|||
$(GST_ALL_LIBS) \
|
||||
$(WIN32_LIBS) \
|
||||
$(SOCKET_LIBS) \
|
||||
$(UNWIND_LIBS) \
|
||||
$(DW_LIBS) \
|
||||
$(LIBM)
|
||||
|
||||
libgstreamer_@GST_API_VERSION@_la_LDFLAGS = \
|
||||
|
|
192
gst/gstinfo.c
192
gst/gstinfo.c
|
@ -90,7 +90,6 @@
|
|||
#undef gst_debug_add_log_function
|
||||
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
|
||||
#ifdef HAVE_DLFCN_H
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
@ -127,9 +126,34 @@
|
|||
|
||||
static char *gst_info_printf_pointer_extension_func (const char *format,
|
||||
void *ptr);
|
||||
#else /* GST_DISABLE_GST_DEBUG */
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
#endif /* !GST_DISABLE_GST_DEBUG */
|
||||
|
||||
#ifdef HAVE_UNWIND
|
||||
/* No need for remote debugging so turn on the 'local only' optimizations in
|
||||
* libunwind */
|
||||
#define UNW_LOCAL_ONLY
|
||||
|
||||
#include <libunwind.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_DW
|
||||
#include <elfutils/libdwfl.h>
|
||||
#endif /* HAVE_DW */
|
||||
#endif /* HAVE_UNWIND */
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#define BT_BUF_SIZE 100
|
||||
#endif /* HAVE_BACKTRACE */
|
||||
|
||||
extern gboolean gst_is_initialized (void);
|
||||
|
||||
/* we want these symbols exported even if debug is disabled, to maintain
|
||||
|
@ -2253,7 +2277,6 @@ _gst_debug_dump_mem (GstDebugCategory * cat, const gchar * file,
|
|||
* fallback function that cleans up the format string and replaces all pointer
|
||||
* extension formats with plain %p. */
|
||||
#ifdef GST_DISABLE_GST_DEBUG
|
||||
#include <glib/gprintf.h>
|
||||
int
|
||||
__gst_info_fallback_vasprintf (char **result, char const *format, va_list args)
|
||||
{
|
||||
|
@ -2412,15 +2435,16 @@ __cyg_profile_func_exit (void *this_fn, void *call_site)
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_debug_print_stack_trace:
|
||||
* gst_debug_get_stack_trace:
|
||||
*
|
||||
* If GST_ENABLE_FUNC_INSTRUMENTATION is defined a stacktrace is available for
|
||||
* gstreamer code, which can be printed with this function.
|
||||
* If GST_ENABLE_FUNC_INSTRUMENTATION is defined or libunwind or
|
||||
* glibc backtrace are present, a stack trace is return.
|
||||
*/
|
||||
void
|
||||
gst_debug_print_stack_trace (void)
|
||||
gchar *
|
||||
gst_debug_get_stack_trace (void)
|
||||
{
|
||||
GSList *walk = stack_trace;
|
||||
GString *trace = g_string_new (NULL);
|
||||
gint count = 0;
|
||||
|
||||
if (walk)
|
||||
|
@ -2429,16 +2453,162 @@ gst_debug_print_stack_trace (void)
|
|||
while (walk) {
|
||||
gchar *name = (gchar *) walk->data;
|
||||
|
||||
g_print ("#%-2d %s\n", count++, name);
|
||||
g_string_append (trace, "#%-2d %s\n", count++, name);
|
||||
|
||||
walk = g_slist_next (walk);
|
||||
}
|
||||
|
||||
return g_string_free (trace, FALSE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef HAVE_UNWIND
|
||||
#ifdef HAVE_DW
|
||||
static gboolean
|
||||
append_debug_info (GString * trace, const void *ip)
|
||||
{
|
||||
Dwfl *dwfl;
|
||||
Dwfl_Line *line;
|
||||
Dwarf_Addr addr;
|
||||
Dwfl_Module *module;
|
||||
const gchar *function_name;
|
||||
gchar *debuginfo_path = NULL;
|
||||
Dwfl_Callbacks callbacks = {
|
||||
.find_elf = dwfl_linux_proc_find_elf,
|
||||
.find_debuginfo = dwfl_standard_find_debuginfo,
|
||||
.debuginfo_path = &debuginfo_path,
|
||||
};
|
||||
|
||||
dwfl = dwfl_begin (&callbacks);
|
||||
if (!dwfl)
|
||||
return FALSE;
|
||||
|
||||
if (dwfl_linux_proc_report (dwfl, getpid ()) != 0)
|
||||
return FALSE;
|
||||
|
||||
if (dwfl_report_end (dwfl, NULL, NULL))
|
||||
return FALSE;
|
||||
|
||||
addr = (uintptr_t) ip;
|
||||
module = dwfl_addrmodule (dwfl, addr);
|
||||
function_name = dwfl_module_addrname (module, addr);
|
||||
|
||||
g_string_append_printf (trace, "%s(", function_name ? function_name : "??");
|
||||
|
||||
line = dwfl_getsrc (dwfl, addr);
|
||||
if (line != NULL) {
|
||||
gint nline;
|
||||
Dwarf_Addr addr;
|
||||
const gchar *filename = dwfl_lineinfo (line, &addr,
|
||||
&nline, NULL, NULL, NULL);
|
||||
|
||||
g_string_append_printf (trace, "%s:%d", strrchr (filename,
|
||||
G_DIR_SEPARATOR) + 1, nline);
|
||||
} else {
|
||||
const gchar *eflfile = NULL;
|
||||
|
||||
dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, &eflfile, NULL);
|
||||
g_string_append_printf (trace, "%s:%p", eflfile ? eflfile : "??", ip);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* HAVE_DW */
|
||||
|
||||
static gchar *
|
||||
generate_unwind_trace (void)
|
||||
{
|
||||
unw_context_t uc;
|
||||
unw_cursor_t cursor;
|
||||
gboolean use_libunwind = TRUE;
|
||||
GString *trace = g_string_new (NULL);
|
||||
|
||||
unw_getcontext (&uc);
|
||||
unw_init_local (&cursor, &uc);
|
||||
|
||||
while (unw_step (&cursor) > 0) {
|
||||
#ifdef HAVE_DW
|
||||
unw_word_t ip;
|
||||
|
||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||
if (append_debug_info (trace, (void *) (ip - 4))) {
|
||||
use_libunwind = FALSE;
|
||||
g_string_append (trace, ")\n");
|
||||
}
|
||||
#endif /* HAVE_DW */
|
||||
|
||||
if (use_libunwind) {
|
||||
char name[32];
|
||||
|
||||
unw_word_t offset = 0;
|
||||
unw_get_proc_name (&cursor, name, sizeof (name), &offset);
|
||||
g_string_append_printf (trace, "%s (0x%" G_GSIZE_FORMAT ")\n", name,
|
||||
(gsize) offset);
|
||||
}
|
||||
}
|
||||
|
||||
return g_string_free (trace, FALSE);
|
||||
}
|
||||
|
||||
#endif /* HAVE_UNWIND */
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
static gchar *
|
||||
generate_backtrace_trace (void)
|
||||
{
|
||||
int j, nptrs;
|
||||
void *buffer[BT_BUF_SIZE];
|
||||
char **strings;
|
||||
GString *trace;
|
||||
|
||||
trace = g_string_new (NULL);
|
||||
nptrs = backtrace (buffer, BT_BUF_SIZE);
|
||||
|
||||
strings = backtrace_symbols (buffer, nptrs);
|
||||
|
||||
if (!strings)
|
||||
return NULL;
|
||||
|
||||
for (j = 0; j < nptrs; j++)
|
||||
g_string_append_printf (trace, "%s\n", strings[j]);
|
||||
|
||||
return g_string_free (trace, FALSE);
|
||||
}
|
||||
#endif /* HAVE_BACKTRACE */
|
||||
|
||||
gchar *
|
||||
gst_debug_get_stack_trace (void)
|
||||
{
|
||||
gchar *trace = NULL;
|
||||
|
||||
#ifdef HAVE_UNWIND
|
||||
trace = generate_unwind_trace ();
|
||||
if (trace)
|
||||
return trace;
|
||||
#endif /* HAVE_UNWIND */
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
trace = generate_backtrace_trace ();
|
||||
#endif /* HAVE_BACKTRACE */
|
||||
|
||||
return trace;
|
||||
}
|
||||
#endif /* GST_ENABLE_FUNC_INSTRUMENTATION */
|
||||
|
||||
/**
|
||||
* gst_debug_print_stack_trace:
|
||||
*
|
||||
* If GST_ENABLE_FUNC_INSTRUMENTATION is defined or libunwind or
|
||||
* glibc backtrace are present, a stack trace is printed.
|
||||
*/
|
||||
void
|
||||
gst_debug_print_stack_trace (void)
|
||||
{
|
||||
/* nothing because it's compiled out */
|
||||
}
|
||||
gchar *trace = gst_debug_get_stack_trace ();
|
||||
|
||||
#endif /* GST_ENABLE_FUNC_INSTRUMENTATION */
|
||||
if (trace)
|
||||
g_print ("%s\n", trace);
|
||||
|
||||
g_free (trace);
|
||||
}
|
||||
|
|
|
@ -1564,6 +1564,7 @@ GST_TRACE (const char *format, ...)
|
|||
|
||||
|
||||
void gst_debug_print_stack_trace (void);
|
||||
gchar * gst_debug_get_stack_trace (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ if libtype != 'shared'
|
|||
include_directories('parse')],
|
||||
install : true,
|
||||
link_with : printf_lib,
|
||||
dependencies : [gobject_dep, gmodule_dep, glib_dep, mathlib] + platform_deps,
|
||||
dependencies : [gobject_dep, gmodule_dep, glib_dep, mathlib, unwind_dep, dw_dep] + platform_deps,
|
||||
)
|
||||
libgst = libgst_static
|
||||
endif
|
||||
|
@ -221,7 +221,7 @@ if libtype != 'static'
|
|||
include_directories('parse')],
|
||||
link_with : printf_lib,
|
||||
install : true,
|
||||
dependencies : [gobject_dep, gmodule_dep, glib_dep, mathlib] + platform_deps,
|
||||
dependencies : [gobject_dep, gmodule_dep, glib_dep, mathlib, unwind_dep, dw_dep] + platform_deps,
|
||||
vs_module_defs: vs_module_defs_dir + 'libgstreamer.def',
|
||||
)
|
||||
libgst = libgst_shared
|
||||
|
|
21
meson.build
21
meson.build
|
@ -260,6 +260,27 @@ if cc.has_function('strsignal', prefix : '#include <string.h>')
|
|||
cdata.set('HAVE_DECL_STRSIGNAL', 1)
|
||||
endif
|
||||
|
||||
unwind_dep = dependency('libunwind', required : false)
|
||||
dw_dep = dependency('libdw', required: false)
|
||||
if unwind_dep.found()
|
||||
cdata.set('HAVE_UNWIND', 1)
|
||||
if dw_dep.found()
|
||||
cdata.set('HAVE_DW', 1)
|
||||
else
|
||||
message('Support for backtraces is partial only.')
|
||||
endif
|
||||
else
|
||||
if cc.has_function('backtrace')
|
||||
cdata.set('HAVE_BACKTRACE', 1)
|
||||
else
|
||||
message('NO backtraces support.')
|
||||
endif
|
||||
endif
|
||||
|
||||
if cc.has_header('execinfo.h') and cc.has_function('backtrace', prefix : '#include <execinfo.h>')
|
||||
cdata.set('HAVE_BACKTRACE', 1)
|
||||
endif
|
||||
|
||||
configure_file(input : 'config.h.meson',
|
||||
output : 'config.h',
|
||||
configuration : cdata)
|
||||
|
|
|
@ -12,15 +12,6 @@ endif
|
|||
|
||||
tracers_args = gst_c_args + ['-DGST_USE_UNSTABLE_API']
|
||||
|
||||
unwind_dep = dependency('libunwind', required : false)
|
||||
if unwind_dep.found()
|
||||
tracers_args += ['-DHAVE_UNWIND']
|
||||
endif
|
||||
|
||||
if cc.has_header('execinfo.h') and cc.has_function('backtrace', prefix : '#include <execinfo.h>')
|
||||
tracers_args += ['-DHAVE_BACKTRACE']
|
||||
endif
|
||||
|
||||
gst_tracers = library('gstcoretracers',
|
||||
gst_tracers_sources,
|
||||
c_args : tracers_args,
|
||||
|
|
Loading…
Reference in a new issue