[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