public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2014-12-24 12:27 Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2014-12-24 12:27 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 9577 bytes --]

In commit 7d9b5a dwfl_module_getsrc was changed so that it returns the last
line record <= addr, rather than returning immediately on a match. This
changes dwarf_getsrc_die to do the same. And it adds a new test that checks
this by comparing against the same results from eu-addr2line (which uses
dwfl_module_getsrc) using dwarf_addrdie and dwarf_getsrc_die instead.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libdw/ChangeLog          |  6 ++++
 libdw/dwarf_getsrc_die.c | 33 +++++++++-------------
 tests/Makefile.am        | 10 +++++--
 tests/getsrc_die.c       | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 tests/run-getsrc-die.sh  | 51 ++++++++++++++++++++++++++++++++++
 5 files changed, 149 insertions(+), 23 deletions(-)
 create mode 100644 tests/getsrc_die.c
 create mode 100755 tests/run-getsrc-die.sh

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index abc2d71..bf64c2e 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2014-12-24  Mark Wielaard  <mjw@redhat.com>
+
+	* dwarf_getsrc_die.c (dwarf_getsrc_die): Return the last line record
+	smaller than or equal to addr, rather than returning immediately on
+	a match.
+
 2014-12-18  Ulrich Drepper  <drepper@gmail.com>
 
 	* Makefile.am: Suppress output of textrel_check command.
diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c
index 1914cdf..fe06ca4 100644
--- a/libdw/dwarf_getsrc_die.c
+++ b/libdw/dwarf_getsrc_die.c
@@ -1,5 +1,5 @@
 /* Find line information for address.
-   Copyright (C) 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2004, 2005, 2014 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2004.
 
@@ -45,33 +45,26 @@ dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr)
     return NULL;
 
   /* The lines are sorted by address, so we can use binary search.  */
-  size_t l = 0, u = nlines;
+  size_t l = 0, u = nlines - 1;
   while (l < u)
     {
-      size_t idx = (l + u) / 2;
-      if (addr < lines->info[idx].addr)
-	u = idx;
-      else if (addr > lines->info[idx].addr || lines->info[idx].end_sequence)
-	l = idx + 1;
+      size_t idx = u - (u -l) / 2;
+      Dwarf_Line *line = &lines->info[idx];
+      if (addr < line->addr)
+	u = idx - 1;
       else
-	return &lines->info[idx];
+	l = idx;
     }
 
+  /* This is guaranteed for us by libdw read_srclines.  */
   if (nlines > 0)
     assert (lines->info[nlines - 1].end_sequence);
 
-  /* If none were equal, the closest one below is what we want.  We
-     never want the last one, because it's the end-sequence marker
-     with an address at the high bound of the CU's code.  If the debug
-     information is faulty and no end-sequence marker is present, we
-     still ignore it.  */
-  if (u > 0 && u < nlines && addr > lines->info[u - 1].addr)
-    {
-      while (lines->info[u - 1].end_sequence && u > 0)
-	--u;
-      if (u > 0)
-	return &lines->info[u - 1];
-    }
+  /* The last line which is less than or equal to addr is what we want,
+     except with an end_sequence which can only be strictly equal.  */
+  Dwarf_Line *line = &lines->info[l];
+  if (line->addr == addr || (! line->end_sequence && line->addr < addr))
+    return &lines->info[l];
 
   __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE);
   return NULL;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 303f783..c364cc9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,7 +50,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
 		  dwfl-report-elf-align varlocs backtrace backtrace-child \
 		  backtrace-data backtrace-dwarf debuglink debugaltlink \
-		  buildid deleted deleted-lib.so aggregate_size vdsosyms
+		  buildid deleted deleted-lib.so aggregate_size vdsosyms \
+		  getsrc_die
 
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
 	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -111,7 +112,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
 	run-backtrace-core-aarch64.sh \
 	run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \
 	run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \
