[PATCH 4/5] Support backtracing through elfutils (#70746)

Mark Wielaard mjw at redhat.com
Thu Oct 31 10:55:09 CET 2013

On Thu, 2013-10-31 at 14:00 +1000, Peter Hutterer wrote:
> On Wed, Oct 30, 2013 at 07:50:28PM +0100, Mark Wielaard wrote:
> > It also looks like this might be called from OsSigHandler to handle a
> > fatal signal. In that case you really should do the minimum possible and
> > get out quickly.
> > 
> > Do you really want to do anything more than direct (.dynsym) symbol
> > lookup? Looking up and loading separate .debug files or decompressing
> > a .gnu_debugdata section for example to get more interesting tables with
> > symbol names might not be the best thing to do from a signal handler
> > through any of the proposed libraries.
> tbh, the only thing I care about is good backtraces when the server crashes.
> how we get to that I don't care too much about. 
> and yes, xorg_backtrace() is almost always called from within the signal
> handler.

In that case, the process is crashing, possibly corrupted and inside a
signal handler, I am not sure you really want to do in-process
backtracing and symbol lookup. You might want to let the OS catch it (or
divert to gdb, abrt, dump core, etc.). IMHO getting the backtrace and
printing whatever you can through the standard glibc library might be
simplest and safest. Anything more might not be very safe at that point.

> The elfutils API isn't the
> prettiest atm but this is code that barely moves once written, so I'd be
> happy with it.

But if you really want to, then I think the elfutils API isn't that bad.
The setup might be a little verbose, but the rest seems as simple as
what you have now. It is just that you are using the callback interface
to iterate over all the modules, but you don't really need that. I would
do it something like the following:

#include <inttypes.h>
#include <stdio.h>
#include <elfutils/libdwfl.h>
#include <unistd.h>
#include <stdlib.h>
#include <execinfo.h>

/* Use the default debuginfo path. */
static char *dwfl_debuginfo_path = NULL;

/* Use default callbacks for creating a Dwfl for a process. */
static const Dwfl_Callbacks proc_callbacks =
  .find_debuginfo = dwfl_standard_find_debuginfo,
  .find_elf = dwfl_linux_proc_find_elf,
  .debuginfo_path = &dwfl_debuginfo_path

static void
dwfl_backtrace (void)
  /* Setup Dwfl for local process. */
  Dwfl *dwfl = dwfl_begin (&proc_callbacks);
  if (dwfl_linux_proc_report (dwfl, getpid ()) != 0)
      fprintf (stderr, "dwfl_linux_proc_report: %s\n", dwfl_errmsg (-1));
  dwfl_report_end (dwfl, NULL, NULL);

  /* Get local backtrace, using glibc. */
  void *array[64];
  int size = backtrace(array, 64);

  int i;
  for (i = 0; i < size; i++)
      GElf_Addr addr = (uintptr_t) array[i];
      Dwfl_Module *module = dwfl_addrmodule (dwfl, addr);
      if (module == NULL)
	  printf ("%u: ?? [%" PRIx64 "]\n", i, addr);

      const char *modname = dwfl_module_info (module, NULL, NULL, NULL,
					      NULL, NULL, NULL, NULL);
      GElf_Sym sym;
      GElf_Word shndx;
      const char *name = dwfl_module_addrsym (module, addr, &sym, &shndx);
      if (name == NULL)
        printf ("%u: ?? [%" PRIx64 " (%s)\n", i, addr, modname);
        printf ("%u: %s+%#" PRIx64 " (%s)\n", i, name, addr - sym.st_value,

      /* Lets throw in some source/line info if we can find it. */
      Dwfl_Line *line = dwfl_module_getsrc (module, addr);
      if (line != NULL)
	  int lineno;
	  const char *src = dwfl_lineinfo (line, NULL, &lineno, NULL,
					   NULL, NULL);
	  if (src != NULL)
	    printf ("\t%s:%d\n", src, lineno);
  dwfl_end (dwfl);

$ gcc -g -Wall -ldw -o dwfl_backtrace dwfl_backtrace.c -Wall -ldw
$ ./dwfl_backtrace 
0: dwfl_backtrace+0x87 (/tmp/dwfl_backtrace)
1: main+0x14 (/tmp/dwfl_backtrace)
2: __libc_start_main+0xf5 (/usr/lib64/libc-2.18.so)
3: _start+0x29 (/tmp/dwfl_backtrace)



More information about the xorg-devel mailing list