]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
More relocatable libdw interfaces.
authorRoland McGrath <roland@redhat.com>
Wed, 23 Jun 2010 05:13:01 +0000 (22:13 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 23 Jun 2010 05:13:01 +0000 (22:13 -0700)
14 files changed:
libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf_form_relocatable.c
libdw/dwarf_getlocation.c
libdw/dwarf_getlocation_relocatable.c [new file with mode: 0644]
libdw/dwarf_haspc_relocatable.c [new file with mode: 0644]
libdw/dwarf_ranges_relocatable.c [new file with mode: 0644]
libdw/dwarf_relocatable_info.c
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h
libdw/memory-access.h
libdw/relocate.c
libdw/relocate.h [new file with mode: 0644]

index e3b631bc41627634e812084b2ad8d2efd714cfcf..486c7e4a7d25231b155cd366bd35d302eef43e28 100644 (file)
@@ -1,14 +1,31 @@
 2010-06-22  Roland McGrath  <roland@redhat.com>
 
+       * dwarf_ranges_relocatable.c: New file.
+       * dwarf_getlocation_relocatable.c: New file.
+       * dwarf_haspc_relocatable.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add them.
+       * libdw.map (ELFUTILS_0.149): Add them.
+       * libdw.h: Declare them.
+       * libdwP.h: Add INTDECLs.
+
+       * dwarf_getlocation.c (getlocation): Renamed to ...
+       (__libdw_getlocation): ... this; made global.
+       (dwarf_getlocation, dwarf_getlocation_addr): Update callers.
+       * libdwP.h: Declare it.
+
+       * relocate.h: New file.
+       * relocate.c: Move structs there.
+       (relocatable_datum): Renamed to ...
+        (__libdw_relocatable): ... here, made global.
        * libdw.h (Dwarf_Relocatable): New type.  Declare three new functions.
        * dwarf_relocatable_info.c: New file.
        * dwarf_form_relocatable.c: New file.
        * dwarf_line_relocatable.c: New file.
        * Makefile.am (libdw_a_SOURCES): Add them.
        * libdw.map (ELFUTILS_0.149): New set; add those.
+       * libdwP.h: Add an INTDECL.
 
-       * relocate.c (__libdw_relocatable): New function.
-       * libdwP.h: Declare it.
+       * memory-access.h (read_8ubyte_unaligned_noncvt): New function/macro.
 
        * dwarf_getlocation.c (check_constant_offset): data[48] are constant.
 
index 146d7f4428d8ed257a1c2d541f639a1c0f380c21..e77ea5f4cb2adf42e274bec6933dade466c0bde2 100644 (file)
@@ -86,7 +86,9 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c \
                  dwarf_aggregate_size.c \
                  relocate.c dwarf_relocatable_info.c \
-                 dwarf_form_relocatable.c dwarf_line_relocatable.c
+                 dwarf_form_relocatable.c dwarf_line_relocatable.c \
+                 dwarf_ranges_relocatable.c dwarf_getlocation_relocatable.c \
+                 dwarf_haspc_relocatable.c
 
 if MAINTAINER_MODE
 BUILT_SOURCES = $(srcdir)/known-dwarf.h
index 3b2dc9c2d3285d1a4ad5df56e1b6d79d2314dcd0..ee00522a850a643f63b924e8f03b4f02e6fde1c3 100644 (file)
@@ -71,3 +71,4 @@ dwarf_form_relocatable (attr, reloc)
 
   return 0;
 }
+INTDEF (dwarf_form_relocatable)
index e960ef9e97ab3dfabcf91a0c837d5e2235c314ec..fa188dcc90ac80acffd908c8e88abbdabcbac9a0 100644 (file)
@@ -517,10 +517,12 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
   return 0;
 }
 
-static int
-getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
-            Dwarf_Op **llbuf, size_t *listlen, int sec_index)
+int
+internal_function
+__libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+                    Dwarf_Op **llbuf, size_t *listlen, int sec_index)
 {
+  struct Dwarf_CU *cu = attr->cu;
   return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
                                    cu->address_size, (cu->version == 2
                                                       ? cu->address_size
@@ -548,7 +550,8 @@ dwarf_getlocation (attr, llbuf, listlen)
   if (INTUSE(dwarf_formblock) (attr, &block) != 0)
     return -1;
 
-  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
+  return __libdw_getlocation (attr, &block, llbuf, listlen,
+                             cu_sec_idx (attr->cu));
 }
 
 int
@@ -567,22 +570,25 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
 
   /* If it has a block form, it's a single location expression.  */
   Dwarf_Block block;
-  if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+  if (attr->cu->version < 4 || attr->form == DW_FORM_exprloc)
     {
-      if (maxlocs == 0)
-       return 0;
-      if (llbufs != NULL &&
-         getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
-                      cu_sec_idx (attr->cu)) != 0)
-       return -1;
-      return listlens[0] == 0 ? 0 : 1;
-    }
+      if (INTUSE(dwarf_formblock) (attr, &block) == 0)
+       {
+         if (maxlocs == 0)
+           return 0;
+         if (llbufs != NULL &&
+             __libdw_getlocation (attr, &block, &llbufs[0], &listlens[0],
+                                  cu_sec_idx (attr->cu)) != 0)
+           return -1;
+         return listlens[0] == 0 ? 0 : 1;
+       }
 
