]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: Add minisymtab support.
authorMark Wielaard <mjw@redhat.com>
Wed, 16 Jan 2013 14:19:32 +0000 (15:19 +0100)
committerMark Wielaard <mjw@redhat.com>
Tue, 22 Jan 2013 15:09:18 +0000 (16:09 +0100)
Add an auxiliary symbol table dwfl_file aux_sym to Dwfl_Module if all we
have is the dynsym table.  The main file might contain a .gnu_debugdata
section. The .gnu_debugdata section is a compressed embedded ELF file
that contains the text (code) section symbols from the symtab table
that are not in the main file dynsym table. dwfl_module_getsymtab (),
dwfl_module_addrsym () and dwfl_module_getsym () will use the auxiliary
symbol table when available (and no full symtab is available from the
debug file).

    * libdwflP.h (struct Dwfl_Module): Add aux_sym, aux_symdata,
    aux_syments, aux_symstrdata, aux_symxndxdata and aux_first_global.
    (dwfl_adjusted_aux_sym_addr): New function.
    (dwfl_deadjust_aux_sym_addr): Likewise.
    (dwfl_adjusted_st_value): Take and check symfile argument.
    (dwfl_deadjust_st_value): Likewise.
    * dwfl_module_getdwarf.c (find_prelink_address_sync): Take and
    use dwfl_file as argument to set address_sync.
    (find_debuginfo): Call find_prelink_address_sync with debug file.
    (find_aux_sym): New function.
    (find_symtab): Use find_aux_sym if all we have is the dynsym table
    and fill in aux DwflModule fields.
    (dwfl_module_getsymtab): Return syments plus aux_syments.
    (load_symtab): Always set first_global.
    * dwfl_module_addrsym.c (dwfl_module_addrsym): Check symfile
    when using same_section. Calculate first_global based on both
    mod->first_global and mod->aux_first_global.
    * dwfl_module.c (__libdwfl_module_free): Free aux_sym.
    * dwfl_module_getsym.c (dwfl_module_getsym): Use auxsym table
    to retrieve symbol and name if necessary, making sure all locals
    from any table come before any globals.
    * dwfl_module_info.c (dwfl_module_info): Call dwfl_adjusted_st_value
    with symfile.
    * relocate.c (resolve_symbol): Likewise.

https://fedoraproject.org/wiki/Features/MiniDebugInfo

Signed-off-by: Mark Wielaard <mjw@redhat.com>
libdwfl/ChangeLog
libdwfl/dwfl_module.c
libdwfl/dwfl_module_addrsym.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsym.c
libdwfl/dwfl_module_info.c
libdwfl/libdwflP.h
libdwfl/relocate.c

index 62973368a3ef0ed30657d35afe4c4ca15ef79ef1..828db083d25d5c2aee804a6b4d31dc003bc2b652 100644 (file)
@@ -1,3 +1,30 @@
+2013-01-16  Mark Wielaard  <mjw@redhat.com>
+
+       * libdwflP.h (struct Dwfl_Module): Add aux_sym, aux_symdata,
+       aux_syments, aux_symstrdata, aux_symxndxdata and aux_first_global.
+       (dwfl_adjusted_aux_sym_addr): New function.
+       (dwfl_deadjust_aux_sym_addr): Likewise.
+       (dwfl_adjusted_st_value): Take and check symfile argument.
+       (dwfl_deadjust_st_value): Likewise.
+       * dwfl_module_getdwarf.c (find_prelink_address_sync): Take and
+       use dwfl_file as argument to set address_sync.
+       (find_debuginfo): Call find_prelink_address_sync with debug file.
+       (find_aux_sym): New function.
+       (find_symtab): Use find_aux_sym if all we have is the dynsym table
+       and fill in aux DwflModule fields.
+       (dwfl_module_getsymtab): Return syments plus aux_syments.
+       (load_symtab): Always set first_global.
+       * dwfl_module_addrsym.c (dwfl_module_addrsym): Check symfile
+       when using same_section. Calculate first_global based on both
+       mod->first_global and mod->aux_first_global.
+       * dwfl_module.c (__libdwfl_module_free): Free aux_sym.
+       * dwfl_module_getsym.c (dwfl_module_getsym): Use auxsym table
+       to retrieve symbol and name if necessary, making sure all locals
+       from any table come before any globals.
+       * dwfl_module_info.c (dwfl_module_info): Call dwfl_adjusted_st_value
+       with symfile.
+       * relocate.c (resolve_symbol): Likewise.
+
 2013-01-07  Roland McGrath  <roland@hack.frob.com>
 
        * link_map.c (auxv_format_probe): Handle unaligned 64-bit data, but
