]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Rejigger relocatable Dwarf_Line in a sort-friendly way.
authorRoland McGrath <roland@redhat.com>
Tue, 29 Jun 2010 06:23:05 +0000 (23:23 -0700)
committerRoland McGrath <roland@redhat.com>
Tue, 29 Jun 2010 06:23:05 +0000 (23:23 -0700)
libdw/ChangeLog
libdw/dwarf_getsrclines.c
libdw/dwarf_line_relocatable.c
libdw/dwarf_lineaddr.c
libdw/dwarf_relocatable_info.c
libdw/libdw.h
libdw/libdwP.h
libdw/relocate.c
libdw/relocate.h

index 7223eb7db7f659dc007c99ef9e890041fd96c0b8..70e46a16e9b90385ab0fe475ff6ce4c8b4e8c4f1 100644 (file)
@@ -1,3 +1,24 @@
+2010-06-28  Roland McGrath  <roland@redhat.com>
+
+       * libdwP.h (struct Dwarf_Lines_s): Change reloc member to int pointer.
+       * dwarf_getsrclines.c (struct linelist): Add reloc/symndx/shndx members.
+       (compare_lines): Sort by shndx before line.addr.
+       (dwarf_getsrclines): Resolve relocatable addresses to a symndx and
+       section-relative address.
+       * dwarf_line_relocatable.c: Initialize symndx instead of valp.
+       * dwarf_lineaddr.c: Use __libdw_relocate_shndx
+
+       * relocate.c (__libdw_relocatable_getsym): New function.
+       (__libdw_relocate_address, __libdw_relocate_offset): Call it.
+       (__libdw_relocate_shndx): New function.
+       * relocate.h: Declare them.
+
+       * libdw.h (Dwarf_Relocatable): Use uint8_t for sec and form members.
+       Add symndx member.
+       * dwarf_relocatable_info.c (relocatable_form): Take new arg SYMNDX.
+       If VALP is null, use SYMNDX instead of looking for a reloc.
+       (dwarf_relocatable_info): Update caller.
+
 2010-06-24  Roland McGrath  <roland@redhat.com>
 
        * encoded-value.h (encoded_value_size): Replace E_IDENT parameter
index aefa8d32daa9b51125d58deee055e9d327066b99..f15b4410c793a2206e8b46d04b4a41ab3f192ad3 100644 (file)
 # include <config.h>
 #endif
 
+#include "relocate.h"
+#include <dwarf.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include "dwarf.h"
-#include "libdwP.h"
 
 
 struct filelist
@@ -68,7 +68,15 @@ struct filelist
 struct linelist
 {
   Dwarf_Line line;
-  const unsigned char *reloc;
+  union
+  {
+    const unsigned char *reloc;
+    struct
+    {
+      int symndx;
+      int shndx;
+    };
+  };
   struct linelist *next;
 };
 
@@ -77,14 +85,23 @@ struct linelist
 static int
 compare_lines (const void *a, const void *b)
 {
-  Dwarf_Line *const *p1 = a;
-  Dwarf_Line *const *p2 = b;
+  struct linelist *const *p1 = a;
+  struct linelist *const *p2 = b;
+
+  int result = (*p1)->shndx - (*p2)->shndx;
+  if (result != 0)
+    return result;
 
-  if ((*p1)->addr == (*p2)->addr)
+  if ((*p1)->line.addr == (*p2)->line.addr)
     /* An end_sequence marker precedes a normal record at the same address.  */
-    return (*p2)->end_sequence - (*p1)->end_sequence;
+    return (*p2)->line.end_sequence - (*p1)->line.end_sequence;
 
-  return (*p1)->addr - (*p2)->addr;
+  if ((*p1)->line.addr > (*p2)->line.addr)
+    return 1;
+  if ((*p1)->line.addr < (*p2)->line.addr)
+    return -1;
+
+  return 0;
 }
 
 int
@@ -726,8 +743,69 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
         ascending addresses.  So fill from the back to probably start with
         runs already in order before we sort.  */
       unsigned int i = nlinelist;