-  int error = INTUSE(dwarf_errno) ();
-  if (unlikely (error != DWARF_E_NO_BLOCK))
-    {
-      __libdw_seterrno (error);
-      return -1;
+      int error = INTUSE(dwarf_errno) ();
+      if (unlikely (error != DWARF_E_NO_BLOCK))
+       {
+         __libdw_seterrno (error);
+         return -1;
+       }
     }
 
   int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
@@ -661,9 +667,9 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
        {
          /* This one matches the address.  */
          if (llbufs != NULL
-             && unlikely (getlocation (attr->cu, &block,
-                                       &llbufs[got], &listlens[got],
-                                       IDX_debug_loc) != 0))
+             && unlikely (__libdw_getlocation (attr, &block,
+                                               &llbufs[got], &listlens[got],
+                                               IDX_debug_loc) != 0))
            return -1;
          ++got;
        }
diff --git a/libdw/dwarf_getlocation_relocatable.c b/libdw/dwarf_getlocation_relocatable.c
new file mode 100644 (file)
index 0000000..a9bf025
--- /dev/null
@@ -0,0 +1,112 @@
+/* Enumerate the PC ranges covered by a location list.
+   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 "relocate.h"
+#include <dwarf.h>
+#include <assert.h>
+
+
+ptrdiff_t
+dwarf_getlocation_relocatable (Dwarf_Attribute *attr, ptrdiff_t offset,
+                              Dwarf_Relocatable *basep,
+                              Dwarf_Relocatable *startp,
+                              Dwarf_Relocatable *endp,
+                              Dwarf_Op **expr, size_t *exprlen)
+{
+  if (attr == NULL)
+    return -1;
+
+  unsigned int sec_idx = IDX_debug_loc;
+  Dwarf_Block block;
+  if (offset == 0)
+    switch (attr->form)
+      {
+      case DW_FORM_block:
+      case DW_FORM_block1:
+      case DW_FORM_block2:
+      case DW_FORM_block4:
+       if (unlikely (attr->cu->version >= 4))
+         {
+           __libdw_seterrno (DWARF_E_NO_LOCLIST);
+           return -1;
+         }
+
+      case DW_FORM_exprloc:
+       if (unlikely (INTUSE(dwarf_formblock) (attr, &block) < 0))
+         return -1;
+
+       sec_idx = cu_sec_idx (attr->cu);
+       *startp = (Dwarf_Relocatable) { .adjust = 0 };
+       *endp = (Dwarf_Relocatable) { .adjust = (Dwarf_Addr) -1 };
+
+       /* A offset into .debug_loc will never be 1, it must be at least a
+          multiple of 4.  So we can return 1 as a special case value to
+          mark there are no ranges to look for on the next call.  */
+       offset = 1;
+       break;
+      }
+  else if (offset == 1)
+    return 0;
+
+  if (offset != 1)
+    /* Iterate from last position.  */
+    offset = __libdw_ranges_relocatable (attr->cu, attr, offset,
+                                        basep, startp, endp, &block);
+
+  /* Parse the block into internal form.  */
+  if (offset > 0 && expr != NULL
+      && __libdw_getlocation (attr, &block, expr, exprlen, sec_idx) < 0)
+    offset = -1;
+
+  return offset;
+}
diff --git a/libdw/dwarf_haspc_relocatable.c b/libdw/dwarf_haspc_relocatable.c
new file mode 100644 (file)
index 0000000..62ba5a4
--- /dev/null
@@ -0,0 +1,111 @@
+/* Determine whether a DIE covers a PC address.
+   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_haspc_relocatable (Dwarf_Die *die, Dwarf_Relocatable *pc)
+{
+  if (die == NULL)
+    return -1;
+
+  GElf_Sym pc_sym;
+  GElf_Sxword pc_addend;
+  int pc_shndx = INTUSE(dwarf_relocatable_info) (pc, &pc_sym, NULL,
+                                                &pc_addend, NULL);
+  if (pc_shndx < 0)
+    return pc_shndx;
+  pc_sym.st_value += pc_addend;
+
+  Dwarf_Relocatable base;
+  Dwarf_Relocatable begin;
+  Dwarf_Relocatable end;
+  ptrdiff_t offset = 0;
+  while ((offset = INTUSE(dwarf_ranges_relocatable) (die, offset, &base,
+                                                    &begin, &end)) > 0)
+    if (begin.valp == NULL && end.valp == NULL && pc->valp == NULL)
+      {
+       if (pc->adjust >= begin.adjust && pc->adjust < end.adjust)
+         return 1;
+      }
+    else
+      {
+       /* A relocatable address matches if it's in the same section
+          and the section-relative offsets match.  */
+
+       GElf_Sym sym;
+       GElf_Sxword addend;
+       int shndx = INTUSE(dwarf_relocatable_info) (&begin, &sym, NULL,
+                                                   &addend, NULL);
+       if (shndx < 0)
+         return -1;
+       if (shndx == pc_shndx && sym.st_shndx == pc_sym.st_shndx
+           && pc_sym.st_value >= sym.st_value + addend)
+         {
+           if (pc_sym.st_value == sym.st_value + addend)
+             return 1;
+           shndx = INTUSE(dwarf_relocatable_info) (&end, &sym, NULL,
+                                                   &addend, NULL);
+           if (shndx < 0)
+             return -1;
+           if (shndx == pc_shndx && sym.st_shndx == pc_sym.st_shndx
+               && pc_sym.st_value < sym.st_value + addend)
+             return 1;
+         }
+      }
+
+  return offset;
+}
+INTDEF (dwarf_haspc_relocatable)
diff --git a/libdw/dwarf_ranges_relocatable.c b/libdw/dwarf_ranges_relocatable.c
new file mode 100644 (file)
index 0000000..61f52a4
--- /dev/null
@@ -0,0 +1,256 @@
+/* Enumerate the PC ranges covered by a DIE.
+   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 "relocate.h"
+#include <dwarf.h>
+#include <assert.h>
+
+ptrdiff_t
+internal_function
+__libdw_ranges_relocatable (struct Dwarf_CU *cu, Dwarf_Attribute *attr,
+                           ptrdiff_t offset,
+                           Dwarf_Relocatable *basep,
+                           Dwarf_Relocatable *startp, Dwarf_Relocatable *endp,
+                           Dwarf_Block *exprloc)
+{
+  if (offset == 1)
+    return 0;
+
+  const unsigned int sec_idx = (exprloc != NULL ? IDX_debug_loc
+                               : IDX_debug_ranges);
+  unsigned char *readp;
+  unsigned char *readendp;
+  if (offset == 0)
+    {
+      Dwarf_Word start_offset;
+      if ((readp = __libdw_formptr (attr, sec_idx,
+                                   exprloc != NULL ? DWARF_E_NO_LOCLIST
+                                   : DWARF_E_NO_DEBUG_RANGES,
+                                   &readendp, &start_offset)) == NULL)
+       return -1;
+
+      offset = start_offset;
+      assert ((Dwarf_Word) offset == start_offset);
+
+      /* This is a marker that we need to fetch the CU base address.  */
+      basep->cu = NULL;
+    }
+  else if (__libdw_offset_in_section (cu->dbg,
+                                     exprloc != NULL ? IDX_debug_loc
+                                     : IDX_debug_ranges,
+                                     offset, 1))
+    return -1l;
+  else
+    {
+      const Elf_Data *d = cu->dbg->sectiondata[sec_idx];
+      readp = d->d_buf + offset;
+      readendp = d->d_buf + d->d_size;
+    }
+
+  inline void store (Dwarf_Relocatable *relocp, ptrdiff_t read_adjust)
+  {
+    *relocp = (Dwarf_Relocatable)
+      {
+       .cu = cu, .sec = sec_idx, .form = DW_FORM_addr,
+       .valp = readp
+      };
+    readp += read_adjust;
+  }
+
+  inline bool finalize_reloc (Dwarf_Relocatable *reloc, unsigned int width)
+  {
+    if (basep->cu == NULL)
+      {
+       /* This is the initial default base address and we have not used it
+          yet.  Find the base address of the compilation unit.  It will
+          normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4, the
+          base address could be overridden by DW_AT_entry_pc.  It's been
+          removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for
+          compilation units with discontinuous ranges.  */
+
+       Dwarf_Die cudie = CUDIE (cu);
+       Dwarf_Attribute loattr;
+       if (unlikely (INTUSE(dwarf_form_relocatable)
+                     (INTUSE(dwarf_attr) (&cudie, DW_AT_low_pc, &loattr)
+                      ?: INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, &loattr),
+                      basep) < 0))
+         return true;
+      }
+
+    GElf_Sxword addend;
+    if (__libdw_relocatable (cu->dbg, sec_idx, reloc->valp, width,
+                            NULL, &addend) > 0)
+      {
+       /* The address itself has a relocation.
+          The base address entry must not also have a relocation.  */
+
+       if (unlikely (__libdw_relocatable (cu->dbg, sec_idx, basep->valp, width,
+                                          NULL, &addend) > 0))
+         {
+           __libdw_seterrno (DWARF_E_INVALID_DWARF);
+           return true;
+         }
+      }
+    else
+      /* The address is relative to the base address relocation.  */
+      reloc->valp = basep->valp;
+
+    reloc->adjust = addend;
+
+    return false;
+  }
+
+  inline ptrdiff_t finalize (unsigned int width)
+  {
+    if (finalize_reloc (startp, width) || finalize_reloc (endp, width))
+      return -1;
+    return readp - (unsigned char *) cu->dbg->sectiondata[sec_idx]->d_buf;
+  }
+
+#define READ_RANGES(AS, Addr, READ)                                          \
+  while (likely (readendp - readp >= 2 * AS))                                \
+    {                                                                        \
+      Addr begin = READ (readp);                                             \
+                                                                             \
+      if (begin == (Addr) -1)                                                \
+       {                                                                     \
+         /* If this is unrelocated, this is a base address entry.  */        \
+         int result = __libdw_relocatable (cu->dbg, sec_idx, readp, AS,      \
+                                           NULL, NULL);                      \
+         if (unlikely (result < 0)) /* Indigestion.  */                      \
+           return -1;                                                        \
+         if (result == 0)      /* Not relocatable. */                        \
+           {                                                                 \
+             readp += AS;                                                    \
+             store (basep, AS);                                              \
+             continue;                                                       \
+           }                                                                 \
+       }                                                                     \
+      else if (begin == 0 && READ (readp + AS) == 0)                         \
+       {                                                                     \
+         /* If these are both unrelocated, this is the end of list entry.  */\
+         int result = __libdw_relocatable (cu->dbg, sec_idx, readp, AS,      \
+                                           NULL, NULL);                      \
+         if (result == 0)              /* Not relocatable. */                \
+           result = __libdw_relocatable (cu->dbg, sec_idx, readp + AS, AS,   \
+                                         NULL, NULL);                        \
+         if (unlikely (result < 0))    /* Indigestion.  */                   \
+           return -1;                                                        \
+         if (result == 0)      /* Not relocatable: end of list entry.  */    \
+           return 0;                                                         \
+       }                                                                     \
+                                                                             \
+      /* This is a pair of addresses.  */                                    \
+      store (startp, AS);                                                    \
+      store (endp, AS);                                                              \
+                                                                             \
+      if (exprloc != NULL)                                                   \
+       {                                                                     \
+         if (unlikely (readendp - readp < 2))                                \
+           break;                                                            \
+         exprloc->length = read_2ubyte_unaligned_inc (cu->dbg, readp);       \
+         if (unlikely ((size_t) (readendp - readp) < exprloc->length))       \
+           break;                                                            \
+         exprloc->data = readp;                                              \
+       }                                                                     \
+                                                                             \
+      return finalize (AS);                                                  \
+    }
+
+  if (cu->address_size == 8)
+    READ_RANGES (8, Elf64_Addr, read_8ubyte_unaligned_noncvt)
+  else
+    READ_RANGES (4, Elf32_Addr, read_4ubyte_unaligned_noncvt)
+
+  __libdw_seterrno (DWARF_E_INVALID_DWARF);
+  return -1;
+}
+
+ptrdiff_t
+dwarf_ranges_relocatable (Dwarf_Die *die, ptrdiff_t offset,
+                         Dwarf_Relocatable *basep,
+                         Dwarf_Relocatable *startp, Dwarf_Relocatable *endp)
+{
+  if (die == NULL)
+    return -1;
+
+  if (offset != 0)
+    /* Iterate from last position.  */
+    return __libdw_ranges_relocatable (die->cu, NULL, offset,
+                                      basep, startp, endp, NULL);
+
+  Dwarf_Attribute attr_mem;
+
+  /* Usually there is a single contiguous range.  */
+  if (INTUSE(dwarf_form_relocatable) (INTUSE(dwarf_attr) (die,
+                                                         DW_AT_high_pc,
+                                                         &attr_mem),
+                                     endp) == 0
+      && INTUSE(dwarf_form_relocatable) (INTUSE(dwarf_attr) (die,
+                                                            DW_AT_low_pc,
+                                                            &attr_mem),
+                                        startp) == 0)
+    /* A offset into .debug_ranges will never be 1, it must be at least a
+       multiple of 4.  So we can return 1 as a special case value to mark
+       there are no ranges to look for on the next call.  */
+    return 1;
+
+  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem);
+  if (attr == NULL)
+    /* No PC attributes in this DIE at all, so an empty range list.  */
+    return 0;
+
+  return __libdw_ranges_relocatable (die->cu, attr, 0,
+                                    basep, startp, endp, NULL);
+}
+INTDEF (dwarf_ranges_relocatable)
index 67b28f512060a355d74ab65b10415d6a7f9297d1..c1ad305278f13ae18e14bd2edbe465f6ba8f1dc4 100644 (file)
 # include <config.h>
 #endif
 