index e703d27ed9d825171c3331db8ed0edb028ea8882..f914b3a392e692e01ca15d0d466cc31e664c58ae 100644 (file)
@@ -79,6 +79,7 @@ __libdwfl_module_free (Dwfl_Module *mod)
   if (mod->debug.elf != mod->main.elf)
     free_file (&mod->debug);
   free_file (&mod->main);
+  free_file (&mod->aux_sym);
 
   if (mod->build_id_bits != NULL)
     free (mod->build_id_bits);
index fdc95fc0c739606b841d98e954ed13abf7b187f4..d2059ea4bf0f93ba1b29382275beb89bead59c38 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2005-2011 Red Hat, Inc.
+   Copyright (C) 2005-2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -41,7 +41,8 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
 
   /* Return true iff we consider ADDR to lie in the same section as SYM.  */
   GElf_Word addr_shndx = SHN_UNDEF;
-  inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
+  inline bool same_section (const GElf_Sym *sym, struct dwfl_file *symfile,
+                           GElf_Word shndx)
     {
       /* For absolute symbols and the like, only match exactly.  */
       if (shndx >= SHN_LORESERVE)
@@ -50,10 +51,10 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
       /* Figure out what section ADDR lies in.  */
       if (addr_shndx == SHN_UNDEF)
        {
-         GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
+         GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, symfile, addr);
          Elf_Scn *scn = NULL;
          addr_shndx = SHN_ABS;
-         while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
+         while ((scn = elf_nextscn (symfile->elf, scn)) != NULL)
            {
              GElf_Shdr shdr_mem;
              GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
@@ -135,7 +136,11 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
                        }
                      else if (closest_name == NULL
                               && sym.st_value >= min_label
-                              && same_section (&sym, shndx))
+                              && same_section (&sym,
+                                               ((size_t) i < mod->syments
+                                                ? mod->symfile
+                                                : &mod->aux_sym),
+                                               shndx))
                        {
                          /* Handwritten assembly symbols sometimes have no
                             st_size.  If no symbol with proper size includes
@@ -168,17 +173,19 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
        }
     }
 
-  /* First go through global symbols.  mod->first_global is setup by
-     dwfl_module_getsymtab to the index of the first global symbol in
-     the module's symbol table, or -1 when unknown.  All symbols with
-     local binding come first in the symbol table, then all globals.  */
-  search_table (mod->first_global < 0 ? 1 : mod->first_global, syments);
+  /* First go through global symbols.  mod->first_global and
+     mod->aux_first_global are setup by dwfl_module_getsymtab to the
+     index of the first global symbol in the module's symbol table.  Both
+     are zero when unknown.  All symbols with local binding come first in
+     the symbol table, then all globals.  */
+  int first_global = mod->first_global + mod->aux_first_global - 1;
+  search_table (first_global < 0 ? 1 : first_global, syments);
 
   /* If we found nothing searching the global symbols, then try the locals.
      Unless we have a global sizeless symbol that matches exactly.  */
-  if (closest_name == NULL && mod->first_global > 1
+  if (closest_name == NULL && first_global > 1
       && (sizeless_name == NULL || sizeless_sym.st_value != addr))
-    search_table (1, mod->first_global);
+    search_table (1, first_global);
 
   /* If we found no proper sized symbol to use, fall back to the best
      candidate sizeless symbol we found, if any.  */
index 025cb8ac894781a37cfe2ea6424b8c1934b4d0f1..ffbe5898120aa1336eea76369705188d0d71a7a4 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2005-2011 Red Hat, Inc.
+   Copyright (C) 2005-2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <unistd.h>
 #include "../libdw/libdwP.h"   /* DWARF_E_* values are here.  */
+#include "../libelf/libelfP.h"
 
 
 /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
@@ -285,7 +286,7 @@ find_debuglink (Elf *elf, GElf_Word *crc)
    looked like before prelink juggled them--when they still had a
    direct correspondence to the debug file.  */
 static Dwfl_Error
-find_prelink_address_sync (Dwfl_Module *mod)
+find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
 {
   /* The magic section is only identified by name.  */
   size_t shstrndx;
@@ -512,8 +513,8 @@ find_prelink_address_sync (Dwfl_Module *mod)
          consider_shdr (undo_interp, shdr.s64[i].sh_type, shdr.s64[i].sh_flags,
                         shdr.s64[i].sh_addr, shdr.s64[i].sh_size);
 
-      if (highest > mod->debug.vaddr)
-       mod->debug.address_sync = highest;
+      if (highest > file->vaddr)
+       file->address_sync = highest;
       else
        return DWFL_E_BAD_PRELINK;
     }
@@ -539,7 +540,7 @@ find_debuginfo (Dwfl_Module *mod)
                                                           &mod->debug.name);
   Dwfl_Error result = open_elf (mod, &mod->debug);
   if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
-    result = find_prelink_address_sync (mod);
+    result = find_prelink_address_sync (mod, &mod->debug);
   return result;
 }
 
