LCOV - code coverage report
Current view: top level - libdwfl - segment.c (source / functions) Coverage Total Hit
Test: elfutils-0.192 Lines: 89.1 % 138 123
Test Date: 2024-10-18 15:14:37 Functions: 100.0 % 7 7
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 79.2 % 144 114

             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                 :       95242 : __libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start)
      38                 :             : {
      39         [ +  + ]:       95242 :   if (dwfl->segment_align > 1)
      40                 :       95078 :     start &= -dwfl->segment_align;
      41                 :       95242 :   return start;
      42                 :             : }
      43                 :             : 
      44                 :             : GElf_Addr
      45                 :             : internal_function
      46                 :       95242 : __libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end)
      47                 :             : {
      48         [ +  + ]:       95242 :   if (dwfl->segment_align > 1)
      49                 :       95078 :     end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
      50                 :       95242 :   return end;
      51                 :             : }
      52                 :             : 
      53                 :             : static bool
      54                 :       61824 : insert (Dwfl *dwfl, size_t i, GElf_Addr start, GElf_Addr end, int segndx)
      55                 :             : {
      56   [ +  +  +  + ]:       61824 :   bool need_start = (i == 0 || dwfl->lookup_addr[i - 1] != start);
      57                 :      123648 :   bool need_end = (i + 1 >= dwfl->lookup_elts
      58   [ +  +  -  + ]:       61824 :                    || dwfl->lookup_addr[i + 1] != end);
      59                 :       61824 :   size_t need = need_start + need_end;
      60         [ +  - ]:       61824 :   if (need == 0)
      61                 :             :     return false;
      62                 :             : 
      63         [ +  + ]:       61824 :   if (dwfl->lookup_alloc - dwfl->lookup_elts < need)
      64                 :             :     {
      65         [ +  + ]:       10306 :       size_t n = dwfl->lookup_alloc == 0 ? 16 : dwfl->lookup_alloc * 2;
      66                 :       10306 :       GElf_Addr *naddr = realloc (dwfl->lookup_addr, sizeof naddr[0] * n);
      67         [ +  - ]:       10306 :       if (unlikely (naddr == NULL))
      68                 :             :         return true;
      69                 :       10306 :       int *nsegndx = realloc (dwfl->lookup_segndx, sizeof nsegndx[0] * n);
      70         [ -  + ]:       10306 :       if (unlikely (nsegndx == NULL))
      71                 :             :         {
      72         [ #  # ]:           0 :           if (naddr != dwfl->lookup_addr)
      73                 :           0 :             free (naddr);
      74                 :           0 :           return true;
      75                 :             :         }
      76                 :       10306 :       dwfl->lookup_alloc = n;
      77                 :       10306 :       dwfl->lookup_addr = naddr;
      78                 :       10306 :       dwfl->lookup_segndx = nsegndx;
      79                 :             : 
      80         [ +  + ]:       10306 :       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         [ +  + ]:       61824 :   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                 :          42 :         memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i],
     103                 :             :                  move * sizeof dwfl->lookup_module[0]);
     104                 :             :     }
     105                 :             : 
     106         [ +  + ]:       61824 :   if (need_start)
     107                 :             :     {
     108                 :       60870 :       dwfl->lookup_addr[i] = start;
     109                 :       60870 :       dwfl->lookup_segndx[i] = segndx;
     110         [ +  + ]:       60870 :       if (dwfl->lookup_module != NULL)
     111                 :       50084 :         dwfl->lookup_module[i] = NULL;
     112                 :             :       ++i;
     113                 :             :     }
     114                 :             :   else
     115                 :         954 :     dwfl->lookup_segndx[i - 1] = segndx;
     116                 :             : 
     117         [ +  - ]:       61824 :   if (need_end)
     118                 :             :     {
     119                 :       61824 :       dwfl->lookup_addr[i] = end;
     120                 :       61824 :       dwfl->lookup_segndx[i] = -1;
     121         [ +  + ]:       61824 :       if (dwfl->lookup_module != NULL)
     122                 :       50084 :         dwfl->lookup_module[i] = NULL;
     123                 :             :     }
     124                 :             : 
     125                 :       61824 :   dwfl->lookup_elts += need;
     126                 :             : 
     127                 :       61824 :   return false;
     128                 :             : }
     129                 :             : 
     130                 :             : static int
     131                 :       93096 : lookup (Dwfl *dwfl, GElf_Addr address, int hint)
     132                 :             : {
     133         [ +  + ]:       93096 :   if (hint >= 0
     134         [ +  + ]:       60254 :       && address >= dwfl->lookup_addr[hint]
     135         [ +  + ]:       60208 :       && ((size_t) hint + 1 == dwfl->lookup_elts
     136         [ +  + ]:         160 :           || address < dwfl->lookup_addr[hint + 1]))
     137                 :             :     return hint;
     138                 :             : 
     139                 :             :   /* Do binary search on the array indexed by module load address.  */
     140                 :       33046 :   size_t l = 0, u = dwfl->lookup_elts;
     141         [ +  + ]:      114690 :   while (l < u)
     142                 :             :     {
     143                 :       71492 :       size_t idx = (l + u) / 2;
     144         [ +  + ]:       71492 :       if (address < dwfl->lookup_addr[idx])
     145                 :             :         u = idx;
     146                 :             :       else
     147                 :             :         {
     148                 :       34772 :           l = idx + 1;
     149   [ +  +  +  + ]:       34772 :           if (l == dwfl->lookup_elts || address < dwfl->lookup_addr[l])
     150                 :       22894 :             return idx;
     151                 :             :         }
     152                 :             :     }
     153                 :             : 
     154                 :             :   return -1;
     155                 :             : }
     156                 :             : 
     157                 :             : static bool
     158                 :       10506 : reify_segments (Dwfl *dwfl)
     159                 :             : {
     160                 :       10506 :   int hint = -1;
     161                 :       10506 :   int highest = -1;
     162                 :       10506 :   bool fixup = false;
     163         [ +  + ]:       90972 :   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
     164         [ +  - ]:       80466 :     if (! mod->gc)
     165                 :             :       {
     166                 :       80466 :         const GElf_Addr start = __libdwfl_segment_start (dwfl, mod->low_addr);
     167                 :       80466 :         const GElf_Addr end = __libdwfl_segment_end (dwfl, mod->high_addr);
     168                 :       80466 :         bool resized = false;
     169                 :             : 
     170                 :       80466 :         int idx = lookup (dwfl, start, hint);
     171         [ +  + ]:       80466 :         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                 :             :               return true;
     176                 :             :             idx = 0;
     177                 :             :             resized = true;
     178                 :             :           }
     179         [ -  + ]:       70318 :         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                 :             :               return true;
     185                 :             :             ++idx;
     186                 :             :             resized = true;
     187                 :             :           }
     188         [ +  + ]:       70318 :         else if (dwfl->lookup_addr[idx] < start)
     189                 :             :           {
     190                 :             :             /* The module starts past the end of this segment.
     191                 :             :                Add a new one.  */
     192         [ +  - ]:       50046 :             if (unlikely (insert (dwfl, idx + 1, start, end, -1)))
     193                 :             :               return true;
     194                 :             :             ++idx;
     195                 :             :             resized = true;
     196                 :             :           }
     197                 :             : 
     198         [ +  + ]:       80466 :         if ((size_t) idx + 1 < dwfl->lookup_elts
     199         [ +  + ]:       60458 :             && 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                 :             :               return true;
     205                 :             :             resized = true;
     206                 :             :           }
     207                 :             : 
     208         [ +  + ]:       80466 :         if (dwfl->lookup_module == NULL)
     209                 :             :           {
     210                 :       10210 :             dwfl->lookup_module = calloc (dwfl->lookup_alloc,
     211                 :             :                                           sizeof dwfl->lookup_module[0]);
     212         [ +  - ]:       10210 :             if (unlikely (dwfl->lookup_module == NULL))
     213                 :             :               return true;
     214                 :             :           }
     215                 :             : 
     216                 :             :         /* Cache a backpointer in the module.  */
     217                 :       80466 :         mod->segment = idx;
     218                 :             : 
     219                 :             :         /* Put MOD in the table for each segment that's inside it.  */
     220                 :       81182 :         do
     221                 :       81182 :           dwfl->lookup_module[idx++] = mod;
     222                 :       81182 :         while ((size_t) idx < dwfl->lookup_elts
     223   [ +  +  +  + ]:       81182 :                && dwfl->lookup_addr[idx] < end);
     224         [ -  + ]:       80466 :         assert (dwfl->lookup_module[mod->segment] == mod);
     225                 :             : 
     226         [ +  + ]:       80466 :         if (resized && idx - 1 >= highest)
     227                 :             :           /* Expanding the lookup tables invalidated backpointers
     228                 :             :              we've already stored.  Reset those ones.  */
     229                 :       60232 :           fixup = true;
     230                 :             : 
     231                 :       80466 :         highest = idx - 1;
     232         [ +  + ]:       80466 :         hint = (size_t) idx < dwfl->lookup_elts ? idx : -1;
     233                 :             :       }
     234                 :             : 
     235         [ +  + ]:       10506 :   if (fixup)
     236                 :             :     /* Reset backpointer indices invalidated by table insertions.  */
     237         [ +  + ]:      132026 :     for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx)
     238         [ +  + ]:      121840 :       if (dwfl->lookup_module[idx] != NULL)
     239                 :       80988 :         dwfl->lookup_module[idx]->segment = idx;
     240                 :             : 
     241                 :             :   return false;
     242                 :             : }
     243                 :             : 
     244                 :             : int
     245                 :       12630 : dwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod)
     246                 :             : {
     247         [ +  - ]:       12630 :   if (unlikely (dwfl == NULL))
     248                 :             :     return -1;
     249                 :             : 
     250         [ +  + ]:       12630 :   if (unlikely (dwfl->lookup_module == NULL)
     251         [ +  + ]:       11338 :       && mod != NULL
     252         [ -  + ]:       10506 :       && unlikely (reify_segments (dwfl)))
     253                 :             :     {
     254                 :           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     255                 :           0 :       return -1;
     256                 :             :     }
     257                 :             : 
     258                 :       12630 :   int idx = lookup (dwfl, address, -1);
     259         [ +  + ]:       12630 :   if (likely (mod != NULL))
     260                 :             :     {
     261   [ +  +  +  + ]:       11798 :       if (unlikely (idx < 0) || unlikely (dwfl->lookup_module == NULL))
     262                 :         300 :         *mod = NULL;
     263                 :             :       else
     264                 :             :         {
     265                 :       11498 :           *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   [ +  +  +  -  :       11498 :           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         [ +  + ]:       12630 :   if (likely (idx >= 0))
     279                 :             :     /* Translate internal segment table index to user segment index.  */
     280                 :       12626 :     idx = dwfl->lookup_segndx[idx];
     281                 :             : 
     282                 :             :   return idx;
     283                 :             : }
     284                 :             : INTDEF (dwfl_addrsegment)
     285                 :             : 
     286                 :             : int
     287                 :        1590 : 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                 :        1590 :   (void)ident;
     293                 :             : 
     294         [ +  - ]:        1590 :   if (dwfl == NULL)
     295                 :             :     return -1;
     296                 :             : 
     297         [ -  + ]:        1590 :   if (ndx < 0)
     298                 :           0 :     ndx = dwfl->next_segndx;
     299                 :             : 
     300   [ +  -  +  +  :        1590 :   if (phdr->p_align > 1 && (dwfl->segment_align <= 1 ||
                   -  + ]
     301                 :             :                             phdr->p_align < dwfl->segment_align))
     302                 :          78 :     dwfl->segment_align = phdr->p_align;
     303                 :             : 
     304         [ -  + ]:        1590 :   if (unlikely (dwfl->lookup_module != NULL))
     305                 :             :     {
     306                 :           0 :       free (dwfl->lookup_module);
     307                 :           0 :       dwfl->lookup_module = NULL;
     308                 :             :     }
     309                 :             : 
     310                 :        1590 :   GElf_Addr start = __libdwfl_segment_start (dwfl, bias + phdr->p_vaddr);
     311                 :        1590 :   GElf_Addr end = __libdwfl_segment_end (dwfl,
     312                 :        1590 :                                          bias + phdr->p_vaddr + phdr->p_memsz);
     313                 :             : 
     314                 :             :   /* Normally just appending keeps us sorted.  */
     315                 :             : 
     316                 :        1590 :   size_t i = dwfl->lookup_elts;
     317   [ +  +  -  + ]:        1590 :   while (i > 0 && unlikely (start < dwfl->lookup_addr[i - 1]))
     318                 :           0 :     --i;
     319                 :             : 
     320         [ -  + ]:        1590 :   if (unlikely (insert (dwfl, i, start, end, ndx)))
     321                 :             :     {
     322                 :           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     323                 :           0 :       return -1;
     324                 :             :     }
     325                 :             : 
     326                 :        1590 :   dwfl->next_segndx = ndx + 1;
     327                 :             : 
     328                 :        1590 :   return ndx;
     329                 :             : }
     330                 :             : INTDEF (dwfl_report_segment)
        

Generated by: LCOV version 2.0-1