-	run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh
+	run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh \
+	run-getsrc-die.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -280,7 +282,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     linkmap-cut.bz2 linkmap-cut.core.bz2 \
 	     run-aggregate-size.sh testfile-sizes1.o.bz2 testfile-sizes2.o.bz2 \
 	     testfile-sizes3.o.bz2 \
-	     run-readelf-A.sh testfileppc32attrs.o.bz2
+	     run-readelf-A.sh testfileppc32attrs.o.bz2 \
+	     run-getsrc-die.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
@@ -420,6 +423,7 @@ deleted_lib_so_LDFLAGS = -shared -rdynamic
 deleted_lib_so_CFLAGS = -fPIC -fasynchronous-unwind-tables
 aggregate_size_LDADD = $(libdw) $(libelf)
 vdsosyms_LDADD = $(libdw) $(libelf)
+getsrc_die_LDADD = $(libdw) $(libelf)
 
 if GCOV
 check: check-am coverage
diff --git a/tests/getsrc_die.c b/tests/getsrc_die.c
new file mode 100644
index 0000000..055aede
--- /dev/null
+++ b/tests/getsrc_die.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libelf.h>
+#include ELFUTILS_HEADER(dw)
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int
+main (int argc, char *argv[])
+{
+  /* file addr+ */
+  int fd = open (argv[1], O_RDONLY);
+  Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
+  if  (dbg == NULL)
+    error (-1, 0, "dwarf_begin (%s): %s\n", argv[1], dwarf_errmsg (-1));
+
+  for (int i = 2; i < argc; i++)
+    {
+      Dwarf_Addr addr;
+      char *endptr;
+      Dwarf_Die cudie;
+      Dwarf_Line *line;
+
+      errno = 0;
+      addr = strtoull (argv[i], &endptr, 16);
+      if (errno != 0)
+	error (-1, errno, "Cannot parrse '%s'", argv[1]);
+
+      if (dwarf_addrdie (dbg, addr, &cudie) == NULL)
+	error (-1, 0, "dwarf_addrdie (%s): %s", argv[i], dwarf_errmsg (-1));
+
+      line = dwarf_getsrc_die (&cudie, addr);
+      if (line == NULL)
+	error (-1, 0, "dwarf_getsrc_die (%s): %s", argv[i], dwarf_errmsg (-1));
+
+      const char *f = dwarf_linesrc (line, NULL, NULL);
+      int l;
+      if (dwarf_lineno (line, &l) != 0)
+	l = 0;
+
+      printf ("%s:%d\n", f ?: "???", l);
+    }
+
+  dwarf_end (dbg);
+  close (fd);
+
+  return 0;
+}
diff --git a/tests/run-getsrc-die.sh b/tests/run-getsrc-die.sh
new file mode 100755
index 0000000..4da16e7
--- /dev/null
+++ b/tests/run-getsrc-die.sh
@@ -0,0 +1,51 @@
+#! /bin/sh
+# Copyright (C) 2014 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# See run-addr2line-test.sh run-addr2line-i-test.sh run-addr2line-i-lex-test.sh
+# Output/files/lines matched should equal what is done through addr2line
+# which uses dwfl_module_getsrc. This test uses dwarf_addrdie and
+# dwarf_getsrc_die
+testfiles testfile testfile-inlines testfile-lex-inlines
+
+testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile 0x08048468 0x0804845c <<\EOF
+/home/drepper/gnu/new-bu/build/ttt/f.c:3
+/home/drepper/gnu/new-bu/build/ttt/b.c:4
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile-inlines 0x00000000000005a0 0x00000000000005a1 0x00000000000005b0 0x00000000000005b1 0x00000000000005c0 0x00000000000005d0 0x00000000000005e0 0x00000000000005e1 0x00000000000005f1 0x00000000000005f2 <<\EOF
+/tmp/x.cpp:5
+/tmp/x.cpp:6
+/tmp/x.cpp:10
+/tmp/x.cpp:11
+/tmp/x.cpp:5
+/tmp/x.cpp:10
+/tmp/x.cpp:5
+/tmp/x.cpp:10
+/tmp/x.cpp:10
+/tmp/x.cpp:5
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile-lex-inlines 0x0000000000000680 0x0000000000000681 0x0000000000000690 0x0000000000000691 <<\EOF
+/tmp/x.cpp:5
+/tmp/x.cpp:5
+/tmp/x.cpp:5
+/tmp/x.cpp:5
+EOF
+
+exit 0
-- 
2.1.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2015-01-16  8:09 Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2015-01-16  8:09 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 1011 bytes --]