-#include "libdwP.h"
+#include "relocate.h"
 #include <dwarf.h>
 
+
 static int
 relocatable_form (struct Dwarf_CU *cu,
                  unsigned int sec_idx,
@@ -67,24 +68,33 @@ relocatable_form (struct Dwarf_CU *cu,
   switch (form)
     {
     default:
-      /* This can't be relocatable.  We'll let __libdw_relocatable
-        fill in the SHN_ABS indicator for the constant 0 base.  */
+      /* This can't be relocatable.  */
       if (addend != NULL)
        {
-         Dwarf_Attribute attr =
+         if (valp == NULL)
+           *addend = 0;
+         else
            {
-             .cu = cu,
-             .form = form,
-             .valp = (unsigned char *) valp
-           };
-         if (INTUSE(dwarf_formsdata) (&attr, addend))
-           return -1;
-         *addend += adjust;
-         addend = NULL;
+             Dwarf_Attribute attr =
+               {
+                 .cu = cu,
+                 .form = form,
+                 .valp = (unsigned char *) valp
+               };
+             if (INTUSE(dwarf_formsdata) (&attr, addend))
+               return -1;
+           }
        }
-      width = 0;
-      valp = NULL;
-      break;
+    noreloc:
+      if (addend != NULL)
+       *addend += adjust;
+      if (sym != NULL)
+       *sym = (GElf_Sym) { .st_shndx = SHN_ABS };
+      if (name != NULL)
+       *name = NULL;
+      if (secname != NULL)
+       *secname = NULL;
+      return 0;
 
     case DW_FORM_addr:
       width = cu->address_size;
@@ -99,10 +109,63 @@ relocatable_form (struct Dwarf_CU *cu,
       break;
     }
 
-  return __libdw_relocatable (cu->dbg, sec_idx, valp, width,
-                             sym, name, addend, adjust, secname);
+  int symndx;
+  int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
+                                   &symndx, addend);
+  if (result == 0)
+    goto noreloc;
+  else if (likely (result > 0))
+    {
+      struct dwarf_section_reloc *r = cu->dbg->relocate->sectionrel[sec_idx];
+      GElf_Sym sym_mem;
+      GElf_Word shndx;
+      if (sym == NULL)
+       sym = &sym_mem;
+
+      if (unlikely (gelf_getsymshndx (r->symdata, r->symxndxdata,
+                                     symndx, sym, &shndx) == NULL))
+       {
+         __libdw_seterrno (DWARF_E_RELBADSYM);
+         return -1;
+       }
+
+      if (name != NULL)
+       {
+         if (sym->st_name == 0)
+           *name = NULL;
+         else if (unlikely (sym->st_name >= r->symstrdata->d_size))
+           {
+             __libdw_seterrno (DWARF_E_RELBADSYM);
+             return -1;
+           }
+         else
+           *name = (const char *) r->symstrdata->d_buf + sym->st_name;
+       }
+
+      if (addend != NULL)
+       *addend += adjust;
+
+      result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
+               : sym->st_shndx == SHN_XINDEX ? shndx : SHN_UNDEF);
+
+      if (secname != NULL)
+       {
+         Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
+         size_t shstrndx;
+         GElf_Shdr shdr;
+         if (result == 0
+             || elf_getshdrstrndx (symelf, &shstrndx) < 0
+             || gelf_getshdr (elf_getscn (symelf, result), &shdr) == NULL)
+           *secname = NULL;
+         else
+           *secname = elf_strptr (symelf, shstrndx, shdr.sh_name);
+       }
+    }
+
+  return result;
 }
 
