]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Add dwarf_getlocation_relocatable_addr.
authorRoland McGrath <roland@redhat.com>
Thu, 1 Jul 2010 06:47:02 +0000 (23:47 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 1 Jul 2010 06:47:02 +0000 (23:47 -0700)
libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf_frame_cfa.c
libdw/dwarf_frame_register.c
libdw/dwarf_getlocation.c
libdw/dwarf_getlocation_relocatable.c
libdw/dwarf_getlocation_relocatable_addr.c [new file with mode: 0644]
libdw/dwarf_relocatable_info.c
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h

index 21dd1c6dd55d59a6a4407b4ad3dd3e433d8bed9c..e76d97d268ff8aca0da373b4f0a457aca9c5da88 100644 (file)
@@ -1,5 +1,19 @@
 2010-06-30  Roland McGrath  <roland@redhat.com>
 
+       * dwarf_getlocation_relocatable_addr.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add it.
+       * libdw.map (ELFUTILS_0.149): Add it.
+       * libdw.h: Declare it.
+
+       * dwarf_getlocation.c (__libdw_intern_expression): New flag argument.
+       When set, handle relocatable DW_OP_addr.
+       (__libdw_getlocation): Likewise, pass it through.
+       (dwarf_getlocation, dwarf_getlocation_addr): Update callers.
+       * dwarf_frame_register.c: Likewise.
+       * dwarf_frame_cfa.c: Likewise.
+       * dwarf_getlocation_relocatable.c: Likewise.
+       * libdwP.h: Update decls.
+
        * relocate.c (digest_one_reloc, digest_relocs): Track r_offset values
        and don't bother sorting if they were already sorted.
 
index 719d1d5804b51d0595679337674aaddb6ed5c3f4..35a0fd8d0afbc31977aec2f1522882247d39706f 100644 (file)
@@ -88,6 +88,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  relocate.c dwarf_relocatable_info.c \
                  dwarf_form_relocatable.c dwarf_line_relocatable.c \
                  dwarf_ranges_relocatable.c dwarf_getlocation_relocatable.c \
+                 dwarf_getlocation_relocatable_addr.c \
                  dwarf_haspc_relocatable.c dwarf_getsrc_relocatable.c
 
 if MAINTAINER_MODE
index 2f3268a89a37bbb10587796901e37c737bcdfdcb..eb4a16ee09281d1c1f4bfaee9697f6e126fa5bee 100644 (file)
@@ -84,7 +84,7 @@ dwarf_frame_cfa (fs, ops, nops)
       result = __libdw_intern_expression
        (NULL, fs->cache->other_byte_order,
         fs->cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8, 4,
-        &fs->cache->expr_tree, &fs->cfa_data.expr, false, false,
+        &fs->cache->expr_tree, &fs->cfa_data.expr, false, false, false,
         ops, nops, IDX_debug_frame);
       break;
 
index ae0db0200521df4ed675f34a99e5b6da551a061f..0fc759e6701b32bad9e53fbda4e0cee0247f455c 100644 (file)
@@ -130,7 +130,7 @@ dwarf_frame_register (fs, regno, ops_mem, ops, nops)
        if (__libdw_intern_expression (NULL,
                                       fs->cache->other_byte_order,
                                       address_size, 4,
-                                      &fs->cache->expr_tree, &block,
+                                      &fs->cache->expr_tree, &block, false,
                                       true, reg->rule == reg_val_expression,
                                       ops, nops, IDX_debug_frame) < 0)
          return -1;
index fa188dcc90ac80acffd908c8e88abbdabcbac9a0..0c4dc346f8f9cf8f701770171341204d9c293106 100644 (file)
@@ -57,7 +57,7 @@
 #include <stdlib.h>
 #include <assert.h>
 
-#include <libdwP.h>
+#include "relocate.h"
 
 
 static bool
@@ -137,7 +137,7 @@ dwarf_getlocation_implicit_value (attr, op, return_block)
 
   struct loc_block_s fake = { .addr = (void *) op };
   struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
-  if (unlikely (found == NULL))
+  if (unlikely (found == NULL) || unlikely (op->atom != DW_OP_implicit_value))
     {
       __libdw_seterrno (DWARF_E_NO_BLOCK);
       return -1;
@@ -216,7 +216,7 @@ int
 internal_function
 __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
                           unsigned int address_size, unsigned int ref_size,
-                          void **cache, const Dwarf_Block *block,
+                          void **cache, const Dwarf_Block *block, bool reloc,
                           bool cfap, bool valuep,
                           Dwarf_Op **llbuf, size_t *listlen, int sec_index)
 {
@@ -238,6 +238,9 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
       return 0;
     }
 
+  reloc = reloc && (dbg->relocate != NULL
+                   && dbg->relocate->sectionrel[sec_index] != NULL);
+
   const unsigned char *data = block->data;
   const unsigned char *const end_data = data + block->length;
 
@@ -262,9 +265,30 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
        {
        case DW_OP_addr:
          /* Address, depends on address size of CU.  */
-         if (__libdw_read_address_inc (dbg, sec_index, &data,
-                                       address_size, &newloc->number))
-           return -1;
+         if (reloc)
+           {
+             /* When taking relocatable addresses, we resolve to the
+                symndx and store that in the Dwarf_Op for later use
+                with dwarf_getlocation_relocatable_addr.  */
+             int symndx;
+             GElf_Sxword addend;
+             int shndx = __libdw_relocatable (dbg, sec_index,
+                                              data, address_size,
+                                              &symndx, &addend);
+             if (unlikely (shndx < 0))
+               return -1;
+             data += address_size;
+             newloc->number = addend;
+             if (shndx > 0)
+               newloc->number2 = symndx;
+           }
+         else
+           {
+             /* The address has to be resolved now.  */
+             if (__libdw_read_address_inc (dbg, sec_index, &data,
+                                           address_size, &newloc->number))
+               return -1;
+           }
          break;
 
        case DW_OP_call_ref:
@@ -520,6 +544,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 int
 internal_function
 __libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+                    bool reloc,
                     Dwarf_Op **llbuf, size_t *listlen, int sec_index)
 {
   struct Dwarf_CU *cu = attr->cu;
@@ -527,7 +552,7 @@ __libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
                                    cu->address_size, (cu->version == 2
                                                       ? cu->address_size
                                                       : cu->offset_size),
-                                   &cu->locs, block,
+                                   &cu->locs, block, reloc,
                                    false, false,
                                    llbuf, listlen, sec_index);
 }