On Thu, 2015-01-15 at 11:54 -0800, Josh Stone wrote:
> On 01/12/2015 01:25 PM, Mark Wielaard wrote:
> > On Sat, 2014-12-27 at 16:49 +0100, Mark Wielaard wrote:
> >> I think you are right and those tests, addrscopes and funcscopes, are
> >> wrong. They use dwfl_module_getsrc to find the line associated with start
> >> and end of the scope. But for the end they use the value of the high_pc
> >> attribute. The high_pc attributes indicates the first address beyond
> >> the current scope of the associated DIE. So the tests should use
> >> highpc - 1 as end of scope.
> >>
> >> I created a patch to change dwfl_module_getsrc to not match against
> >> a line with end_sequence set, changed the tests to use highpc -1.
> >> And adjusted this patch for dwarf_getsrc_die. to match the new
> >> behavior. Do those changes look correct to you?
> > 
> > Those are the following 2 commits on the mjw/pending branch:
> 
> Both look good to me.

Thanks for looking over them. I pushed both to master.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2015-01-15 19:54 Josh Stone
  0 siblings, 0 replies; 6+ messages in thread
From: Josh Stone @ 2015-01-15 19:54 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2401 bytes --]

On 01/12/2015 01:25 PM, Mark Wielaard wrote:
> On Sat, 2014-12-27 at 16:49 +0100, Mark Wielaard wrote:
>> I think you are right and those tests, addrscopes and funcscopes, are
>> wrong. They use dwfl_module_getsrc to find the line associated with start
>> and end of the scope. But for the end they use the value of the high_pc
>> attribute. The high_pc attributes indicates the first address beyond
>> the current scope of the associated DIE. So the tests should use
>> highpc - 1 as end of scope.
>>
>> I created a patch to change dwfl_module_getsrc to not match against
>> a line with end_sequence set, changed the tests to use highpc -1.
>> And adjusted this patch for dwarf_getsrc_die. to match the new
>> behavior. Do those changes look correct to you?
> 
> Those are the following 2 commits on the mjw/pending branch:

Both look good to me.

> commit f5ea852c13d94fc04cdbd1d49c9185246d78fc62
> Author: Mark Wielaard <mjw@redhat.com>
> Date:   Wed Dec 24 13:17:23 2014 +0100
> 
>     libdw: Search for the last matching address with dwarf_getsrc_die.
>     
>     In commit 7d9b5a dwfl_module_getsrc was changed so that it returns the last
>     line record <= addr, rather than returning immediately on a match. This
>     changes dwarf_getsrc_die to do the same. And it adds a new test that checks
>     this by comparing against the same results from eu-addr2line (which uses
>     dwfl_module_getsrc) using dwarf_addrdie and dwarf_getsrc_die instead.
>     
>     Signed-off-by: Mark Wielaard <mjw@redhat.com>
> 
> commit bc000d1b457dfec65c20d43abd0dcc634f2e43cb
> Author: Mark Wielaard <mjw@redhat.com>
> Date:   Sat Dec 27 16:16:29 2014 +0100
> 
>     libdwfl: dwfl_module_getsrc should never match end_sequence line.
>     
>     The line with end_sequence set has an address outside the current line
>     sequence. An end_sequence line has no other useful information except
>     marking the address as out of range.
>     
>     Two tests, addrscopes and funcscopes, depended on matching the end_sequence
>     line. But that was because they included the high_pc address in the scope.
>     However the high_pc attributes has as address the first location past the
>     range associated with a given DIE. Adjust the tests to use high_pc - 1 as
>     end of the scope.
>     
>     Signed-off-by: Mark Wielaard <mjw@redhat.com>
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2015-01-12 21:25 Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2015-01-12 21:25 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2248 bytes --]