+
 int
 dwarf_relocatable_info (reloc, sym, name, addend, secname)
      Dwarf_Relocatable *reloc;
@@ -118,6 +181,7 @@ dwarf_relocatable_info (reloc, sym, name, addend, secname)
                           reloc->form, reloc->valp, reloc->adjust,
                           sym, name, addend, secname);
 }
+INTDEF (dwarf_relocatable_info)
 
 #if 0
 /* Shorthand for dwarf_relocatable_info(dwarf_form_relocatable).  */
index f55be48a419c31bd9605cc255b2e2dc7c2180155..3cac5bd7ff13ca5827cd3323459b01a9103e17a5 100644 (file)
@@ -501,6 +501,9 @@ extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
    0 if not, or -1 for errors.  */
 extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
 
+/* Like dwarf_haspc, but for a relocatable address.  */
+extern int dwarf_haspc_relocatable (Dwarf_Die *die, Dwarf_Relocatable *pc);
+
 /* Enumerate the PC address ranges covered by this DIE, covering all
    addresses where dwarf_haspc returns true.  In the first call OFFSET
    should be zero and *BASEP need not be initialized.  Returns -1 for
@@ -510,7 +513,16 @@ extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
    *STARTP and *ENDP with a contiguous address range.  */
 extern ptrdiff_t dwarf_ranges (Dwarf_Die *die,
                               ptrdiff_t offset, Dwarf_Addr *basep,
-                              Dwarf_Addr *startp, Dwarf_Addr *endp);
+                              Dwarf_Addr *startp, Dwarf_Addr *endp)
+  __nonnull_attribute__ (3, 4, 5);
+
+/* Like dwarf_ranges, but with relocatable addresses.  */
+extern ptrdiff_t dwarf_ranges_relocatable (Dwarf_Die *die,
+                                          ptrdiff_t offset,
+                                          Dwarf_Relocatable *basep,
+                                          Dwarf_Relocatable *startp,
+                                          Dwarf_Relocatable *endp)
+  __nonnull_attribute__ (3, 4, 5);
 
 
 /* Return byte size attribute of DIE.  */
