This is the mail archive of the mailing list for the elfutils project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] fixing addr2line inline info


I have a simple patch attached to improve the output addr2line -fi.  The
problem I had is it failed to identify the parent function name if there
was any lexical_block in the scope hierarchy.  For example, try the
following, compiled as the attached testfile-lex-inlines.bz2:

  1 // g++ x.cpp -g -fPIC -shared -O3 -fvisibility=hidden
  3 void foobar()
  4 {
  5   __asm__ ( "nop" ::: );
  6 }
  8 void foo()
  9 {
 10   {
 11     void (*bar) () = foobar;
 12     bar();
 13   }
 14 }

$ eu-addr2line -f -i -e testfile-lex-inlines.bz2 0x690
foobar inlined at /tmp/x.cpp:12 in _Z3foov

With my patch:

$ ./src/addr2line -fi -e testfile-lex-inlines.bz2 0x690
foobar inlined at /tmp/x.cpp:12 in _Z3foov

So the name is resolved, and I'm happier.  But, as I went to make this a
testcase, I noticed that the ":9" line isn't really correct for "foobar"
-- that's the start of "foo".

There are two candidate lines for 0x690:
 [    33] special opcode 246: address+16 = +0x690 <_Z3foov>, line+4 = 9
 [    34] special opcode 14: address+0 = +0x690 <_Z3foov>, line-4 = 5

So what happens AFAICT, the name is found with dwarf_getscopes(), which
will find the innermost address match.  The line is found with
dwfl_module_getsrc, which uses a binary search, making no guarantees if
there are multiple matches.  The bsearch happened to pick the first one
in this case.  Perhaps this should choose the last matching address to
be approximately innermost?

I also noticed that addr2line's print_dwarf_function() doesn't try to
read linkage_name, although that wouldn't matter for this foobar inline.
 It also looks like it's trying to walk up the inline / subprogram
stack, but since dwarf_getscopes chases the abstract_origin, it doesn't
have any of that.  So print_dwarf_function() returns false, and it falls
back to dwfl_module_addrname to get the outer name.

With dwarf_getscopes_die this would work, including multiple layers of
inlines, as it later does for -i.  But actually, I think having -i makes
this "inlined at ..." message redundant.  Binutils addr2line -fi doesn't
print anything like this.  Should we just kill that part?

Patch review and other thoughts appreciated...

diff --git a/src/addr2line.c b/src/addr2line.c
index 50fc2b38c367..eea39da97e2c 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -672,7 +672,22 @@ handle_address (const char *string, Dwfl *dwfl)
 		      if (show_functions)
-			print_diesym (&scopes[i + 1]);
+			{
+			  /* Search for the parent inline or function.  It
+			     might not be directly above this inline -- e.g.
+			     there could be a lexical_block in between.  */
+			  for (int j = i + 1; j < nscopes; j++)
+			    {
+			      Dwarf_Die *parent = &scopes[j];
+			      int tag = dwarf_tag (parent);
+			      if (tag == DW_TAG_inlined_subroutine
+				  || tag == DW_TAG_subprogram)
+				{
+				  print_diesym (parent);
+				  break;
+				}
+			    }
+			}
 		      src = NULL;
 		      lineno = 0;

Attachment: testfile-lex-inlines.bz2
Description: application/bzip

Attachment: readelf-w-testfile-lex-inlines.txt
Description: Text document

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]