[PATCH 4/5] Support backtracing through elfutils (#70746)
Peter Hutterer
peter.hutterer at who-t.net
Wed Oct 30 00:25:11 CET 2013
>From Jan Kratochvil:
There is a longterm plan to obsolete libunwind from Fedora by new elfutils
unwinder. But xorg-x11-server does not even need any external (non-glibc)
unwinder.
According to e21e183059df5975e7086850d1931edb2c1bbd06 you do only
self-backtrace (called local unwinding by libunwind). glibc backtrace() can
do the same. According to the sample backtrace in the patch above the
backtrace addresses there are the same in before/after cases, libunwind only
adds resolving of address -> symbol name there, IIUC.
address -> symbol name resolving can be done with RH-supported elfutils
package.
X.Org Bug 70746 <http://bugs.freedesktop.org/show_bug.cgi?id=70746>
Cc: Marcin Slusarz <marcin.slusarz at gmail.com>
Cc: Jan Kratochvil <jan.kratochvil at redhat.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
This may need some extra linux checks...
configure.ac | 10 ++++--
include/dix-config.h.in | 3 ++
os/backtrace.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 99 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index d36aefc..0e589f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -308,6 +308,12 @@ AC_CHECK_HEADER([execinfo.h],[
])]
)
+dnl elfutils for backtrace symbol lookup
+AC_CHECK_HEADER([elfutils/libdwfl.h],
+ [AC_DEFINE(HAVE_ELFUTILS, 1, [Has elfutils])
+ ELFUTILS_LIBS="-ldw"])
+AC_SUBST(ELFUTILS_LIBS)
+
dnl ---------------------------------------------------------------------------
dnl Bus options and CPU capabilities. Replaces logic in
dnl hw/xfree86/os-support/bus/Makefile.am, among others.
@@ -1339,10 +1345,10 @@ AC_DEFINE(BIGREQS, 1, [Support BigRequests extension])
if test "x$SPECIAL_DTRACE_OBJECTS" = "xyes" ; then
DIX_LIB='$(top_builddir)/dix/dix.O'
- OS_LIB='$(top_builddir)/os/os.O $(SHA1_LIBS) $(DLOPEN_LIBS)'
+ OS_LIB='$(top_builddir)/os/os.O $(SHA1_LIBS) $(DLOPEN_LIBS) $(ELFUTILS_LIBS)'
else
DIX_LIB='$(top_builddir)/dix/libdix.la'
- OS_LIB='$(top_builddir)/os/libos.la'
+ OS_LIB='$(top_builddir)/os/libos.la $(ELFUTILS_LIBS)'
fi
AC_SUBST([DIX_LIB])
AC_SUBST([OS_LIB])
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index e1cb9eb..c7c0a8a 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -60,6 +60,9 @@
/* Has backtrace support */
#undef HAVE_BACKTRACE
+/* Has elfutils */
+#undef HAVE_ELFUTILS
+
/* Define to 1 if you have the <byteswap.h> header file. */
#undef HAVE_BYTESWAP_H
diff --git a/os/backtrace.c b/os/backtrace.c
index c807bd2..acf110a 100644
--- a/os/backtrace.c
+++ b/os/backtrace.c
@@ -37,6 +37,89 @@
#include <dlfcn.h>
#include <execinfo.h>
+#ifdef HAVE_ELFUTILS
+#include <unistd.h>
+#include <elfutils/libdwfl.h>
+
+static Dwfl*
+dwfl_get(void)
+{
+ static char *debuginfo_path;
+ static Dwfl *dwfl;
+
+ static const Dwfl_Callbacks proc_callbacks = {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+ .find_elf = dwfl_linux_proc_find_elf,
+ };
+
+ if (dwfl)
+ return dwfl;
+
+ dwfl = dwfl_begin(&proc_callbacks);
+ if (!dwfl)
+ return NULL;
+
+ errno = 0;
+ if (dwfl_linux_proc_report(dwfl, getpid ()) != 0 ||
+ dwfl_report_end(dwfl, NULL, NULL) != 0)
+ {
+ ErrorFSigSafe("dwfl reporting: %s\n", sterror(errno));
+ dwfl_end(dwfl);
+ dwfl = NULL;
+ abort();
+ }
+
+ return dwfl;
+}
+
+struct getmodules_callback_arg {
+ void *addr;
+ const char *name;
+};
+
+static int
+getmodules_callback(Dwfl_Module *module,
+ void **userdata,
+ const char *module_name,
+ Dwarf_Addr module_low_addr, void *arg)
+{
+ struct getmodules_callback_arg *cbarg = arg;
+ cbarg->name = dwfl_module_addrname(module, (GElf_Addr)cbarg->addr);
+ return cbarg->name ? DWARF_CB_ABORT : DWARF_CB_OK;
+}
+
+static const char*
+addr_lookup(void *addr)
+{
+ Dwfl *dwfl = dwfl_get();
+ struct getmodules_callback_arg arg;
+
+ arg.name = NULL;
+ arg.addr = addr;
+ dwfl_getmodules(dwfl, getmodules_callback, &arg, 0);
+ return arg.name;
+}
+#endif
+
+static const char*
+symbol_name(void *addr, void *fbase)
+{
+ const char *name = NULL;
+
+#ifdef HAVE_ELFUTILS
+ name = addr_lookup(addr);
+#endif
+
+ if (!name) {
+ static char buf[20];
+ sprintf(buf, "%p", fbase);
+ name = buf;
+ }
+
+ return name;
+}
+
void
xorg_backtrace(void)
{
@@ -66,15 +149,17 @@ xorg_backtrace(void)
(unsigned int)((char *) array[i] -
(char *) info.dli_saddr),
array[i]);
- else
+ else {
+ const char *name = symbol_name(array[i], info.dli_fbase);
ErrorFSigSafe(
- "%u: %s (%p+0x%x) [%p]\n",
+ "%u: %s (%s+0x%x) [%p]\n",
i,
mod,
- info.dli_fbase,
+ name,
(unsigned int)((char *) array[i] -
(char *) info.dli_fbase),
array[i]);
+ }
}
ErrorFSigSafe("\n");
}
--
1.8.3.1
More information about the xorg-devel
mailing list