PR25058 - Better support fn DIEs referring to symbols using DW_AT_ranges
authorDodji Seketeli <dodji@redhat.com>
Fri, 4 Oct 2019 08:05:42 +0000 (10:05 +0200)
committerDodji Seketeli <dodji@redhat.com>
Fri, 4 Oct 2019 08:05:42 +0000 (10:05 +0200)
In the previous commit 2f7248f, we were just taking the first address
referred to by the DW_AT_ranges attribute as being the address of the
symbol of the function we are looking at.  But there can be cases
where this is not true, as explained at
https://sourceware.org/bugzilla/show_bug.cgi?id=25058#c7.

We really need to get the first address that represents an exported
and defined function symbol, which is pointed to by the DW_AT_ranges
attribute.

And this is what this patch does.

* src/abg-dwarf-reader.cc
(read_context::get_first_exported_fn_address_from_DW_AT_ranges):
Rename read_context::get_first_address_from_DW_AT_ranges into
this.  Walk through the addresses referred to by the DW_AT_ranges
attribute until we find one that is for an exported function
symbol, rather than just picking the first address of the set.
(read_context::get_function_address): Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
src/abg-dwarf-reader.cc

index 1c9b816..af212ac 100644 (file)
@@ -8565,8 +8565,8 @@ public:
     return addr;
   }
 
-  /// Get the first address in the set of addresses referred to by the
-  /// DW_AT_ranges attribute of a given DIE.
+  /// Get the first exported function address in the set of addresses
+  /// referred to by the DW_AT_ranges attribute of a given DIE.
   ///
   /// @param die the DIE we are considering.
   ///
@@ -8576,14 +8576,29 @@ public:
   /// true.  Otherwise, no value is set into this output parameter.
   ///
   /// @return true iff the DIE @p die does have a DW_AT_ranges
-  /// attribute and an address was found in its sequence value.
+  /// attribute and an address of an exported function was found in
+  /// its sequence value.
   bool
-  get_first_address_from_DW_AT_ranges(Dwarf_Die* die, Dwarf_Addr& address) const
+  get_first_exported_fn_address_from_DW_AT_ranges(Dwarf_Die* die,
+                                                 Dwarf_Addr& address) const
   {
     Dwarf_Addr base;
     Dwarf_Addr end_addr;
-    if (dwarf_ranges(die, /*offset=*/0, &base, &address, &end_addr))
-      return true;
+    ptrdiff_t offset = 0;
+
+    do
+      {
+       Dwarf_Addr addr, fn_addr;
+       if ((offset = dwarf_ranges(die, offset, &base, &addr, &end_addr)) >= 0)
+         {
+           fn_addr = maybe_adjust_fn_sym_address(addr);
+           if (function_symbol_is_exported(fn_addr))
+             {
+               address = fn_addr;
+               return true;
+             }
+         }
+      } while (offset > 0);
     return false;
   }
 
@@ -8603,18 +8618,17 @@ public:
   bool
   get_function_address(Dwarf_Die* function_die, Dwarf_Addr& address) const
   {
-    Dwarf_Addr fn_address = 0;
-    if (!die_address_attribute(function_die, DW_AT_low_pc, fn_address))
+    if (!die_address_attribute(function_die, DW_AT_low_pc, address))
       // So no DW_AT_low_pc was found.  Let's see if the function DIE
       // has got a DW_AT_ranges attribute instead.  If it does, the
       // first address of the set of addresses represented by the
       // value of that DW_AT_ranges represents the function (symbol)
       // address we are looking for.
-      if (!get_first_address_from_DW_AT_ranges(function_die, fn_address))
+      if (!get_first_exported_fn_address_from_DW_AT_ranges(function_die,
+                                                          address))
        return false;
 
-    fn_address = maybe_adjust_fn_sym_address(fn_address);
-    address = fn_address;
+    address = maybe_adjust_fn_sym_address(address);
     return true;
   }