@@ -698,6 +710,19 @@ extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
                                   Dwarf_Op **exprs, size_t *exprlens,
                                   size_t nlocs);
 
+/* Enumerate the locations in a location list.
+   The interface is as for dwarf_ranges_relocatable, above,
+   but also fills in *EXPR and *EXPRLEN as for dwarf_getlocation.  */
+extern ptrdiff_t dwarf_getlocation_relocatable (Dwarf_Attribute *attr,
+                                               ptrdiff_t offset,
+                                               Dwarf_Relocatable *basep,
+                                               Dwarf_Relocatable *startp,
+                                               Dwarf_Relocatable *endp,
+                                               Dwarf_Op **expr,
+                                               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.  */
index ff530702ebf167d9c109b78b12a35258134f7f18..1c3e1c30f3a60a540f71171d5eb0663a87412e40 100644 (file)
@@ -254,5 +254,8 @@ ELFUTILS_0.149 {
   global:
     dwarf_form_relocatable;
     dwarf_line_relocatable;
+    dwarf_getlocation_relocatable;
+    dwarf_haspc_relocatable;
+    dwarf_ranges_relocatable;
     dwarf_relocatable_info;
 } ELFUTILS_0.148;
index 017920e9af8515afb62977f64507d4fe68442419..c970c9aed4c124e006f9e2ba6c45bebbdcc1aaa4 100644 (file)
@@ -480,6 +480,10 @@ extern int __libdw_intern_expression (Dwarf *dbg,
                                      int sec_index)
   __nonnull_attribute__ (5, 6, 9, 10) internal_function;
 
+extern int __libdw_getlocation (Dwarf_Attribute *attr, const Dwarf_Block *block,
+                               Dwarf_Op **llbuf, size_t *listlen, int sec_idx)
+  __nonnull_attribute__ (2, 3, 4) internal_function;
+
 
 /* Return error code of last failing function call.  This value is kept
    separately for each thread.  */
@@ -619,13 +623,6 @@ __libdw_read_offset (Dwarf *dbg,
                                  ret, sec_ret, size);
 }
 