+      addr_reloc = NULL;
+      int reloc_symndx = STN_UNDEF;
+      int reloc_shndx = 0;
+      GElf_Sxword reloc_value = 0;
       while (i-- > 0)
        {
+         if (linelist->reloc == NULL)
+           {
+             assert (linelist->symndx == STN_UNDEF);
+             assert (linelist->shndx == 0);
+           }
+         else
+           {
+             /* A relocatable address in line information must be
+                a defined symbol.  So we can reduce it immediately
+                to a section index.  */
+
+             if (linelist->reloc != addr_reloc)
+               {
+                 addr_reloc = linelist->reloc;
+
+                 GElf_Sym sym;
+                 GElf_Word shndx;
+                 int result = __libdw_relocatable_getsym (cu->dbg,
+                                                          IDX_debug_line,
+                                                          addr_reloc,
+                                                          cu->address_size,
+                                                          &reloc_symndx,
+                                                          &sym, &shndx,
+                                                          &reloc_value);
+                 if (unlikely (result < 0))
+                   {
+                     res = -1;
+                     goto out;
+                   }
+                 if (result == 0)
+                   reloc_symndx = STN_UNDEF;
+                 if (reloc_symndx == STN_UNDEF)
+                   reloc_shndx = 0;
+                 else
+                   {
+                     reloc_value += sym.st_value;
+                     if (likely (sym.st_shndx < SHN_LORESERVE)
+                         && likely (sym.st_shndx != SHN_UNDEF))
+                       reloc_shndx = sym.st_shndx;
+                     else if (sym.st_shndx == SHN_ABS)
+                       reloc_shndx = 0;
+                     else if (sym.st_shndx == SHN_XINDEX)
+                       reloc_shndx = shndx;
+                     else
+                       {
+                         __libdw_seterrno (DWARF_E_RELOC);
+                         res = -1;
+                         goto out;
+                       }
+                   }
+               }
+
+             linelist->symndx = reloc_symndx;
+             linelist->shndx = reloc_shndx;
+             linelist->line.addr += reloc_value;
+           }
+
          sortlines[i] = linelist;
          linelist = linelist->next;
        }
@@ -746,11 +824,13 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
          && cu->dbg->relocate->sectionrel[IDX_debug_line] != NULL)
        {
          /* Add a parallel table of relocation pointers.  */
-         cu->lines->reloc = libdw_alloc (cu->dbg, const unsigned char *,
-                                         sizeof (const unsigned char *),
-                                         nlinelist);
+         cu->lines->reloc = libdw_alloc (cu->dbg, int, sizeof (int),
+                                         2 * nlinelist);
          for (i = 0; i < nlinelist; ++i)
-           cu->lines->reloc[i] = sortlines[i]->reloc;
+           {
+             cu->lines->reloc[i * 2] = sortlines[i]->symndx;
+             cu->lines->reloc[i * 2 + 1] = sortlines[i]->shndx;
+           }
        }
       else
        cu->lines->reloc = NULL;
index a57422e96fd23891f23953cd9f5ad563a73e10f6..d53644b707efe379d12fe0f442ad9f847119464e 100644 (file)
@@ -63,12 +63,14 @@ dwarf_line_relocatable (line, reloc)
   if (line == NULL)
     return -1;
 
+  const int *const linerel = line->cu->lines->reloc;
+  const size_t idx = line - line->cu->lines->info;
+
   *reloc = (Dwarf_Relocatable)
     {
       .sec = IDX_debug_line, .form = DW_FORM_addr,
       .cu = line->cu,
-      .valp = (line->cu->lines->reloc == NULL ? NULL
-              : line->cu->lines->reloc[line - line->cu->lines->info]),
+      .symndx = linerel == NULL ? STN_UNDEF : linerel[idx * 2],
       .adjust = line->addr
     };
 
index 7bfefd6cc4f705f2dacd49e25f90ed47b2a61962..1e0b3234303e128015d9407bbf876f3f3ce31a72 100644 (file)
@@ -53,6 +53,7 @@
 #endif
 
 #include "libdwP.h"
+#include "relocate.h"
 
 
 int
@@ -61,22 +62,18 @@ dwarf_lineaddr (Dwarf_Line *line, Dwarf_Addr *addrp)
   if (line == NULL)
     return -1;
 
-  if (line->cu->lines->reloc == NULL
-      || line->cu->lines->reloc[line - line->cu->lines->info] == NULL)
+  const int *const reloc = line->cu->lines->reloc;
+  const size_t idx = line - line->cu->lines->info;
+
+  if (reloc == NULL || reloc[idx * 2] == STN_UNDEF)
     {
       *addrp = line->addr;
       return 0;
     }
 
-  /* We have to relocate an address and then adjust it for this line record.  */
-
-  int result = __libdw_read_address
-    (line->cu->dbg, IDX_debug_line,
-     line->cu->lines->reloc[line - line->cu->lines->info],
-     line->cu->address_size, addrp);
-
-  if (result >= 0)
-    *addrp += line->addr;
+  /* We have already reduced this relocatable address to a section offset.
+     We just have to resolve the section address.  */
 