On Sat, 2014-12-27 at 16:49 +0100, Mark Wielaard wrote:
> I think you are right and those tests, addrscopes and funcscopes, are
> wrong. They use dwfl_module_getsrc to find the line associated with start
> and end of the scope. But for the end they use the value of the high_pc
> attribute. The high_pc attributes indicates the first address beyond
> the current scope of the associated DIE. So the tests should use
> highpc - 1 as end of scope.
> 
> I created a patch to change dwfl_module_getsrc to not match against
> a line with end_sequence set, changed the tests to use highpc -1.
> And adjusted this patch for dwarf_getsrc_die. to match the new
> behavior. Do those changes look correct to you?

Those are the following 2 commits on the mjw/pending branch:

commit f5ea852c13d94fc04cdbd1d49c9185246d78fc62
Author: Mark Wielaard <mjw@redhat.com>
Date:   Wed Dec 24 13:17:23 2014 +0100

    libdw: Search for the last matching address with dwarf_getsrc_die.
    
    In commit 7d9b5a dwfl_module_getsrc was changed so that it returns the last
    line record <= addr, rather than returning immediately on a match. This
    changes dwarf_getsrc_die to do the same. And it adds a new test that checks
    this by comparing against the same results from eu-addr2line (which uses
    dwfl_module_getsrc) using dwarf_addrdie and dwarf_getsrc_die instead.
    
    Signed-off-by: Mark Wielaard <mjw@redhat.com>

commit bc000d1b457dfec65c20d43abd0dcc634f2e43cb
Author: Mark Wielaard <mjw@redhat.com>
Date:   Sat Dec 27 16:16:29 2014 +0100

    libdwfl: dwfl_module_getsrc should never match end_sequence line.
    
    The line with end_sequence set has an address outside the current line
    sequence. An end_sequence line has no other useful information except
    marking the address as out of range.
    
    Two tests, addrscopes and funcscopes, depended on matching the end_sequence
    line. But that was because they included the high_pc address in the scope.
    However the high_pc attributes has as address the first location past the
    range associated with a given DIE. Adjust the tests to use high_pc - 1 as
    end of the scope.
    
    Signed-off-by: Mark Wielaard <mjw@redhat.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2014-12-27 15:49 Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2014-12-27 15:49 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 2074 bytes --]

On Fri, Dec 26, 2014 at 02:12:14PM -0700, Josh Stone wrote:
> >    /* The lines are sorted by address, so we can use binary search.  */
> > -  size_t l = 0, u = nlines;
> > +  size_t l = 0, u = nlines - 1;
> >    while (l < u)
> 
> What if nlines == 0?

I wanted to say that cannot happen. If nlines == 0 then cu->lines would
be NULL. But looking at the code there is a theoretical possibility
that isn't the case. It seems unlikely to happen in practice, but we
should guard against it indeed.

> > +      size_t idx = u - (u -l) / 2;
> 
> [nit] missing a space: "(u - l)"

Fixed.
 
> > +  /* This is guaranteed for us by libdw read_srclines.  */
> >    if (nlines > 0)
> >      assert (lines->info[nlines - 1].end_sequence);
> 
> In case your answer above was that nlines is never 0, then this "if" is
> redundant.

I moved the if up before the while loop.

> > +  /* The last line which is less than or equal to addr is what we want,
> > +     except with an end_sequence which can only be strictly equal.  */
> > +  Dwarf_Line *line = &lines->info[l];
> > +  if (line->addr == addr || (! line->end_sequence && line->addr < addr))
> > +    return &lines->info[l];
> 
> BTW, it seems like the end ought to be exclusive, i.e. [start,end).  I
> only wrote my commit this way because some existing tests depended on
> end-inclusive behavior, and I forgot to argue it. :)  Thoughts?