-extern int __libdw_relocatable (Dwarf *dbg, int sec_idx,
-                               const unsigned char *valp, unsigned int width,
-                               GElf_Sym *sym, const char **name,
-                               GElf_Sxword *addend, GElf_Sxword offset,
-                               const char **secname)
-  __nonnull_attribute__ (1) internal_function;
-
 
 static inline size_t
 cu_sec_idx (struct Dwarf_CU *cu)
@@ -674,6 +671,7 @@ INTDECL (dwarf_formref_die)
 INTDECL (dwarf_formsdata)
 INTDECL (dwarf_formstring)
 INTDECL (dwarf_formudata)
+INTDECL (dwarf_form_relocatable)
 INTDECL (dwarf_getarange_addr)
 INTDECL (dwarf_getarangeinfo)
 INTDECL (dwarf_getaranges)
@@ -688,6 +686,8 @@ INTDECL (dwarf_nextcu)
 INTDECL (dwarf_next_unit)
 INTDECL (dwarf_offdie)
 INTDECL (dwarf_ranges)
+INTDECL (dwarf_ranges_relocatable)
+INTDECL (dwarf_relocatable_info)
 INTDECL (dwarf_siblingof)
 INTDECL (dwarf_srclang)
 INTDECL (dwarf_tag)
index e2946b92a135f8acdb769c330ada112fc2f41f4e..181bcdeb71148a74613b2d7e926c7651a1882728 100644 (file)
@@ -168,6 +168,8 @@ __libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
    ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))                        \
    : *((const int32_t *) (Addr)))
 
+# define read_8ubyte_unaligned_noncvt(Addr) \
+   *((const uint64_t *) (Addr))
 # define read_8ubyte_unaligned(Dbg, Addr) \
   (unlikely ((Dbg)->other_byte_order)                                        \
    ? bswap_64 (*((const uint64_t *) (Addr)))                                 \
@@ -243,6 +245,12 @@ read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
   return up->s4;
 }
 