-  return result;
+  return __libdw_relocate_shndx (line->cu->dbg,
+                                reloc[idx * 2 + 1], line->addr, addrp);
 }
index c1ad305278f13ae18e14bd2edbe465f6ba8f1dc4..f4260e7729ba5b96d733967cf70a9b70d5c8be98 100644 (file)
 
 static int
 relocatable_form (struct Dwarf_CU *cu,
-                 unsigned int sec_idx,
-                 unsigned int form,
+                 uint_fast8_t sec_idx,
+                 uint_fast8_t form,
                  const unsigned char *valp,
+                 int symndx,
                  Dwarf_Addr adjust,
                  GElf_Sym *sym, const char **name,
                  GElf_Sxword *addend, const char **secname)
@@ -109,57 +110,66 @@ relocatable_form (struct Dwarf_CU *cu,
       break;
     }
 
-  int symndx;
-  int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
-                                   &symndx, addend);
-  if (result == 0)
-    goto noreloc;
-  else if (likely (result > 0))
+  if (valp != NULL)
     {
-      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))
+      int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
+                                       &symndx, addend);
+      if (unlikely (result < 0))
+       return result;
+      if (result == 0)
+       goto noreloc;
+    }
+
+  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 (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)
+  if (addend != NULL)
+    {
+      if (valp == NULL)
+       /* The ADJUST value was already section-relative, so we have to
+          remove the st_value portion of it.  */
+       *addend = adjust - sym->st_value;
+      else
        *addend += adjust;
+    }
 
-      result = (sym->st_shndx < SHN_LORESERVE ? sym->st_shndx
+  int 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);
-       }
+  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;
@@ -177,8 +187,8 @@ dwarf_relocatable_info (reloc, sym, name, addend, secname)
   if (reloc == NULL)
     return -1;
 
-  return relocatable_form (reloc->cu, reloc->sec,
-                          reloc->form, reloc->valp, reloc->adjust,
+  return relocatable_form (reloc->cu, reloc->sec, reloc->form,
+                          reloc->valp, reloc->symndx, reloc->adjust,
                           sym, name, addend, secname);
 }
 INTDEF (dwarf_relocatable_info)
index 52962b4a05e0a2556649360710b0c5bbc0f8e239..c359e10f2c59cd76997ce9f445042c99a602cc13 100644 (file)
@@ -151,8 +151,9 @@ typedef struct
 /* Relocatable address representation.  */
 typedef struct
 {
-  unsigned int sec;
-  unsigned int form;
+  int symndx;
+  uint8_t sec;
+  uint8_t form;
   const unsigned char *valp;
   struct Dwarf_CU *cu;
   Dwarf_Addr adjust;
index c970c9aed4c124e006f9e2ba6c45bebbdcc1aaa4..f2886028c8f73ce309c6aa632c1a07c33c81be1c 100644 (file)
@@ -280,7 +280,9 @@ struct Dwarf_Line_s
 
 struct Dwarf_Lines_s
 {
-  const unsigned char **reloc;
+  /* If non-null, reloc[i * 2], reloc[i * 2 + 1] are symndx, shndx
+     corresponding to info[i], and info[i].addr is section-relative.  */
+  int *reloc;
   size_t nlines;
   struct Dwarf_Line_s info[0];
 };
index 2a38e51c0ecd188f1ee4c32f5be5f863cc93f527..03671ce44d4b27f345037faed9e098da9a6d8b34 100644 (file)
@@ -462,29 +462,55 @@ reloc_getsym (struct dwarf_section_reloc *r, int symndx,
   return 1;
 }
 
+int
+internal_function
+__libdw_relocatable_getsym (Dwarf *dbg, int sec_index,
+                           const unsigned char *datum, int width,
+                           int *symndx, GElf_Sym *sym, GElf_Word *shndx,
+                           GElf_Sxword *addend)
+{
+  int result = __libdw_relocatable (dbg, sec_index, datum, width,
+                                   symndx, addend);
+  if (result > 0 && *symndx != STN_UNDEF)
+    result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
+                          *symndx, sym, shndx);
+  return result;
+}
+
+int
+internal_function
+__libdw_relocate_shndx (Dwarf *dbg, GElf_Word shndx, GElf_Sxword addend,
+                       Dwarf_Addr *val)
+{
+  GElf_Sym sym =
+    {
+      .st_shndx = shndx < SHN_LORESERVE ? shndx : SHN_XINDEX,
+      .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
+    };
+  int result = (*dbg->relocate->resolve_symbol) (false, dbg, &sym, shndx);
+  if (result == 0)
+    *val = sym.st_value + addend;
+  return result;
+}
+
 int
 internal_function
 __libdw_relocate_address (Dwarf *dbg, int sec_index,
                          const void *datum, int width, Dwarf_Addr *val)
 {
   int symndx;
+  GElf_Sym sym;
+  GElf_Word shndx;
   GElf_Sxword addend;
-  int result = __libdw_relocatable (dbg, sec_index, datum, width,
-                                   &symndx, &addend);
+  int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
+                                          &symndx, &sym, &shndx, &addend);
   if (result > 0 && symndx != STN_UNDEF)
     {
-      GElf_Sym sym;
-      GElf_Word shndx;
-      result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
-                            symndx, &sym, &shndx);
-      if (result > 0)
-       {
-         result = (*dbg->relocate->resolve_symbol)
-           (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
-            || GELF_ST_BIND (sym.st_info) > STB_WEAK,
-            dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx);
-         addend += sym.st_value;
-       }
+      result = (*dbg->relocate->resolve_symbol)
+       (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_COMMON
+        || GELF_ST_BIND (sym.st_info) > STB_WEAK,
+        dbg, &sym, sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx);
+      addend += sym.st_value;
     }
   if (result >= 0)
     *val = addend;