@@ -579,6 +580,7 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
            *symfile = file;
            *strshndx = shdr->sh_link;
            *syments = shdr->sh_size / shdr->sh_entsize;
+           *first_global = shdr->sh_info;
            break;
 
          case SHT_SYMTAB_SHNDX:
@@ -814,6 +816,135 @@ find_dynsym (Dwfl_Module *mod)
     }
 }
 
+/* Try to find the auxiliary symbol table embedded in the main elf file
+   section .gnu_debugdata.  Only matters if the symbol information comes
+   from the main file dynsym.  No harm done if not found.  */
+static void
+find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
+             Elf_Scn **aux_symscn __attribute__ ((unused)),
+             Elf_Scn **aux_xndxscn __attribute__ ((unused)),
+             GElf_Word *aux_strshndx __attribute__ ((unused)))
+{
+  /* Since a .gnu_debugdata section is compressed using lzma don't do
+     anything unless we have support for that.  */
+#if USE_LZMA
+  Elf *elf = mod->main.elf;
+
+  size_t shstrndx;
+  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
+    return;
+
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (shdr == NULL)
+       return;
+
+      const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
+      if (name == NULL)
+       return;
+
+      if (!strcmp (name, ".gnu_debugdata"))
+       break;
+    }
+
+  if (scn == NULL)
+    return;
+
+  /* Found the .gnu_debugdata section.  Uncompress the lzma image and
+     turn it into an ELF image.  */
+  Elf_Data *rawdata = elf_rawdata (scn, NULL);
+  if (rawdata == NULL)
+    return;
+
+  Dwfl_Error error;
+  void *buffer = NULL;
+  size_t size = 0;
+  error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size,
+                         &buffer, &size);
+  if (error == DWFL_E_NOERROR)
+    {
+      if (unlikely (size == 0))
+       free (buffer);
+      else
+       {
+         mod->aux_sym.elf = elf_memory (buffer, size);
+         if (mod->aux_sym.elf == NULL)
+           free (buffer);
+         else
+           {
+             mod->aux_sym.fd = -1;
+             mod->aux_sym.elf->flags |= ELF_F_MALLOCED;
+             if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR)
+               return;
+             /* Don't trust the phdrs in the minisymtab elf file to be
+                setup correctly.  The address_sync is equal to the main
+                file it is embedded in at first.  The shdrs are setup
+                OK to make find_prelink_address_sync () do the right
+                thing if necessary though.  */
+             mod->aux_sym.address_sync = mod->main.address_sync;
+             if (mod->aux_sym.address_sync != 0)
+               {
+                 error = find_prelink_address_sync (mod, &mod->aux_sym);
+                 if (error != DWFL_E_NOERROR)
+                   {
+                     elf_end (mod->aux_sym.elf);
+                     mod->aux_sym.elf = NULL;
+                     return;
+                   }
+               }
+
+             /* So far, so good. Get minisymtab table data and cache it. */
+             bool minisymtab = false;
+             scn = NULL;
+             while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL)
+               {
+                 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
+                 if (shdr != NULL)
+                   switch (shdr->sh_type)
+                     {
+                     case SHT_SYMTAB:
+                       minisymtab = true;
+                       *aux_symscn = scn;
+                       *aux_strshndx = shdr->sh_link;
+                       mod->aux_syments = shdr->sh_size / shdr->sh_entsize - 1;
+                       mod->aux_first_global = shdr->sh_info;
+                       if (*aux_xndxscn != NULL)
+                         return;
+                       break;
+
+                     case SHT_SYMTAB_SHNDX:
+                       *aux_xndxscn = scn;
+                       if (minisymtab)
+                         return;
+                       break;
+
+                     default:
+                       break;
+                     }
+               }
+
+             if (minisymtab)
+               /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
+               return;
+
+             /* We found no SHT_SYMTAB, so everything else is bogus.  */
+             *aux_xndxscn = NULL;
+             *aux_strshndx = 0;
+             mod->aux_syments = 0;
+             elf_end (mod->aux_sym.elf);
+             mod->aux_sym.elf = NULL;
+             return;
+           }
+       }
+    }
+  else
+    free (buffer);
+#endif
+}
+
 /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
 static void
 find_symtab (Dwfl_Module *mod)
