LCOV - code coverage report
Current view: top level - libdwfl - derelocate.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 129 161 80.1 %
Date: 2017-01-05 09:15:16 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Recover relocatibility for addresses computed from debug information.
       2             :    Copyright (C) 2005-2010, 2013, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #include "libdwflP.h"
      30             : 
      31             : struct dwfl_relocation
      32             : {
      33             :   size_t count;
      34             :   struct
      35             :   {
      36             :     Elf_Scn *scn;
      37             :     Elf_Scn *relocs;
      38             :     const char *name;
      39             :     GElf_Addr start, end;
      40             :   } refs[0];
      41             : };
      42             : 
      43             : 
      44             : struct secref
      45             : {
      46             :   struct secref *next;
      47             :   Elf_Scn *scn;
      48             :   Elf_Scn *relocs;
      49             :   const char *name;
      50             :   GElf_Addr start, end;
      51             : };
      52             : 
      53             : static int
      54        4491 : compare_secrefs (const void *a, const void *b)
      55             : {
      56        4491 :   struct secref *const *p1 = a;
      57        4491 :   struct secref *const *p2 = b;
      58             : 
      59             :   /* No signed difference calculation is correct here, since the
      60             :      terms are unsigned and could be more than INT64_MAX apart.  */
      61        4491 :   if ((*p1)->start < (*p2)->start)
      62             :     return -1;
      63          45 :   if ((*p1)->start > (*p2)->start)
      64             :     return 1;
      65             : 
      66          45 :   return 0;
      67             : }
      68             : 
      69             : static int
      70      125914 : cache_sections (Dwfl_Module *mod)
      71             : {
      72      125914 :   if (likely (mod->reloc_info != NULL))
      73      125800 :     return mod->reloc_info->count;
      74             : 
      75         114 :   struct secref *refs = NULL;
      76         114 :   size_t nrefs = 0;
      77             : 
      78             :   size_t shstrndx;
      79         114 :   if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0))
      80             :     {
      81             :     elf_error:
      82           0 :       __libdwfl_seterrno (DWFL_E_LIBELF);
      83           0 :       nrefs = -1;
      84           0 :       goto free_refs;
      85             :     }
      86             : 
      87             :   bool check_reloc_sections = false;
      88             :   Elf_Scn *scn = NULL;
      89        3453 :   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
      90             :     {
      91             :       GElf_Shdr shdr_mem;
      92        3339 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
      93        3339 :       if (shdr == NULL)
      94             :         goto elf_error;
      95             : 
      96        3339 :       if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0
      97          38 :           && mod->e_type == ET_REL)
      98             :         {
      99             :           /* This section might not yet have been looked at.  */
     100          37 :           if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
     101          37 :                                         elf_ndxscn (scn),
     102          37 :                                         &shdr->sh_addr) != DWFL_E_NOERROR)
     103           0 :             continue;
     104          37 :           shdr = gelf_getshdr (scn, &shdr_mem);
     105          37 :           if (unlikely (shdr == NULL))
     106             :             goto elf_error;
     107             :         }
     108             : 
     109        3339 :       if (shdr->sh_flags & SHF_ALLOC)
     110             :         {
     111        2171 :           const char *name = elf_strptr (mod->main.elf, shstrndx,
     112        2171 :                                          shdr->sh_name);
     113        2171 :           if (unlikely (name == NULL))
     114             :             goto elf_error;
     115             : 
     116        2171 :           struct secref *newref = malloc (sizeof *newref);
     117        2171 :           if (unlikely (newref == NULL))
     118             :             {
     119             :             nomem:
     120           0 :               __libdwfl_seterrno (DWFL_E_NOMEM);
     121           0 :               nrefs = -1;
     122           0 :               goto free_refs;
     123             :             }
     124             : 
     125        2171 :           newref->scn = scn;
     126        2171 :           newref->relocs = NULL;
     127        2171 :           newref->name = name;
     128        4342 :           newref->start = dwfl_adjusted_address (mod, shdr->sh_addr);
     129        2171 :           newref->end = newref->start + shdr->sh_size;
     130        2171 :           newref->next = refs;
     131        2171 :           refs = newref;
     132        2171 :           ++nrefs;
     133             :         }
     134             : 
     135        3339 :       if (mod->e_type == ET_REL
     136         939 :           && shdr->sh_size != 0
     137         740 :           && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
     138          70 :           && mod->dwfl->callbacks->section_address != NULL)
     139             :         {
     140          70 :           if (shdr->sh_info < elf_ndxscn (scn))
     141             :             {
     142             :               /* We've already looked at the section these relocs apply to.  */
     143          70 :               Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
     144          70 :               if (likely (tscn != NULL))
     145           0 :                 for (struct secref *sec = refs; sec != NULL; sec = sec->next)
     146          70 :                   if (sec->scn == tscn)
     147             :                     {
     148          70 :                       sec->relocs = scn;
     149          70 :                       break;
     150             :                     }
     151             :             }
     152             :           else
     153             :             /* We'll have to do a second pass.  */
     154             :             check_reloc_sections = true;
     155             :         }
     156             :     }
     157             : 
     158         114 :   mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
     159         114 :   if (unlikely (mod->reloc_info == NULL))
     160             :     goto nomem;
     161             : 
     162         114 :   struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]);
     163         114 :   if (unlikely (sortrefs == NULL))
     164             :     goto nomem;
     165             : 
     166        2171 :   for (size_t i = nrefs; i-- > 0; refs = refs->next)
     167        2171 :     sortrefs[i] = refs;
     168         114 :   assert (refs == NULL);
     169             : 
     170         114 :   qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs);
     171             : 
     172         114 :   mod->reloc_info->count = nrefs;
     173        2285 :   for (size_t i = 0; i < nrefs; ++i)
     174             :     {
     175        2171 :       mod->reloc_info->refs[i].name = sortrefs[i]->name;
     176        2171 :       mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
     177        2171 :       mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
     178        2171 :       mod->reloc_info->refs[i].start = sortrefs[i]->start;
     179        2171 :       mod->reloc_info->refs[i].end = sortrefs[i]->end;
     180        2171 :       free (sortrefs[i]);
     181             :     }
     182             : 
     183         114 :   free (sortrefs);
     184             : 
     185         114 :   if (unlikely (check_reloc_sections))
     186             :     {
     187             :       /* There was a reloc section that preceded its target section.
     188             :          So we have to scan again now that we have cached all the
     189             :          possible target sections we care about.  */
     190             : 
     191             :       scn = NULL;
     192           0 :       while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
     193             :         {
     194             :           GElf_Shdr shdr_mem;
     195           0 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     196           0 :           if (shdr == NULL)
     197             :             goto elf_error;
     198             : 
     199           0 :           if (shdr->sh_size != 0
     200           0 :               && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
     201             :             {
     202           0 :               Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
     203           0 :               if (likely (tscn != NULL))
     204           0 :                 for (size_t i = 0; i < nrefs; ++i)
     205           0 :                   if (mod->reloc_info->refs[i].scn == tscn)
     206             :                     {
     207           0 :                       mod->reloc_info->refs[i].relocs = scn;
     208           0 :                       break;
     209             :                     }
     210             :             }
     211             :         }
     212             :     }
     213             : 
     214             : free_refs:
     215         114 :   while (refs != NULL)
     216             :     {
     217           0 :       struct secref *ref = refs;
     218           0 :       refs = ref->next;
     219           0 :       free (ref);
     220             :     }
     221             : 
     222         114 :   return nrefs;
     223             : }
     224             : 
     225             : 
     226             : int
     227      591627 : dwfl_module_relocations (Dwfl_Module *mod)
     228             : {
     229      591627 :   if (mod == NULL)
     230             :     return -1;
     231             : 
     232      591627 :   switch (mod->e_type)
     233             :     {
     234             :     case ET_REL:
     235       36617 :       return cache_sections (mod);
     236             : 
     237             :     case ET_DYN:
     238             :       return 1;
     239             : 
     240             :     case ET_EXEC:
     241      434638 :       assert (mod->main.vaddr == mod->low_addr);
     242             :       break;
     243             :     }
     244             : 
     245      434638 :   return 0;
     246             : }
     247             : 
     248             : const char *
     249      156998 : dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx,
     250             :                              Elf32_Word *shndxp)
     251             : {
     252      156998 :   if (mod == NULL)
     253             :     return NULL;
     254             : 
     255      156998 :   switch (mod->e_type)
     256             :     {
     257             :     case ET_REL:
     258             :       break;
     259             : 
     260             :     case ET_DYN:
     261      120374 :       if (idx != 0)
     262             :         return NULL;
     263      120374 :       if (shndxp)
     264           0 :         *shndxp = SHN_ABS;
     265             :       return "";
     266             : 
     267             :     default:
     268             :       return NULL;
     269             :     }
     270             : 
     271       36624 :   if (cache_sections (mod) < 0)
     272             :     return NULL;
     273             : 
     274       36624 :   struct dwfl_relocation *sections = mod->reloc_info;
     275             : 
     276       36624 :   if (idx >= sections->count)
     277             :     return NULL;
     278             : 
     279       36624 :   if (shndxp)
     280           0 :     *shndxp = elf_ndxscn (sections->refs[idx].scn);
     281             : 
     282       36624 :   return sections->refs[idx].name;
     283             : }
     284             : 
     285             : /* Check that MOD is valid and make sure its relocation has been done.  */
     286             : static bool
     287      157253 : check_module (Dwfl_Module *mod)
     288             : {
     289      157253 :   if (mod == NULL)
     290             :     return true;
     291             : 
     292      157253 :   if (INTUSE(dwfl_module_getsymtab) (mod) < 0)
     293             :     {
     294           0 :       Dwfl_Error error = dwfl_errno ();
     295           0 :       if (error != DWFL_E_NO_SYMTAB)
     296             :         {
     297           0 :           __libdwfl_seterrno (error);
     298           0 :           return true;
     299             :         }
     300             :     }
     301             : 
     302      157253 :   if (mod->dw == NULL)
     303             :     {
     304             :       Dwarf_Addr bias;
     305         153 :       if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL)
     306             :         {
     307         142 :           Dwfl_Error error = dwfl_errno ();
     308         142 :           if (error != DWFL_E_NO_DWARF)
     309             :             {
     310           0 :               __libdwfl_seterrno (error);
     311           0 :               return true;
     312             :             }
     313             :         }
     314             :     }
     315             : 
     316             :   return false;
     317             : }
     318             : 
     319             : /* Find the index in MOD->reloc_info.refs containing *ADDR.  */
     320             : static int
     321       52673 : find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
     322             : {
     323       52673 :   if (cache_sections (mod) < 0)
     324             :     return -1;
     325             : 
     326       52673 :   struct dwfl_relocation *sections = mod->reloc_info;
     327             : 
     328             :   /* The sections are sorted by address, so we can use binary search.  */
     329       52673 :   size_t l = 0, u = sections->count;
     330      252425 :   while (l < u)
     331             :     {
     332      199749 :       size_t idx = (l + u) / 2;
     333      199749 :       if (*addr < sections->refs[idx].start)
     334             :         u = idx;
     335       71697 :       else if (*addr > sections->refs[idx].end)
     336       19027 :         l = idx + 1;
     337             :       else
     338             :         {
     339             :           /* Consider the limit of a section to be inside it, unless it's
     340             :              inside the next one.  A section limit address can appear in
     341             :              line records.  */
     342       52670 :           if (*addr == sections->refs[idx].end
     343        2764 :               && idx + 1 < sections->count
     344        2763 :               && *addr == sections->refs[idx + 1].start)
     345        2668 :             ++idx;
     346             : 
     347       52670 :           *addr -= sections->refs[idx].start;
     348       52670 :           return idx;
     349             :         }
     350             :     }
     351             : 
     352           3 :   __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
     353           3 :   return -1;
     354             : }
     355             : 
     356             : size_t
     357             : internal_function
     358       15971 : __libdwfl_find_section_ndx (Dwfl_Module *mod, Dwarf_Addr *addr)
     359             : {
     360       15971 :   int idx = find_section (mod, addr);
     361       15971 :   if (unlikely (idx == -1))
     362             :     return SHN_UNDEF;
     363             : 
     364       15968 :   return elf_ndxscn (mod->reloc_info->refs[idx].scn);
     365             : }
     366             : 
     367             : int
     368      157179 : dwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr)
     369             : {
     370      157179 :   if (unlikely (check_module (mod)))
     371             :     return -1;
     372             : 
     373      157179 :   switch (mod->e_type)
     374             :     {
     375             :     case ET_REL:
     376       36628 :       return find_section (mod, addr);
     377             : 
     378             :     case ET_DYN:
     379             :       /* All relative to first and only relocation base: module start.  */
     380      120535 :       *addr -= mod->low_addr;
     381      120535 :       break;
     382             : 
     383             :     default:
     384             :       /* Already absolute, dwfl_module_relocations returned zero.  We
     385             :          shouldn't really have been called, but it's a harmless no-op.  */
     386             :       break;
     387             :     }
     388             : 
     389             :   return 0;
     390             : }
     391             : INTDEF (dwfl_module_relocate_address)
     392             : 
     393             : Elf_Scn *
     394          74 : dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
     395             :                              Dwarf_Addr *bias)
     396             : {
     397          74 :   if (check_module (mod))
     398             :     return NULL;
     399             : 
     400          74 :   int idx = find_section (mod, address);
     401          74 :   if (idx < 0)
     402             :     return NULL;
     403             : 
     404          74 :   if (mod->reloc_info->refs[idx].relocs != NULL)
     405             :     {
     406           2 :       assert (mod->e_type == ET_REL);
     407             : 
     408           2 :       Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
     409           2 :       Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
     410           2 :       Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
     411             :                                                       relocscn, tscn, true);
     412           2 :       if (likely (result == DWFL_E_NOERROR))
     413           2 :         mod->reloc_info->refs[idx].relocs = NULL;
     414             :       else
     415             :         {
     416           0 :           __libdwfl_seterrno (result);
     417           0 :           return NULL;
     418             :         }
     419             :     }
     420             : 
     421          74 :   *bias = dwfl_adjusted_address (mod, 0);
     422          74 :   return mod->reloc_info->refs[idx].scn;
     423             : }
     424             : INTDEF (dwfl_module_address_section)

Generated by: LCOV version 1.12