Using dwfl to enumerate frames of current thread

Mark Wielaard mjw at redhat.com
Fri Aug 21 22:41:59 UTC 2015


On Fri, Aug 21, 2015 at 04:41:20PM +0200, Ben Gamari wrote:
> Mark Wielaard <mjw at redhat.com> writes:
> 
> > On Fri, Aug 21, 2015 at 09:35:14AM +0200, Ben Gamari wrote:
> >
> >> I have noticed that `/opt/exp/elfutils-root/bin/readelf -e
> >> ghc/stage2/build/Main.o --debug-dump=aranges` returns nothing for
> >> GHC-produced objects whereas it does not for objects produced by GCC.
> >
> > And this is the problem. Sorry. I should have realized earlier.
> > We use the .debug_aranges to get a quick index of the CUs and which
> > address ranges they cover. In the case that there is no .debug_aranges
> > we could do a full scan of all CUs. But that is somewhat inefficient,
> > since no .debug_aranges could also mean that there really are no
> > CUs with address scope DIEs (however that is probably unlikely). But
> > if there is a .debug_aranges then we do assume it is complete. I am
> > thinking whether we should still scan all CUs anyway if we are
> > looking for an address that is really inside a module. But I think
> > that would quickly become very inefficient.
> >
> Brilliant! I'll try implementing these.

That would be best I think.

Meanwhile, to show it should really work, the attached horrible hack
makes it work with the current setup (if all CUs do have the pc ranges
attached).

Maybe we can turn this horrible hack into something that is less horrible
to make eu-addr2line and friends work better with missing/partial
.debug_aranges. But then we should really properly cache the results/CUs
we scanned. And make sure that we don't unnecessary scan all CUs if
the .debug_aranges are complete (sadly we cannot really tell just from
the .debug_aranges section itself).

> I know this is probably a "patches accepted" sort of task, but it would
> be great if libdw documented precisely what it expects from user objects
> in order to behave as expected. Even better would be optional warnings
> when the library doesn't find a DWARF annotation that it expects. As
> someone relatively new to DWARF, it is rather difficult to get a
> high-level view of what the significant differences are.

Yeah. Unfortunately DWARF is not very strict. A lot is left as a "quality
of implementation" issue. In practice that means we assume that the
minimum quality is what GCC outputs. And it isn't till some other DWARF
producer comes around that we even realize that is what we assumed was
the "quality" we needed.

Cheers,

Mark
-------------- next part --------------
diff --git a/libdwfl/dwfl_module_getsrc.c b/libdwfl/dwfl_module_getsrc.c
index f7e340b..579abad 100644
--- a/libdwfl/dwfl_module_getsrc.c
+++ b/libdwfl/dwfl_module_getsrc.c
@@ -1,5 +1,5 @@
 /* Find source location for PC address in module.
-   Copyright (C) 2005, 2008, 2014 Red Hat, Inc.
+   Copyright (C) 2005, 2008, 2014, 2015 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -29,6 +29,19 @@
 #include "libdwflP.h"
 #include "../libdw/libdwP.h"
 
+static bool
+in_cu_range (Dwarf_Die *cudie, Dwarf_Addr addr)
+{
+  ptrdiff_t off = 0;
+  Dwarf_Addr base, begin, end;
+  while ((off = dwarf_ranges (cudie, off, &base, &begin, &end) > 0))
+    {
+      if (addr >= begin && addr < end)
+	return true;
+    }
+  return false;
+}
+
 Dwfl_Line *
 dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr)
 {
@@ -38,6 +51,26 @@ dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr)
 
   struct dwfl_cu *cu;
   Dwfl_Error error = __libdwfl_addrcu (mod, addr, &cu);
+  /* Horrible hack, if we do this then we should at least cache results.
+     There are two cases here, the aranges indicated no CU with the
+     requested address or the aranges do, but it isn't actually in the
+     actual CU because there was a gap that got optimized away for the
+     quick search and the real CU lies in that gap.  */
+  if ((error == DWFL_E_ADDR_OUTOFRANGE
+       || (error == DWFL_E_NOERROR
+	   && ! in_cu_range (&cu->die, addr)))
+      && addr >= mod->low_addr && addr < mod->high_addr)
+    {
+      /* Assume the user knows there is some CU that should cover
+	 this address, even though there is no aranges for it.  */
+      cu = NULL;
+      while ((error = __libdwfl_nextcu (mod, cu, &cu)) == DWFL_E_NOERROR
+	     && cu != NULL)
+	if (in_cu_range (&cu->die, addr))
+	  break;
+      if (error == DWFL_E_NOERROR && cu == NULL)
+	error = DWFL_E_ADDR_OUTOFRANGE;
+    }
   if (likely (error == DWFL_E_NOERROR))
     error = __libdwfl_cu_getsrclines (cu);
   if (likely (error == DWFL_E_NOERROR))


More information about the elfutils-devel mailing list