@@ -827,11 +958,10 @@ find_symtab (Dwfl_Module *mod)
   if (mod->symerr != DWFL_E_NOERROR)
     return;
 
-  mod->first_global = -1; /* Unknown, unless explicitly set by load_symtab.  */
-
   /* First see if the main ELF file has the debugging information.  */
   Elf_Scn *symscn = NULL, *xndxscn = NULL;
-  GElf_Word strshndx;
+  Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL;
+  GElf_Word strshndx, aux_strshndx = 0;
   mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
                             &xndxscn, &mod->syments, &mod->first_global,
                             &strshndx);
@@ -875,6 +1005,9 @@ find_symtab (Dwfl_Module *mod)
            {
              /* We still have the dynamic symbol table.  */
              mod->symerr = DWFL_E_NOERROR;
+
+             /* The dynsym table might be extended by an auxiliary table.  */
+             find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx);
              break;
            }
 
@@ -890,7 +1023,7 @@ find_symtab (Dwfl_Module *mod)
     {
     elferr:
       mod->symerr = DWFL_E (LIBELF, elf_errno ());
-      return;
+      goto aux_cleanup;
     }
 
   /* Cache the data; MOD->syments and MOD->first_global were set above.  */
@@ -912,6 +1045,39 @@ find_symtab (Dwfl_Module *mod)
   mod->symdata = elf_getdata (symscn, NULL);
   if (mod->symdata == NULL)
     goto elferr;
+
+  /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym.  */
+  if (aux_symscn != NULL)
+    {
+      /* This does some sanity checks on the string table section.  */
+      if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL)
+       {
+       aux_cleanup:
+         mod->aux_syments = 0;
+         elf_end (mod->aux_sym.elf);
+         mod->aux_sym.elf = NULL;
+         return;
+       }
+
+      mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf,
+                                                    aux_strshndx),
+                                        NULL);
+      if (mod->aux_symstrdata == NULL)
+       goto aux_cleanup;
+
+      if (aux_xndxscn == NULL)
+       mod->aux_symxndxdata = NULL;
+      else
+       {
+         mod->aux_symxndxdata = elf_getdata (xndxscn, NULL);
+         if (mod->aux_symxndxdata == NULL)
+           goto aux_cleanup;
+       }
+
+      mod->aux_symdata = elf_getdata (aux_symscn, NULL);
+      if (mod->aux_symdata == NULL)
+       goto aux_cleanup;
+    }
 }
 
 
@@ -1067,7 +1233,7 @@ dwfl_module_getsymtab (Dwfl_Module *mod)
 
   find_symtab (mod);
   if (mod->symerr == DWFL_E_NOERROR)
-    return mod->syments;
+    return mod->syments + mod->aux_syments;
 
   __libdwfl_seterrno (mod->symerr);
   return -1;
index 9103380e923aa678452105199c9ae1f2b33157c7..3e4d9f612d730a5c58a95104d4ddafcaccb67bf3 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2006-2010 Red Hat, Inc.
+   Copyright (C) 2006-2013 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -42,8 +42,55 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
        return NULL;
     }
 
+  /* All local symbols should come before all global symbols.  If we
+     have an auxiliary table make sure all the main locals come first,
+     then all aux locals, then all main globals and finally all aux globals.
+     And skip the auxiliary table zero undefined entry.  */
   GElf_Word shndx;
