LCOV - code coverage report
Current view: top level - libdwfl - segment.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 133 159 83.6 %
Date: 2024-03-01 16:42:08 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 114 144 79.2 %

           Branch data     Line data    Source code
       1                 :            : /* Manage address space lookup table for libdwfl.
       2                 :            :    Copyright (C) 2008, 2009, 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                 :            : #ifdef HAVE_CONFIG_H
      30                 :            : # include <config.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include "libdwflP.h"
      34                 :            : 
      35                 :            : GElf_Addr
      36                 :            : internal_function
      37                 :      91672 : __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start)
      38                 :            : {
      39         [ +  + ]:      91672 :   if (dwfl->segment_align > 1)
      40                 :      91508 :     start &= -dwfl->segment_align;
      41                 :      91672 :   return start;
      42                 :            : }
      43                 :            : 
      44                 :            : GElf_Addr
      45                 :            : internal_function
      46                 :      91672 : __libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end)
      47                 :            : {
      48         [ +  + ]:      91672 :   if (dwfl->segment_align > 1)
      49                 :      91508 :     end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
      50                 :      91672 :   return end;
      51                 :            : }
      52                 :            : 
      53                 :            : static bool
      54                 :      71714 : insert (Dwfl *dwfl, size_t i, GElf_Addr start, GElf_Addr end, int segndx)
      55                 :            : {
      56   [ +  +  +  + ]:      71714 :   bool need_start = (i == 0 || dwfl->lookup_addr[i - 1] != start);
      57                 :     143428 :   bool need_end = (i + 1 >= dwfl->lookup_elts
      58   [ +  +  +  - ]:      71714 :                    || dwfl->lookup_addr[i + 1] != end);
      59                 :      71714 :   size_t need = need_start + need_end;
      60         [ -  + ]:      71714 :   if (need == 0)
      61                 :          0 :     return false;
      62                 :            : 
      63         [ +  + ]:      71714 :   if (dwfl->lookup_alloc - dwfl->lookup_elts < need)
      64                 :            :     {
      65         [ +  + ]:      10300 :       size_t n = dwfl->lookup_alloc == 0 ? 16 : dwfl->lookup_alloc * 2;
      66                 :      10300 :       GElf_Addr *naddr = realloc (dwfl->lookup_addr, sizeof naddr[0] * n);
      67         [ -  + ]:      10300 :       if (unlikely (naddr == NULL))
      68                 :          0 :         return true;
      69                 :      10300 :       int *nsegndx = realloc (dwfl->lookup_segndx, sizeof nsegndx[0] * n);
      70         [ -  + ]:      10300 :       if (unlikely (nsegndx == NULL))
      71                 :            :         {
      72         [ #  # ]:          0 :           if (naddr != dwfl->lookup_addr)
      73                 :          0 :             free (naddr);
      74                 :          0 :           return true;
      75                 :            :         }
      76                 :      10300 :       dwfl->lookup_alloc = n;
      77                 :      10300 :       dwfl->lookup_addr = naddr;
      78                 :      10300 :       dwfl->lookup_segndx = nsegndx;
      79                 :            : 
      80         [ +  + ]:      10300 :       if (dwfl->lookup_module != NULL)
      81                 :            :         {
      82                 :            :           /* Make sure this array is big enough too.  */
      83                 :          4 :           Dwfl_Module **old = dwfl->lookup_module;
      84                 :          4 :           dwfl->lookup_module = realloc (dwfl->lookup_module,
      85                 :            :                                          sizeof dwfl->lookup_module[0] * n);
      86         [ -  + ]:          4 :           if (unlikely (dwfl->lookup_module == NULL))
      87                 :            :             {
      88                 :          0 :               free (old);
      89                 :          0 :               return true;
      90                 :            :             }
      91                 :            :         }
      92                 :            :     }
      93                 :            : 
      94         [ +  + ]:      71714 :   if (unlikely (i < dwfl->lookup_elts))
      95                 :            :     {
      96                 :         48 :       const size_t move = dwfl->lookup_elts - i;
      97                 :         48 :       memmove (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i],
      98                 :            :                move * sizeof dwfl->lookup_addr[0]);
      99                 :         48 :       memmove (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i],
     100                 :            :                move * sizeof dwfl->lookup_segndx[0]);
     101         [ +  + ]:         48 :       if (dwfl->lookup_module != NULL)
     102                 :         40 :         memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i],
     103                 :            :                  move * sizeof dwfl->lookup_module[0]);
     104                 :            :     }
     105                 :            : 
     106         [ +  + ]:      71714 :   if (need_start)
     107                 :            :     {
     108                 :      70838 :       dwfl->lookup_addr[i] = start;
     109                 :      70838 :       dwfl->lookup_segndx[i] = segndx;
     110         [ +  + ]:      70838 :       if (dwfl->lookup_module != NULL)
     111                 :      60084 :         dwfl->lookup_module[i] = NULL;
     112                 :      70838 :       ++i;
     113                 :            :     }
     114                 :            :   else
     115                 :        876 :     dwfl->lookup_segndx[i - 1] = segndx;
     116                 :            : 
     117         [ +  - ]:      71714 :   if (need_end)
     118                 :            :     {
     119                 :      71714 :       dwfl->lookup_addr[i] = end;
     120                 :      71714 :       dwfl->lookup_segndx[i] = -1;
     121         [ +  + ]:      71714 :       if (dwfl->lookup_module != NULL)
     122                 :      60084 :         dwfl->lookup_module[i] = NULL;
     123                 :            :     }
     124                 :            : 
     125                 :      71714 :   dwfl->lookup_elts += need;
     126                 :            : 
     127                 :      71714 :   return false;
     128                 :            : }
     129                 :            : 
     130                 :            : static int
     131                 :      93038 : lookup (Dwfl *dwfl, GElf_Addr address, int hint)
     132                 :            : {
     133         [ +  + ]:      93038 :   if (hint >= 0
     134         [ +  + ]:      60236 :       && address >= dwfl->lookup_addr[hint]
     135         [ +  + ]:      60190 :       && ((size_t) hint + 1 == dwfl->lookup_elts
     136         [ +  + ]:        146 :           || address < dwfl->lookup_addr[hint + 1]))
     137                 :      60046 :     return hint;
     138                 :            : 
     139                 :            :   /* Do binary search on the array indexed by module load address.  */
     140                 :      32992 :   size_t l = 0, u = dwfl->lookup_elts;
     141         [ +  + ]:      81294 :   while (l < u)
     142                 :            :     {
     143                 :      71142 :       size_t idx = (l + u) / 2;
     144         [ +  + ]:      71142 :       if (address < dwfl->lookup_addr[idx])
     145                 :      36520 :         u = idx;
     146                 :            :       else
     147                 :            :         {
     148                 :      34622 :           l = idx + 1;
     149   [ +  +  +  + ]:      34622 :           if (l == dwfl->lookup_elts || address < dwfl->lookup_addr[l])
     150                 :      22840 :             return idx;
     151                 :            :         }
     152                 :            :     }
     153                 :            : 
     154                 :      10152 :   return -1;
     155                 :            : }
     156                 :            : 
     157                 :            : static bool
     158                 :      10494 : reify_segments (Dwfl *dwfl)
     159                 :            : {
     160                 :      10494 :   int hint = -1;
     161                 :      10494 :   int highest = -1;
     162                 :      10494 :   bool fixup = false;
     163         [ +  + ]:      90940 :   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
     164         [ +  - ]:      80446 :     if (! mod->gc)
     165                 :            :       {
     166                 :      80446 :         const GElf_Addr start = __libdwfl_segment_start (dwfl, mod->low_addr);
     167                 :      80446 :         const GElf_Addr end = __libdwfl_segment_end (dwfl, mod->high_addr);
     168                 :      80446 :         bool resized = false;
     169                 :            : 
     170                 :      80446 :         int idx = lookup (dwfl, start, hint);
     171         [ +  + ]:      80446 :         if (unlikely (idx < 0))
     172                 :            :           {
     173                 :            :             /* Module starts below any segment.  Insert a low one.  */
     174         [ -  + ]:      10148 :             if (unlikely (insert (dwfl, 0, start, end, -1)))
     175                 :          0 :               return true;
     176                 :      10148 :             idx = 0;
     177                 :      10148 :             resized = true;
     178                 :            :           }
     179         [ -  + ]:      70298 :         else if (dwfl->lookup_addr[idx] > start)
     180                 :            :           {
     181                 :            :             /* The module starts in the middle of this segment.  Split it.  */
     182         [ #  # ]:          0 :             if (unlikely (insert (dwfl, idx + 1, start, end,
     183                 :            :                                   dwfl->lookup_segndx[idx])))
     184                 :          0 :               return true;
     185                 :          0 :             ++idx;
     186                 :          0 :             resized = true;
     187                 :            :           }
     188         [ +  + ]:      70298 :         else if (dwfl->lookup_addr[idx] < start)
     189                 :            :           {
     190                 :            :             /* The module starts past the end of this segment.
     191                 :            :                Add a new one.  */
     192         [ -  + ]:      60048 :             if (unlikely (insert (dwfl, idx + 1, start, end, -1)))
     193                 :          0 :               return true;
     194                 :      60048 :             ++idx;
     195                 :      60048 :             resized = true;
     196                 :            :           }
     197                 :            : 
     198         [ +  + ]:      80446 :         if ((size_t) idx + 1 < dwfl->lookup_elts
     199         [ +  + ]:      70444 :             && end < dwfl->lookup_addr[idx + 1])
     200                 :            :           {
     201                 :            :             /* The module ends in the middle of this segment.  Split it.  */
     202         [ -  + ]:         40 :             if (unlikely (insert (dwfl, idx + 1,
     203                 :            :                                   end, dwfl->lookup_addr[idx + 1], -1)))
     204                 :          0 :               return true;
     205                 :         40 :             resized = true;
     206                 :            :           }
     207                 :            : 
     208         [ +  + ]:      80446 :         if (dwfl->lookup_module == NULL)
     209                 :            :           {
     210                 :      10208 :             dwfl->lookup_module = calloc (dwfl->lookup_alloc,
     211                 :            :                                           sizeof dwfl->lookup_module[0]);
     212         [ -  + ]:      10208 :             if (unlikely (dwfl->lookup_module == NULL))
     213                 :          0 :               return true;
     214                 :            :           }
     215                 :            : 
     216                 :            :         /* Cache a backpointer in the module.  */
     217                 :      80446 :         mod->segment = idx;
     218                 :            : 
     219                 :            :         /* Put MOD in the table for each segment that's inside it.  */
     220                 :            :         do
     221                 :      81060 :           dwfl->lookup_module[idx++] = mod;
     222                 :      81060 :         while ((size_t) idx < dwfl->lookup_elts
     223   [ +  +  +  + ]:      81060 :                && dwfl->lookup_addr[idx] < end);
     224         [ -  + ]:      80446 :         assert (dwfl->lookup_module[mod->segment] == mod);
     225                 :            : 
     226   [ +  +  +  + ]:      80446 :         if (resized && idx - 1 >= highest)
     227                 :            :           /* Expanding the lookup tables invalidated backpointers
     228                 :            :              we've already stored.  Reset those ones.  */
     229                 :      70234 :           fixup = true;
     230                 :            : 
     231                 :      80446 :         highest = idx - 1;
     232         [ +  + ]:      80446 :         hint = (size_t) idx < dwfl->lookup_elts ? idx : -1;
     233                 :            :       }
     234                 :            : 
     235         [ +  + ]:      10494 :   if (fixup)
     236                 :            :     /* Reset backpointer indices invalidated by table insertions.  */
     237         [ +  + ]:     152000 :     for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx)
     238         [ +  + ]:     141814 :       if (dwfl->lookup_module[idx] != NULL)
     239                 :      80962 :         dwfl->lookup_module[idx]->segment = idx;
     240                 :            : 
     241                 :      10494 :   return false;
     242                 :            : }
     243                 :            : 
     244                 :            : int
     245                 :      12592 : dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod)
     246                 :            : {
     247         [ -  + ]:      12592 :   if (unlikely (dwfl == NULL))
     248                 :          0 :     return -1;
     249                 :            : 
     250         [ +  + ]:      12592 :   if (unlikely (dwfl->lookup_module == NULL)
     251         [ +  + ]:      11284 :       && mod != NULL
     252         [ -  + ]:      10494 :       && unlikely (reify_segments (dwfl)))
     253                 :            :     {
     254                 :          0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     255                 :          0 :       return -1;
     256                 :            :     }
     257                 :            : 
     258                 :      12592 :   int idx = lookup (dwfl, address, -1);
     259         [ +  + ]:      12592 :   if (likely (mod != NULL))
     260                 :            :     {
     261   [ +  +  +  + ]:      11802 :       if (unlikely (idx < 0) || unlikely (dwfl->lookup_module == NULL))
     262                 :        290 :         *mod = NULL;
     263                 :            :       else
     264                 :            :         {
     265                 :      11512 :           *mod = dwfl->lookup_module[idx];
     266                 :            : 
     267                 :            :           /* If this segment does not have a module, but the address is
     268                 :            :              the upper boundary of the previous segment's module, use that.  */
     269   [ +  +  +  -  :      11512 :           if (*mod == NULL && idx > 0 && dwfl->lookup_addr[idx] == address)
                   +  - ]
     270                 :            :             {
     271                 :          4 :               *mod = dwfl->lookup_module[idx - 1];
     272   [ +  -  -  + ]:          4 :               if (*mod != NULL && (*mod)->high_addr != address)
     273                 :          0 :                 *mod = NULL;
     274                 :            :             }
     275                 :            :         }
     276                 :            :     }
     277                 :            : 
     278         [ +  + ]:      12592 :   if (likely (idx >= 0))
     279                 :            :     /* Translate internal segment table index to user segment index.  */
     280                 :      12588 :     idx = dwfl->lookup_segndx[idx];
     281                 :            : 
     282                 :      12592 :   return idx;
     283                 :            : }
     284                 :            : INTDEF (dwfl_addrsegment)
     285                 :            : 
     286                 :            : int
     287                 :       1478 : dwfl_report_segment (Dwfl *dwfl, int ndx, const GElf_Phdr *phdr, GElf_Addr bias,
     288                 :            :                      const void *ident)
     289                 :            : {
     290                 :            :   /* This was previously used for coalescing segments, but it was buggy since
     291                 :            :      day one.  We don't use it anymore.  */
     292                 :            :   (void)ident;
     293                 :            : 
     294         [ -  + ]:       1478 :   if (dwfl == NULL)
     295                 :          0 :     return -1;
     296                 :            : 
     297         [ -  + ]:       1478 :   if (ndx < 0)
     298                 :          0 :     ndx = dwfl->next_segndx;
     299                 :            : 
     300   [ +  -  +  + ]:       1478 :   if (phdr->p_align > 1 && (dwfl->segment_align <= 1 ||
     301         [ -  + ]:       1402 :                             phdr->p_align < dwfl->segment_align))
     302                 :         76 :     dwfl->segment_align = phdr->p_align;
     303                 :            : 
     304         [ -  + ]:       1478 :   if (unlikely (dwfl->lookup_module != NULL))
     305                 :            :     {
     306                 :          0 :       free (dwfl->lookup_module);
     307                 :          0 :       dwfl->lookup_module = NULL;
     308                 :            :     }
     309                 :            : 
     310                 :       1478 :   GElf_Addr start = __libdwfl_segment_start (dwfl, bias + phdr->p_vaddr);
     311                 :       1478 :   GElf_Addr end = __libdwfl_segment_end (dwfl,
     312                 :       1478 :                                          bias + phdr->p_vaddr + phdr->p_memsz);
     313                 :            : 
     314                 :            :   /* Normally just appending keeps us sorted.  */
     315                 :            : 
     316                 :       1478 :   size_t i = dwfl->lookup_elts;
     317   [ +  +  -  + ]:       1478 :   while (i > 0 && unlikely (start < dwfl->lookup_addr[i - 1]))
     318                 :          0 :     --i;
     319                 :            : 
     320         [ -  + ]:       1478 :   if (unlikely (insert (dwfl, i, start, end, ndx)))
     321                 :            :     {
     322                 :          0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     323                 :          0 :       return -1;
     324                 :            :     }
     325                 :            : 
     326                 :       1478 :   dwfl->next_segndx = ndx + 1;
     327                 :            : 
     328                 :       1478 :   return ndx;
     329                 :            : }
     330                 :            : INTDEF (dwfl_report_segment)

Generated by: LCOV version 1.14