@@ -497,32 +523,27 @@ __libdw_relocate_offset (Dwarf *dbg, int sec_index,
                         const void *datum, int width, Dwarf_Off *val)
 {
   int symndx;
+  GElf_Sym sym;
+  GElf_Word shndx;
   GElf_Sxword addend;
-  int result = __libdw_relocatable (dbg, sec_index, datum, width,
-                                   &symndx, &addend);
+  int result = __libdw_relocatable_getsym (dbg, sec_index, datum, width,
+                                          &symndx, &sym, &shndx, &addend);
   if (result > 0 && symndx != STN_UNDEF)
     {
-      GElf_Sym sym;
-      GElf_Word shndx;
-      result = reloc_getsym (dbg->relocate->sectionrel[sec_index],
-                            symndx, &sym, &shndx);
-      if (result > 0)
+      if (unlikely (sym.st_shndx == SHN_UNDEF)
+         || (sym.st_shndx > SHN_LORESERVE
+             && unlikely (sym.st_shndx != SHN_XINDEX)))
+       {
+         __libdw_seterrno (DWARF_E_RELUNDEF);
+         return -1;
+       }
+      if (unlikely (((Elf_Data_Scn *) dbg->sectiondata[sec_index])->s->index
+                   != (sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx)))
        {
-         if (unlikely (sym.st_shndx == SHN_UNDEF)
-             || (sym.st_shndx > SHN_LORESERVE
-                 && unlikely (sym.st_shndx != SHN_XINDEX)))
-           {
-             __libdw_seterrno (DWARF_E_RELUNDEF);
-             return -1;
-           }
-         if (unlikely (((Elf_Data_Scn *) dbg->sectiondata[sec_index])->s->index
-                       != (sym.st_shndx == SHN_XINDEX ? shndx : sym.st_shndx)))
-           {
-             __libdw_seterrno (DWARF_E_RELWRONGSEC);
-             return -1;
-           }
-         addend += sym.st_value;
+         __libdw_seterrno (DWARF_E_RELWRONGSEC);
+         return -1;
        }
+      addend += sym.st_value;
     }
   if (result >= 0)
     *val = addend;
index eaf8e6285aac85a29db8896bf18127c7d151cc0e..6c9751879b1ca606cb0066284a96350a1b9e804e 100644 (file)
@@ -86,6 +86,17 @@ extern int __libdw_relocatable (Dwarf *dbg, int sec_index,
                                int *symndx, GElf_Sxword *addend)
   __nonnull_attribute__ (1) internal_function;
 
+extern int __libdw_relocatable_getsym (Dwarf *dbg, int sec_index,
+                                      const unsigned char *datum, int width,
+                                      int *symndx, GElf_Sym *sym,
+                                      GElf_Word *shndx, GElf_Sxword *addend)
+  __nonnull_attribute__ (1, 3, 5, 6, 7, 8) internal_function;
+
+extern int __libdw_relocate_shndx (Dwarf *dbg,
+                                  GElf_Word shndx, GElf_Sxword addend,
+                                  Dwarf_Addr *val)
+  __nonnull_attribute__ (1, 4) internal_function;
+
 extern ptrdiff_t __libdw_ranges_relocatable (struct Dwarf_CU *cu,
                                             Dwarf_Attribute *attr,
                                             ptrdiff_t offset,