]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Search for the last matching address in lines
authorJosh Stone <jistone@redhat.com>
Fri, 12 Dec 2014 00:23:46 +0000 (16:23 -0800)
committerJosh Stone <jistone@redhat.com>
Sat, 13 Dec 2014 21:31:09 +0000 (13:31 -0800)
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 <jistone@redhat.com>
libdwfl/ChangeLog
libdwfl/dwfl_module_getsrc.c

index 66e642f140958a1ed227c3528dce588929c347ce..b83cb121ccaed4edc58ab643714a112ff5a3de93 100644 (file)
@@ -1,3 +1,8 @@
+2014-12-11  Josh Stone  <jistone@redhat.com>
+
+       * dwfl_module_getsrc.c (dwfl_module_getsrc): Return the *last* line
+       record <= addr, rather than returning immediately on matches.
+
 2014-12-09  Mark Wielaard  <mjw@redhat.com>
 
        * dwfl_segment_report_module.c (handle_file_note): Check count doesn't
index cf8dc0fc2d0a5aa6e538130acb55444c20dbf7df..f6d883903b84a360621b44d5aee8af00e1572457 100644 (file)
@@ -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
+               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;
     }