Now that libdw's srclines use a stable sort, we can reliably choose the
*last* matching line record for a given address, which should be the
innermost where inlines are concerned.

Signed-off-by: Josh Stone <[email protected]>
---
 libdwfl/ChangeLog            |  5 +++++
 libdwfl/dwfl_module_getsrc.c | 51 +++++++++++++++++++++++---------------------
 2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index b882f2049ca0..7b0ea15f013f 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-11  Josh Stone  <[email protected]>
+
+       * dwfl_module_getsrc.c (dwfl_module_getsrc): Return the *last* line
+       record <= addr, rather than returning immediately on matches.
+
 2014-12-07  Mark Wielaard  <[email protected]>
 
        * relocate.c (relocate_section): Sanity check section overlap against
diff --git a/libdwfl/dwfl_module_getsrc.c b/libdwfl/dwfl_module_getsrc.c
index cf8dc0fc2d0a..41cf9753313e 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 Red Hat, Inc.
+   Copyright (C) 2005, 2008, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -42,32 +42,35 @@ dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr)
     error = __libdwfl_cu_getsrclines (cu);
   if (likely (error == DWFL_E_NOERROR))
     {
-      /* Now we look at the module-relative address.  */
-      addr -= bias;
-
-      /* The lines are sorted by address, so we can use binary search.  */
-      size_t l = 0, u = cu->die.cu->lines->nlines;
-      while (l < u)
+      Dwarf_Lines *lines = cu->die.cu->lines;
+      size_t nlines = lines->nlines;
+      if (nlines > 0)
        {
-         size_t idx = (l + u) / 2;
-         if (addr < cu->die.cu->lines->info[idx].addr)
-           u = idx;
-         else if (addr > cu->die.cu->lines->info[idx].addr)
-           l = idx + 1;
-         else
-           return &cu->lines->idx[idx];
-       }
+         /* This is guaranteed for us by libdw read_srclines.  */
+         assert(lines->info[nlines - 1].end_sequence);
 
-      if (cu->die.cu->lines->nlines > 0)
-       assert (cu->die.cu->lines->info
-               [cu->die.cu->lines->nlines - 1].end_sequence);
+         /* Now we look at the module-relative address.  */
+         addr -= bias;
 
-      /* 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 (u > 0 && u < cu->die.cu->lines->nlines
-         && addr > cu->die.cu->lines->info[u - 1].addr)
-       return &cu->lines->idx[u - 1];
+         /* The lines are sorted by address, so we can use binary search.  */
+         size_t l = 0, u = nlines - 1;
+         while (l < u)
+           {
+             size_t idx = u - (u - l) / 2;
+             Dwarf_Line *line = &lines->info[idx];
+             if (addr < line->addr)
+               u = idx - 1;
+             else if (addr >= line->addr)
+               l = idx;
+           }
+
+         /* 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 &cu->lines->idx[l];
+       }
 
       error = DWFL_E_ADDR_OUTOFRANGE;
     }
-- 
2.1.0

Reply via email to