I think you are right and those tests, addrscopes and funcscopes, are
wrong. They use dwfl_module_getsrc to find the line associated with start
and end of the scope. But for the end they use the value of the high_pc
attribute. The high_pc attributes indicates the first address beyond
the current scope of the associated DIE. So the tests should use
highpc - 1 as end of scope.

I created a patch to change dwfl_module_getsrc to not match against
a line with end_sequence set, changed the tests to use highpc -1.
And adjusted this patch for dwarf_getsrc_die. to match the new
behavior. Do those changes look correct to you?

Thanks,

Mark

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die.
@ 2014-12-26 21:12 Josh Stone
  0 siblings, 0 replies; 6+ messages in thread
From: Josh Stone @ 2014-12-26 21:12 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 10536 bytes --]

On 12/24/2014 05:27 AM, Mark Wielaard wrote:
> In commit 7d9b5a dwfl_module_getsrc was changed so that it returns the last
> line record <= addr, rather than returning immediately on a match. This
> changes dwarf_getsrc_die to do the same. And it adds a new test that checks
> this by comparing against the same results from eu-addr2line (which uses
> dwfl_module_getsrc) using dwarf_addrdie and dwarf_getsrc_die instead.

Sounds like a good idea.

> Signed-off-by: Mark Wielaard <mjw@redhat.com>
> ---
>  libdw/ChangeLog          |  6 ++++
>  libdw/dwarf_getsrc_die.c | 33 +++++++++-------------
>  tests/Makefile.am        | 10 +++++--
>  tests/getsrc_die.c       | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/run-getsrc-die.sh  | 51 ++++++++++++++++++++++++++++++++++
>  5 files changed, 149 insertions(+), 23 deletions(-)
>  create mode 100644 tests/getsrc_die.c
>  create mode 100755 tests/run-getsrc-die.sh
> 
> diff --git a/libdw/ChangeLog b/libdw/ChangeLog
> index abc2d71..bf64c2e 100644
> --- a/libdw/ChangeLog
> +++ b/libdw/ChangeLog
> @@ -1,3 +1,9 @@
> +2014-12-24  Mark Wielaard  <mjw@redhat.com>
> +
> +	* dwarf_getsrc_die.c (dwarf_getsrc_die): Return the last line record
> +	smaller than or equal to addr, rather than returning immediately on
> +	a match.
> +
>  2014-12-18  Ulrich Drepper  <drepper@gmail.com>
>  
>  	* Makefile.am: Suppress output of textrel_check command.
> diff --git a/libdw/dwarf_getsrc_die.c b/libdw/dwarf_getsrc_die.c
> index 1914cdf..fe06ca4 100644
> --- a/libdw/dwarf_getsrc_die.c
> +++ b/libdw/dwarf_getsrc_die.c
> @@ -1,5 +1,5 @@
>  /* Find line information for address.
> -   Copyright (C) 2004, 2005 Red Hat, Inc.
> +   Copyright (C) 2004, 2005, 2014 Red Hat, Inc.
>     This file is part of elfutils.
>     Written by Ulrich Drepper <drepper@redhat.com>, 2004.
>  
> @@ -45,33 +45,26 @@ dwarf_getsrc_die (Dwarf_Die *cudie, Dwarf_Addr addr)
>      return NULL;
>  
>    /* The lines are sorted by address, so we can use binary search.  */
> -  size_t l = 0, u = nlines;
> +  size_t l = 0, u = nlines - 1;
>    while (l < u)

What if nlines == 0?

>      {
> -      size_t idx = (l + u) / 2;
> -      if (addr < lines->info[idx].addr)
> -	u = idx;
> -      else if (addr > lines->info[idx].addr || lines->info[idx].end_sequence)
> -	l = idx + 1;
> +      size_t idx = u - (u -l) / 2;

[nit] missing a space: "(u - l)"

> +      Dwarf_Line *line = &lines->info[idx];
> +      if (addr < line->addr)
> +	u = idx - 1;
>        else
> -	return &lines->info[idx];
> +	l = idx;
>      }
>  
> +  /* This is guaranteed for us by libdw read_srclines.  */
>    if (nlines > 0)
>      assert (lines->info[nlines - 1].end_sequence);