+static inline uint64_t
+read_8ubyte_unaligned_noncvt (const void *p)
+{
+  const union unaligned *up = p;
+  return up->u8;
+}
 static inline uint64_t
 read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
 {
index 195687390d9540af018cf8433da5b539d6231e65..2a38e51c0ecd188f1ee4c32f5be5f863cc93f527 100644 (file)
 # include <config.h>
 #endif
 
-#include "libdwP.h"
-#include "../libelf/libelfP.h"
+#include "relocate.h"
 #include "../libebl/libebl.h"
 #include <dwarf.h>
 #include <assert.h>
 #include <stdlib.h>
 
 
-struct dwarf_reloc_table
-{
-  size_t n;                    /* Number of elements in this table.  */
-  const unsigned char **datum; /* Sorted pointers into section data.  */
-  int *symndx;                 /* Corresponding symtab indices.  */
-  size_t hint;                 /* Index of last search.  */
-};
-
-struct dwarf_section_reloc
-{
-  /* This is set only in the laziest state from startup: the reloc
-     section needs to be examined, and the rest is uninitialized.
-     When this is cleared, the rest is initialized and safe to use.  */
-  Elf_Scn *scn;
-
-  Elf_Data *symdata;
-  Elf_Data *symstrdata;
-  Elf_Data *symxndxdata;
-
-  /* Two tables of predigested relocations, segregated by size.  */
-  struct dwarf_reloc_table rel4;
-  struct dwarf_reloc_table rel8;
-
-  /* For SHT_RELA, a parallel table of addends.
-     For SHT_REL, these are null.  */
-  Elf32_Sword *rela4;
-  Elf64_Sxword *rela8;
-};
-
 static int
 internal_function
 noresolve_symbol (bool undef,
@@ -424,13 +394,25 @@ find_reloc (struct dwarf_reloc_table *table, const unsigned char *datum)
   return -1;
 }
 
-static int
-relocatable_datum (Dwarf *dbg, int sec_index, struct dwarf_section_reloc *r,
-                  const unsigned char *datum, int width,
-                  int *symndx, GElf_Sxword *addend)
+int
+internal_function
+__libdw_relocatable (Dwarf *dbg, int sec_index,
+                    const unsigned char *datum, int width,
+                    int *symndx, GElf_Sxword *addend)
 {
+  if (dbg->relocate == NULL)
+    {
+    noreloc:
+      if (addend != NULL)
+       *addend = (width == 8
+                  ? read_8ubyte_unaligned (dbg, datum)
+                  : read_4ubyte_unaligned (dbg, datum));
+      return 0;
+    }
+
+  struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
   if (r == NULL)
-    return 0;
+    goto noreloc;
 
   if (r->scn != NULL)
     {
@@ -446,7 +428,8 @@ relocatable_datum (Dwarf *dbg, int sec_index, struct dwarf_section_reloc *r,
   if (width == 4)
     {
       i = find_reloc (&r->rel4, datum);
-      *symndx = i < 0 ? STN_UNDEF : r->rel4.symndx[i];
+      if (symndx != NULL)
+       *symndx = i < 0 ? STN_UNDEF : r->rel4.symndx[i];
       if (addend != NULL)
        *addend = ((i < 0 || r->rela4 == NULL)
                   ? read_4sbyte_unaligned (dbg, datum) : r->rela4[i]);
@@ -456,7 +439,8 @@ relocatable_datum (Dwarf *dbg, int sec_index, struct dwarf_section_reloc *r,
       assert (width == 8);
 
       i = find_reloc (&r->rel8, datum);
-      *symndx = i < 0 ? STN_UNDEF : r->rel8.symndx[i];
+      if (symndx != NULL)
+       *symndx = i < 0 ? STN_UNDEF : r->rel8.symndx[i];
       if (addend != NULL)
        *addend = ((i < 0 || r->rela8 == NULL)
                   ? read_8sbyte_unaligned (dbg, datum) : r->rela8[i]);
@@ -483,16 +467,16 @@ internal_function
 __libdw_relocate_address (Dwarf *dbg, int sec_index,
                          const void *datum, int width, Dwarf_Addr *val)
 {
-  struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
   int symndx;
   GElf_Sxword addend;
-  int result = relocatable_datum (dbg, sec_index, r, datum, width,
-                                 &symndx, &addend);
+  int result = __libdw_relocatable (dbg, sec_index, datum, width,
+                                   &symndx, &addend);
   if (result > 0 && symndx != STN_UNDEF)
     {
       GElf_Sym sym;
       GElf_Word shndx;
-      result = reloc_getsym (r, symndx, &sym, &shndx);
+      result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+                            symndx, &sym, &shndx);
       if (result > 0)
        {
          result = (*dbg->relocate->resolve_symbol)
@@ -512,16 +496,16 @@ internal_function
 __libdw_relocate_offset (Dwarf *dbg, int sec_index,
                         const void *datum, int width, Dwarf_Off *val)
 {
-  struct dwarf_section_reloc *const r = dbg->relocate->sectionrel[sec_index];
   int symndx;
   GElf_Sxword addend;
-  int result = relocatable_datum (dbg, sec_index, r, datum, width,
-                                 &symndx, &addend);
+  int result = __libdw_relocatable (dbg, sec_index, datum, width,
+                                   &symndx, &addend);
   if (result > 0 && symndx != STN_UNDEF)
     {
       GElf_Sym sym;
       GElf_Word shndx;
-      result = reloc_getsym (r, symndx, &sym, &shndx);
+      result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+                            symndx, &sym, &shndx);
       if (result > 0)
        {
          if (unlikely (sym.st_shndx == SHN_UNDEF)
@@ -544,72 +528,3 @@ __libdw_relocate_offset (Dwarf *dbg, int sec_index,
     *val = addend;
   return result;
 }
-\f
-int
-internal_function
-__libdw_relocatable (Dwarf *dbg, int sec_idx,
-                    const unsigned char *valp, unsigned int width,
-                    GElf_Sym *sym, const char **name, GElf_Sxword *addend,
-                    GElf_Sxword offset, const char **secname)
-{
-  struct dwarf_section_reloc *const r = ((valp != NULL && dbg->relocate != NULL)
-                                        ? dbg->relocate->sectionrel[sec_idx]
-                                        : NULL);
-  int symndx;
-  int result = relocatable_datum (dbg, sec_idx, r, valp, width,
-                                 &symndx, addend);
-  if (result == 0)
-    {
-      if (sym != NULL)
-       *sym = (GElf_Sym) { .st_shndx = SHN_ABS };
-      if (name != NULL)
-       *name = NULL;
-      if (addend != NULL)
-       *addend = offset + (width == 8
-                           ? read_8ubyte_unaligned (dbg, valp)
-                           : read_4ubyte_unaligned (dbg, valp));
-      if (secname != NULL)
-       *secname = NULL;
-    }
-  else if (likely (result > 0))
-    {
-      GElf_Sym sym_mem;
-      GElf_Word shndx;
-      if (sym == NULL)
-       sym = &sym_mem;
-      result = reloc_getsym (r, symndx, sym, &shndx);
-      if (likely (result > 0))
-       {
-         if (name != NULL)
-           {
-             if (sym->st_name == 0)
-               *name = NULL;
-             else if (unlikely (sym->st_name >= r->symstrdata->d_size))
-               {
-                 __libdw_seterrno (DWARF_E_RELBADSYM);
-                 return -1;
-               }
-             else
-               *name = (const char *) r->symstrdata->d_buf + sym->st_name;
-           }
-         if (addend != NULL)
-           *addend += offset;
-         result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
-                   : sym->st_shndx == SHN_XINDEX ? shndx : SHN_UNDEF);
-         if (secname != NULL)
-           {
-             Elf *symelf = ((Elf_Data_Scn *) r->symdata)->s->elf;
-             size_t shstrndx;
-             GElf_Shdr shdr;
-             if (result == 0
-                 || elf_getshdrstrndx (symelf, &shstrndx) < 0
-                 || gelf_getshdr (elf_getscn (symelf, result), &shdr) == NULL)
-               *secname = NULL;
-             else
-               *secname = elf_strptr (symelf, shstrndx, shdr.sh_name);
-           }
-       }
-    }
-
-  return result;
-}
diff --git a/libdw/relocate.h b/libdw/relocate.h
new file mode 100644 (file)
index 0000000..eaf8e62
--- /dev/null
@@ -0,0 +1,96 @@
+/* Internal definitions for libdw relocation handling.
+   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>.  */
+
+#include "libdwP.h"
+#include "libelfP.h"
+
+
+struct dwarf_reloc_table
+{
+  size_t n;                    /* Number of elements in this table.  */
+  const unsigned char **datum; /* Sorted pointers into section data.  */
+  int *symndx;                 /* Corresponding symtab indices.  */
+  size_t hint;                 /* Index of last search.  */
+};
+
+struct dwarf_section_reloc
+{
+  /* This is set only in the laziest state from startup: the reloc
+     section needs to be examined, and the rest is uninitialized.
+     When this is cleared, the rest is initialized and safe to use.  */
+  Elf_Scn *scn;
+
+  Elf_Data *symdata;
+  Elf_Data *symstrdata;
+  Elf_Data *symxndxdata;
+
+  /* Two tables of predigested relocations, segregated by size.  */
+  struct dwarf_reloc_table rel4;
+  struct dwarf_reloc_table rel8;
+
+  /* For SHT_RELA, a parallel table of addends.
+     For SHT_REL, these are null.  */
+  Elf32_Sword *rela4;
+  Elf64_Sxword *rela8;
+};
+
+
+extern int __libdw_relocatable (Dwarf *dbg, int sec_index,
+                               const unsigned char *datum, int width,
+                               int *symndx, GElf_Sxword *addend)
+  __nonnull_attribute__ (1) internal_function;
+
+extern ptrdiff_t __libdw_ranges_relocatable (struct Dwarf_CU *cu,
+                                            Dwarf_Attribute *attr,
+                                            ptrdiff_t offset,
+                                            Dwarf_Relocatable *basep,
+                                            Dwarf_Relocatable *startp,
+                                            Dwarf_Relocatable *endp,
+                                            Dwarf_Block *exprloc)
+  __nonnull_attribute__ (1, 4, 5, 6) internal_function;