@@ -550,7 +575,7 @@ dwarf_getlocation (attr, llbuf, listlen)
   if (INTUSE(dwarf_formblock) (attr, &block) != 0)
     return -1;
 
-  return __libdw_getlocation (attr, &block, llbuf, listlen,
+  return __libdw_getlocation (attr, &block, false, llbuf, listlen,
                              cu_sec_idx (attr->cu));
 }
 
@@ -577,7 +602,8 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
          if (maxlocs == 0)
            return 0;
          if (llbufs != NULL &&
-             __libdw_getlocation (attr, &block, &llbufs[0], &listlens[0],
+             __libdw_getlocation (attr, &block, false,
+                                  &llbufs[0], &listlens[0],
                                   cu_sec_idx (attr->cu)) != 0)
            return -1;
          return listlens[0] == 0 ? 0 : 1;
@@ -667,7 +693,7 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
        {
          /* This one matches the address.  */
          if (llbufs != NULL
-             && unlikely (__libdw_getlocation (attr, &block,
+             && unlikely (__libdw_getlocation (attr, &block, false,
                                                &llbufs[got], &listlens[got],
                                                IDX_debug_loc) != 0))
            return -1;
index a9bf025b3f3afcafa80216b26e9cf0892e366b77..f2082d9d7260a54bc7929570e92dcba9e2938bea 100644 (file)
@@ -105,7 +105,7 @@ dwarf_getlocation_relocatable (Dwarf_Attribute *attr, ptrdiff_t offset,
 
   /* Parse the block into internal form.  */
   if (offset > 0 && expr != NULL
-      && __libdw_getlocation (attr, &block, expr, exprlen, sec_idx) < 0)
+      && __libdw_getlocation (attr, &block, true, expr, exprlen, sec_idx) < 0)
     offset = -1;
 
   return offset;
diff --git a/libdw/dwarf_getlocation_relocatable_addr.c b/libdw/dwarf_getlocation_relocatable_addr.c
new file mode 100644 (file)
index 0000000..0886c30
--- /dev/null
@@ -0,0 +1,104 @@
+/* Return relocatable address from DW_OP_addr in a DWARF expression.
+   Copyright (C) 2010 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils 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; version 2 of the License.
+
+   Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwP.h"
+#include <dwarf.h>
+
+int
+dwarf_getlocation_relocatable_addr (attr, op, reloc)
+     Dwarf_Attribute *attr;
+     const Dwarf_Op *op;
+     Dwarf_Relocatable *reloc;
+{
+  if (attr == NULL)
+    return -1;
+
+  if (unlikely (op->atom != DW_OP_addr))
+    {
+      __libdw_seterrno (DWARF_E_INVALID_ACCESS);
+      return -1;
+    }
+
+  *reloc = (Dwarf_Relocatable)
+    {
+      .form = DW_FORM_addr,
+      .cu = attr->cu,
+      .adjust = op->number,
+      .symndx = op->number2,
+    };
+
+  if (reloc->symndx != 0)
+    /* Setting .valp non-null with .symndx nonzero indicates that
+       the adjustment is relative to a known symndx, but not resolved
+       to section-relative.  */
+    reloc->valp = (void *) -1l;
+
+  /* If the attribute this expression came from was a location list, then
+     the relevant symtab is that of the .rela.debug_loc section; otherwise
+     it's that of the section where the attribute resides.  */
+
+  switch (attr->form)
+    {
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_sec_offset:
+      reloc->sec = IDX_debug_loc;
+      break;
+
+    default:
+      reloc->sec = cu_sec_idx (reloc->cu);
+      break;
+    }
+
+  return 0;
+}
index 37868f62734cc8cdaebbeddaba63246c53cc6915..8570276c0ed3304f0db4bceea1909e5af7c971b1 100644 (file)
@@ -112,7 +112,7 @@ dwarf_relocatable_info (reloc, sym, name, addend, secname)
     }
 
   GElf_Sxword adjust = 0;
-  if (reloc->valp != NULL)
+  if (reloc->valp != NULL && reloc->symndx == STN_UNDEF)
     {
       int result = __libdw_relocatable (reloc->cu->dbg, reloc->sec,
                                        reloc->valp, width,
index 2eaf95a27de613a98d1c2d88604624c5e82da60b..75dcd142bc6b5346f09c4392541ecc4542461707 100644 (file)
@@ -728,7 +728,6 @@ extern ptrdiff_t dwarf_getlocation_relocatable (Dwarf_Attribute *attr,
                                                size_t *exprlen)
   __nonnull_attribute__ (3, 4, 5, 6, 7);
 
-
 /* Return the block associated with a DW_OP_implicit_value operation.
    The OP pointer must point into an expression that dwarf_getlocation
    or dwarf_getlocation_addr has returned given the same ATTR.  */
@@ -737,6 +736,14 @@ extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr,
                                             Dwarf_Block *return_block)
   __nonnull_attribute__ (2, 3);
 
+/* Return the relocatable form of a DW_OP_addr operation.  The OP pointer
+   must point into an expression that dwarf_getlocation_relocatable has
+   returned given the same ATTR.  */
+extern int dwarf_getlocation_relocatable_addr (Dwarf_Attribute *attr,
+                                              const Dwarf_Op *op,
+                                              Dwarf_Relocatable *reloc)
+  __nonnull_attribute__ (2, 3);
+
 
 /* Compute the byte-size of a type DIE according to DWARF rules.
    For most types, this is just DW_AT_byte_size.
index 86505b4bd6925bd49c567eb5a149302c5a93f9ed..d5444f6f685d1c96c14c4b0810513269a552dc8a 100644 (file)
@@ -254,6 +254,7 @@ ELFUTILS_0.149 {
     dwarf_getsrc_relocatable;
     dwarf_line_relocatable;
     dwarf_getlocation_relocatable;
+    dwarf_getlocation_relocatable_addr;
     dwarf_haspc_relocatable;
     dwarf_ranges_relocatable;
     dwarf_relocatable_info;
index e7f66a2ffcdd4df81a3e1b7280f47e2f4b868f68..ce52ffdf773e0d0104c461d26e0192b27d8071cd 100644 (file)
@@ -475,14 +475,15 @@ extern int __libdw_intern_expression (Dwarf *dbg,
                                      unsigned int address_size,
                                      unsigned int ref_size,
                                      void **cache, const Dwarf_Block *block,
-                                     bool cfap, bool valuep,
+                                     bool reloc, bool cfap, bool valuep,
                                      Dwarf_Op **llbuf, size_t *listlen,
                                      int sec_index)
-  __nonnull_attribute__ (5, 6, 9, 10) internal_function;
+  __nonnull_attribute__ (5, 6, 10, 11) internal_function;
 
 extern int __libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+                               bool reloc,
                                Dwarf_Op **llbuf, size_t *listlen, int sec_idx)
-  __nonnull_attribute__ (2, 3, 4) internal_function;
+  __nonnull_attribute__ (2, 4, 5) internal_function;
 
 
 /* Return error code of last failing function call.  This value is kept