In case your answer above was that nlines is never 0, then this "if" is
redundant.

>  
> -  /* If none were equal, the closest one below is what we want.  We
> -     never want the last one, because it's the end-sequence marker
> -     with an address at the high bound of the CU's code.  If the debug
> -     information is faulty and no end-sequence marker is present, we
> -     still ignore it.  */
> -  if (u > 0 && u < nlines && addr > lines->info[u - 1].addr)
> -    {
> -      while (lines->info[u - 1].end_sequence && u > 0)
> -	--u;
> -      if (u > 0)
> -	return &lines->info[u - 1];
> -    }
> +  /* The last line which is less than or equal to addr is what we want,
> +     except with an end_sequence which can only be strictly equal.  */
> +  Dwarf_Line *line = &lines->info[l];
> +  if (line->addr == addr || (! line->end_sequence && line->addr < addr))
> +    return &lines->info[l];

BTW, it seems like the end ought to be exclusive, i.e. [start,end).  I
only wrote my commit this way because some existing tests depended on
end-inclusive behavior, and I forgot to argue it. :)  Thoughts?

>  
>    __libdw_seterrno (DWARF_E_ADDR_OUTOFRANGE);
>    return NULL;
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 303f783..c364cc9 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -50,7 +50,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
>  		  test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
>  		  dwfl-report-elf-align varlocs backtrace backtrace-child \
>  		  backtrace-data backtrace-dwarf debuglink debugaltlink \
> -		  buildid deleted deleted-lib.so aggregate_size vdsosyms
> +		  buildid deleted deleted-lib.so aggregate_size vdsosyms \
> +		  getsrc_die
>  
>  asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
>  	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
> @@ -111,7 +112,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
>  	run-backtrace-core-aarch64.sh \
>  	run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \
>  	run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \
> -	run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh
> +	run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh \
> +	run-getsrc-die.sh
>  
>  if !BIARCH
>  export ELFUTILS_DISABLE_BIARCH = 1
> @@ -280,7 +282,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
>  	     linkmap-cut.bz2 linkmap-cut.core.bz2 \
>  	     run-aggregate-size.sh testfile-sizes1.o.bz2 testfile-sizes2.o.bz2 \
>  	     testfile-sizes3.o.bz2 \
> -	     run-readelf-A.sh testfileppc32attrs.o.bz2
> +	     run-readelf-A.sh testfileppc32attrs.o.bz2 \
> +	     run-getsrc-die.sh
>  
>  if USE_VALGRIND
>  valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
> @@ -420,6 +423,7 @@ deleted_lib_so_LDFLAGS = -shared -rdynamic
>  deleted_lib_so_CFLAGS = -fPIC -fasynchronous-unwind-tables
>  aggregate_size_LDADD = $(libdw) $(libelf)
>  vdsosyms_LDADD = $(libdw) $(libelf)
> +getsrc_die_LDADD = $(libdw) $(libelf)
>  
>  if GCOV
>  check: check-am coverage
> diff --git a/tests/getsrc_die.c b/tests/getsrc_die.c
> new file mode 100644
> index 0000000..055aede
> --- /dev/null
> +++ b/tests/getsrc_die.c
> @@ -0,0 +1,72 @@
> +/* Copyright (C) 2014 Red Hat, Inc.
> +   This file is part of elfutils.
> +
> +   This file is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   elfutils is distributed in the hope that it will be useful, but
> +   WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifdef HAVE_CONFIG_H
> +# include <config.h>
> +#endif
> +
> +#include <errno.h>
> +#include <error.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <libelf.h>
> +#include ELFUTILS_HEADER(dw)
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +
> +int
> +main (int argc, char *argv[])
> +{
> +  /* file addr+ */
> +  int fd = open (argv[1], O_RDONLY);
> +  Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
> +  if  (dbg == NULL)
> +    error (-1, 0, "dwarf_begin (%s): %s\n", argv[1], dwarf_errmsg (-1));
> +
> +  for (int i = 2; i < argc; i++)
> +    {
> +      Dwarf_Addr addr;
> +      char *endptr;
> +      Dwarf_Die cudie;
> +      Dwarf_Line *line;
> +
> +      errno = 0;
> +      addr = strtoull (argv[i], &endptr, 16);
> +      if (errno != 0)
> +	error (-1, errno, "Cannot parrse '%s'", argv[1]);
> +
> +      if (dwarf_addrdie (dbg, addr, &cudie) == NULL)
> +	error (-1, 0, "dwarf_addrdie (%s): %s", argv[i], dwarf_errmsg (-1));
> +
> +      line = dwarf_getsrc_die (&cudie, addr);
> +      if (line == NULL)
> +	error (-1, 0, "dwarf_getsrc_die (%s): %s", argv[i], dwarf_errmsg (-1));
> +
> +      const char *f = dwarf_linesrc (line, NULL, NULL);
> +      int l;
> +      if (dwarf_lineno (line, &l) != 0)
> +	l = 0;
> +
> +      printf ("%s:%d\n", f ?: "???", l);
> +    }
> +
> +  dwarf_end (dbg);
> +  close (fd);
> +
> +  return 0;
> +}
> diff --git a/tests/run-getsrc-die.sh b/tests/run-getsrc-die.sh
> new file mode 100755
> index 0000000..4da16e7
> --- /dev/null
> +++ b/tests/run-getsrc-die.sh
> @@ -0,0 +1,51 @@
> +#! /bin/sh
> +# Copyright (C) 2014 Red Hat, Inc.
> +# This file is part of elfutils.
> +#
> +# This file is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# elfutils is distributed in the hope that it will be useful, but
> +# WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +. $srcdir/test-subr.sh
> +
> +# See run-addr2line-test.sh run-addr2line-i-test.sh run-addr2line-i-lex-test.sh
> +# Output/files/lines matched should equal what is done through addr2line
> +# which uses dwfl_module_getsrc. This test uses dwarf_addrdie and
> +# dwarf_getsrc_die
> +testfiles testfile testfile-inlines testfile-lex-inlines
> +
> +testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile 0x08048468 0x0804845c <<\EOF
> +/home/drepper/gnu/new-bu/build/ttt/f.c:3
> +/home/drepper/gnu/new-bu/build/ttt/b.c:4
> +EOF
> +
> +testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile-inlines 0x00000000000005a0 0x00000000000005a1 0x00000000000005b0 0x00000000000005b1 0x00000000000005c0 0x00000000000005d0 0x00000000000005e0 0x00000000000005e1 0x00000000000005f1 0x00000000000005f2 <<\EOF
> +/tmp/x.cpp:5
> +/tmp/x.cpp:6
> +/tmp/x.cpp:10
> +/tmp/x.cpp:11
> +/tmp/x.cpp:5
> +/tmp/x.cpp:10
> +/tmp/x.cpp:5
> +/tmp/x.cpp:10
> +/tmp/x.cpp:10
> +/tmp/x.cpp:5
> +EOF
> +
> +testrun_compare ${abs_top_builddir}/tests/getsrc_die testfile-lex-inlines 0x0000000000000680 0x0000000000000681 0x0000000000000690 0x0000000000000691 <<\EOF
> +/tmp/x.cpp:5
> +/tmp/x.cpp:5
> +/tmp/x.cpp:5
> +/tmp/x.cpp:5
> +EOF
> +
> +exit 0
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-01-16  8:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-24 12:27 [PATCH] libdw: Search for the last matching address with dwarf_getsrc_die Mark Wielaard
2014-12-26 21:12 Josh Stone
2014-12-27 15:49 Mark Wielaard
2015-01-12 21:25 Mark Wielaard
2015-01-15 19:54 Josh Stone
2015-01-16  8:09 Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).