-  sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata, ndx, sym, &shndx);
+  int tndx = ndx;
+  struct dwfl_file *file;
+  Elf_Data *symdata;
+  Elf_Data *symxndxdata;
+  Elf_Data *symstrdata;
+  if (mod->aux_symdata == NULL
+      || ndx < mod->first_global)
+    {
+      /* main symbol table (locals).  */
+      tndx = ndx;
+      file = mod->symfile;
+      symdata = mod->symdata;
+      symxndxdata = mod->symxndxdata;
+      symstrdata = mod->symstrdata;
+    }
+  else if (ndx < mod->first_global + mod->aux_first_global - 1)
+    {
+      /* aux symbol table (locals).  */
+      tndx = ndx - mod->first_global + 1;
+      file = &mod->aux_sym;
+      symdata = mod->aux_symdata;
+      symxndxdata = mod->aux_symxndxdata;
+      symstrdata = mod->aux_symstrdata;
+    }
+  else if ((size_t) ndx < mod->syments + mod->aux_first_global - 1)
+    {
+      /* main symbol table (globals).  */
+      tndx = ndx - mod->aux_first_global + 1;
+      file = mod->symfile;
+      symdata = mod->symdata;
+      symxndxdata = mod->symxndxdata;
+      symstrdata = mod->symstrdata;
+    }
+  else
+    {
+      /* aux symbol table (globals).  */
+      tndx = ndx - mod->syments + 1;
+      file = &mod->aux_sym;
+      symdata = mod->aux_symdata;
+      symxndxdata = mod->aux_symxndxdata;
+      symstrdata = mod->aux_symstrdata;
+    }
+  sym = gelf_getsymshndx (symdata, symxndxdata, tndx, sym, &shndx);
+
   if (unlikely (sym == NULL))
     {
       __libdwfl_seterrno (DWFL_E_LIBELF);
@@ -60,7 +107,7 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
          || (sym->st_shndx < SHN_LORESERVE && sym->st_shndx != SHN_UNDEF)))
     {
       GElf_Shdr shdr_mem;
-      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (mod->symfile->elf, shndx),
+      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (file->elf, shndx),
                                      &shdr_mem);
       alloc = unlikely (shdr == NULL) || (shdr->sh_flags & SHF_ALLOC);
     }
@@ -82,7 +129,7 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
          /* In an ET_REL file, the symbol table values are relative
             to the section, not to the module's load base.  */
          size_t symshstrndx = SHN_UNDEF;
-         Dwfl_Error result = __libdwfl_relocate_value (mod, mod->symfile->elf,
+         Dwfl_Error result = __libdwfl_relocate_value (mod, file->elf,
                                                        &symshstrndx,
                                                        shndx, &sym->st_value);
          if (unlikely (result != DWFL_E_NOERROR))
@@ -93,15 +140,15 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
        }
       else if (alloc)
        /* Apply the bias to the symbol value.  */
-       sym->st_value = dwfl_adjusted_st_value (mod, sym->st_value);
+       sym->st_value = dwfl_adjusted_st_value (mod, file, sym->st_value);
       break;
     }
 
-  if (unlikely (sym->st_name >= mod->symstrdata->d_size))
+  if (unlikely (sym->st_name >= symstrdata->d_size))
     {
       __libdwfl_seterrno (DWFL_E_BADSTROFF);
       return NULL;
     }
-  return (const char *) mod->symstrdata->d_buf + sym->st_name;
+  return (const char *) symstrdata->d_buf + sym->st_name;
 }
 INTDEF (dwfl_module_getsym)
index e14002c185246dd0ce2ee0aba714b0b7ed3cc997..fdb4202af8f5777ae414370ebb91578e0b447fd1 100644 (file)
@@ -49,7 +49,7 @@ dwfl_module_info (Dwfl_Module *mod, void ***userdata,
               : dwfl_adjusted_dwarf_addr (mod, 0));
   if (symbias)
     *symbias = (mod->symfile == NULL ? (Dwarf_Addr) -1
-               : dwfl_adjusted_st_value (mod, 0));
+               : dwfl_adjusted_st_value (mod, mod->symfile, 0));
 
   if (mainfile)
     *mainfile = mod->main.name;
index 806ebcd97d5ef4ec16dbd581faf6431c53931670..5aaa77858c2a6dbb80e3487fdae33c029dae5c9c 100644 (file)
@@ -142,7 +142,7 @@ struct Dwfl_Module
   char *name;                  /* Iterator name for this module.  */
   GElf_Addr low_addr, high_addr;
 
-  struct dwfl_file main, debug;
+  struct dwfl_file main, debug, aux_sym;
   GElf_Addr main_bias;
   Ebl *ebl;
   GElf_Half e_type;            /* GElf_Ehdr.e_type cache.  */
@@ -152,10 +152,15 @@ struct Dwfl_Module
 
   struct dwfl_file *symfile;   /* Either main or debug.  */
   Elf_Data *symdata;           /* Data in the ELF symbol table section.  */
+  Elf_Data *aux_symdata;       /* Data in the auxiliary ELF symbol table.  */
   size_t syments;              /* sh_size / sh_entsize of that section.  */
+  size_t aux_syments;          /* sh_size / sh_entsize of aux_sym section.  */
   int first_global;            /* Index of first global symbol of table.  */
+  int aux_first_global;                /* Index of first global of aux_sym table.  */
   Elf_Data *symstrdata;                /* Data for its string table.  */
+  Elf_Data *aux_symstrdata;    /* Data for aux_sym string table.  */
   Elf_Data *symxndxdata;       /* Data in the extended section index table. */
+  Elf_Data *aux_symxndxdata;   /* Data in the extended auxiliary table. */
 
   Dwarf *dw;                   /* libdw handle for its debugging info.  */
 
@@ -255,20 +260,42 @@ dwfl_deadjust_dwarf_addr (Dwfl_Module *mod, Dwarf_Addr addr)
          + mod->debug.address_sync);
 }
 
+static inline Dwarf_Addr
+dwfl_adjusted_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+  return dwfl_adjusted_address (mod, (addr
+                                     - mod->aux_sym.address_sync
+                                     + mod->main.address_sync));
+}
+
+static inline Dwarf_Addr
+dwfl_deadjust_aux_sym_addr (Dwfl_Module *mod, Dwarf_Addr addr)
+{
+  return (dwfl_deadjust_address (mod, addr)
+         - mod->main.address_sync
+         + mod->aux_sym.address_sync);
+}
+
 static inline GElf_Addr
-dwfl_adjusted_st_value (Dwfl_Module *mod, GElf_Addr addr)
+dwfl_adjusted_st_value (Dwfl_Module *mod, struct dwfl_file *symfile,
+                       GElf_Addr addr)
 {
-  if (mod->symfile == &mod->main)
+  if (symfile == &mod->main)
     return dwfl_adjusted_address (mod, addr);
-  return dwfl_adjusted_dwarf_addr (mod, addr);
+  if (symfile == &mod->debug)
+    return dwfl_adjusted_dwarf_addr (mod, addr);
+  return dwfl_adjusted_aux_sym_addr (mod, addr);
 }
 
 static inline GElf_Addr
-dwfl_deadjust_st_value (Dwfl_Module *mod, GElf_Addr addr)
+dwfl_deadjust_st_value (Dwfl_Module *mod, struct dwfl_file *symfile,
+                       GElf_Addr addr)
 {
-  if (mod->symfile == &mod->main)
+  if (symfile == &mod->main)
     return dwfl_deadjust_address (mod, addr);
-  return dwfl_deadjust_dwarf_addr (mod, addr);
+  if (symfile == &mod->debug)
+    return dwfl_deadjust_dwarf_addr (mod, addr);
+  return dwfl_deadjust_aux_sym_addr (mod, addr);
 }
 
 /* This describes a contiguous address range that lies in a single CU.
index 2c24bd5a982903536a1d21d08057a393497937c4..e06819d06b33840ab807a7df9ca440d01185090d 100644 (file)
@@ -254,7 +254,8 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
 
                if (m->e_type != ET_REL)
                  {
-                   sym->st_value = dwfl_adjusted_st_value (m, sym->st_value);
+                   sym->st_value = dwfl_adjusted_st_value (m, m->symfile,
+                                                           sym->st_value);
                    return DWFL_E_NOERROR;
                  }