LCOV - code coverage report
Current view: top level - libdw - fde.c (source / functions) Hit Total Coverage
Test: elfutils-0.185 Lines: 106 125 84.8 %
Date: 2021-05-22 21:00:18 Functions: 5 5 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 61 82 74.4 %

           Branch data     Line data    Source code
       1                 :            : /* FDE reading.
       2                 :            :    Copyright (C) 2009-2010, 2014, 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 "cfi.h"
      34                 :            : #include <search.h>
      35                 :            : #include <stdlib.h>
      36                 :            : 
      37                 :            : #include "encoded-value.h"
      38                 :            : 
      39                 :            : static int
      40                 :     303134 : compare_fde (const void *a, const void *b)
      41                 :            : {
      42                 :     303134 :   const struct dwarf_fde *fde1 = a;
      43                 :     303134 :   const struct dwarf_fde *fde2 = b;
      44                 :            : 
      45                 :            :   /* Find out which of the two arguments is the search value.
      46                 :            :      It has end offset 0.  */
      47         [ +  + ]:     303134 :   if (fde1->end == 0)
      48                 :            :     {
      49         [ +  + ]:      70519 :       if (fde1->start < fde2->start)
      50                 :            :         return -1;
      51         [ +  + ]:      62277 :       if (fde1->start >= fde2->end)
      52                 :      62206 :         return 1;
      53                 :            :     }
      54                 :            :   else
      55                 :            :     {
      56         [ +  + ]:     232615 :       if (fde2->start < fde1->start)
      57                 :            :         return 1;
      58         [ +  + ]:      20289 :       if (fde2->start >= fde1->end)
      59                 :      20283 :         return -1;
      60                 :            :     }
      61                 :            : 
      62                 :            :   return 0;
      63                 :            : }
      64                 :            : 
      65                 :            : static struct dwarf_fde *
      66                 :      19015 : intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
      67                 :            : {
      68                 :            :   /* Look up the new entry's CIE.  */
      69                 :      19015 :   struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
      70         [ +  - ]:      19015 :   if (cie == NULL)
      71                 :            :     return (void *) -1l;
      72                 :            : 
      73                 :      19015 :   struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde));
      74         [ -  + ]:      19015 :   if (fde == NULL)
      75                 :            :     {
      76                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
      77                 :          0 :       return NULL;
      78                 :            :     }
      79                 :            : 
      80                 :      19015 :   fde->instructions = entry->start;
      81                 :      19015 :   fde->instructions_end = entry->end;
      82         [ +  - ]:      19015 :   if (unlikely (read_encoded_value (cache, cie->fde_encoding,
      83                 :            :                                     &fde->instructions, &fde->start))
      84         [ -  + ]:      19015 :       || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
      85                 :            :                                        &fde->instructions, &fde->end)))
      86                 :            :     {
      87                 :          0 :       free (fde);
      88                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
      89                 :          0 :       return NULL;
      90                 :            :     }
      91                 :      19015 :   fde->end += fde->start;
      92                 :            : 
      93                 :            :   /* Make sure the fde actually covers a real code range.  */
      94         [ +  + ]:      19015 :   if (fde->start >= fde->end)
      95                 :            :     {
      96                 :          4 :       free (fde);
      97                 :          4 :       return (void *) -1;
      98                 :            :     }
      99                 :            : 
     100                 :      19011 :   fde->cie = cie;
     101                 :            : 
     102         [ +  + ]:      19011 :   if (cie->sized_augmentation_data)
     103                 :            :     {
     104                 :            :       /* The CIE augmentation says the FDE has a DW_FORM_block
     105                 :            :          before its actual instruction stream.  */
     106                 :      18915 :       Dwarf_Word len;
     107                 :      18915 :       get_uleb128 (len, fde->instructions, fde->instructions_end);
     108         [ -  + ]:      18915 :       if ((Dwarf_Word) (fde->instructions_end - fde->instructions) < len)
     109                 :            :         {
     110                 :          0 :           free (fde);
     111                 :          0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     112                 :          0 :           return NULL;
     113                 :            :         }
     114                 :      18915 :       fde->instructions += len;
     115                 :            :     }
     116                 :            :   else
     117                 :            :     /* We had to understand all of the CIE augmentation string.
     118                 :            :        We've recorded the number of data bytes in FDEs.  */
     119                 :         96 :     fde->instructions += cie->fde_augmentation_data_size;
     120                 :            : 
     121                 :            :   /* Add the new entry to the search tree.  */
     122                 :      19011 :   struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde);
     123         [ -  + ]:      19011 :   if (tres == NULL)
     124                 :            :     {
     125                 :          0 :       free (fde);
     126                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
     127                 :          0 :       return NULL;
     128                 :            :     }
     129         [ +  + ]:      19011 :   else if (*tres != fde)
     130                 :            :     {
     131                 :            :       /* There is already an FDE in the cache that covers the same
     132                 :            :          address range.  That is odd.  Ignore this FDE.  And just use
     133                 :            :          the one in the cache for consistency.  */
     134                 :          6 :       free (fde);
     135                 :          6 :       return *tres;
     136                 :            :     }
     137                 :            : 
     138                 :            :   return fde;
     139                 :            : }
     140                 :            : 
     141                 :            : struct dwarf_fde *
     142                 :            : internal_function
     143                 :       6239 : __libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset)
     144                 :            : {
     145                 :       6239 :   Dwarf_CFI_Entry entry;
     146                 :       6239 :   Dwarf_Off next_offset;
     147                 :      12478 :   int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
     148                 :       6239 :                                        &cache->data->d, CFI_IS_EH (cache),
     149                 :            :                                        offset, &next_offset, &entry);
     150         [ -  + ]:       6239 :   if (result != 0)
     151                 :            :     {
     152         [ #  # ]:          0 :       if (result > 0)
     153                 :          0 :       invalid:
     154                 :          0 :         __libdw_seterrno (DWARF_E_INVALID_DWARF);
     155                 :          0 :       return NULL;
     156                 :            :     }
     157                 :            : 
     158         [ -  + ]:       6239 :   if (unlikely (dwarf_cfi_cie_p (&entry)))
     159                 :          0 :     goto invalid;
     160                 :            : 
     161                 :            :   /* We have a new FDE to consider.  */
     162                 :       6239 :   struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
     163         [ +  - ]:       6239 :   if (fde == (void *) -1l || fde == NULL)
     164                 :            :     return NULL;
     165                 :            : 
     166                 :            :   /* If this happened to be what we would have read next, notice it.  */
     167         [ +  + ]:       6239 :   if (cache->next_offset == offset)
     168                 :          2 :     cache->next_offset = next_offset;
     169                 :            : 
     170                 :            :   return fde;
     171                 :            : }
     172                 :            : 
     173                 :            : /* Use a binary search table in .eh_frame_hdr format, yield an FDE offset.  */
     174                 :            : static Dwarf_Off
     175                 :       6242 : binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address)
     176                 :            : {
     177                 :       6242 :   const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident,
     178                 :            :                                               cache->search_table_encoding,
     179                 :            :                                               NULL);
     180         [ +  - ]:       6242 :   if (unlikely (size == 0))
     181                 :            :     return (Dwarf_Off) -1l;
     182                 :            : 
     183                 :            :   /* Dummy used by read_encoded_value.  */
     184                 :       6242 :   Elf_Data_Scn dummy_cfi_hdr_data =
     185                 :            :     {
     186                 :       6242 :       .d = { .d_buf = (void *) cache->search_table,
     187                 :       6242 :              .d_size = cache->search_table_len }
     188                 :            :     };
     189                 :            : 
     190                 :       6242 :   Dwarf_CFI dummy_cfi =
     191                 :            :     {
     192                 :            :       .e_ident = cache->e_ident,
     193                 :            :       .datarel = cache->search_table_vaddr,
     194                 :       6242 :       .frame_vaddr = cache->search_table_vaddr,
     195                 :            :       .data = &dummy_cfi_hdr_data
     196                 :            :     };
     197                 :            : 
     198                 :       6242 :   size_t l = 0, u = cache->search_table_entries;
     199         [ +  + ]:      57721 :   while (l < u)
     200                 :            :     {
     201                 :      57718 :       size_t idx = (l + u) / 2;
     202                 :            : 
     203                 :            :       /* Max idx * size is checked against search_table len when
     204                 :            :          loading eh_frame_hdr.  */
     205                 :      57718 :       const uint8_t *p = &cache->search_table[idx * size];
     206                 :      57718 :       Dwarf_Addr start;
     207         [ +  - ]:      57718 :       if (unlikely (read_encoded_value (&dummy_cfi,
     208                 :            :                                         cache->search_table_encoding, &p,
     209                 :            :                                         &start)))
     210                 :            :         break;
     211         [ +  + ]:      57718 :       if (address < start)
     212                 :      24396 :         u = idx;
     213                 :            :       else
     214                 :            :         {
     215                 :      33322 :           l = idx + 1;
     216                 :            : 
     217                 :      33322 :           Dwarf_Addr fde;
     218         [ +  - ]:      33322 :           if (unlikely (read_encoded_value (&dummy_cfi,
     219                 :            :                                             cache->search_table_encoding, &p,
     220                 :            :                                             &fde)))
     221                 :            :             break;
     222                 :            : 
     223                 :            :           /* If this is the last entry, its upper bound is assumed to be
     224                 :            :              the end of the module.
     225                 :            :              XXX really should be end of containing PT_LOAD segment */
     226         [ +  + ]:      33322 :           if (l < cache->search_table_entries)
     227                 :            :             {
     228                 :            :               /* Look at the start address in the following entry.  */
     229                 :      33312 :               Dwarf_Addr end;
     230         [ +  - ]:      33312 :               if (unlikely (read_encoded_value
     231                 :            :                             (&dummy_cfi, cache->search_table_encoding, &p,
     232                 :            :                              &end)))
     233                 :            :                 break;
     234         [ +  + ]:      33312 :               if (address >= end)
     235                 :      27083 :                 continue;
     236                 :            :             }
     237                 :            : 
     238                 :       6239 :           return fde - cache->frame_vaddr;
     239                 :            :         }
     240                 :            :     }
     241                 :            : 
     242                 :            :   return (Dwarf_Off) -1l;
     243                 :            : }
     244                 :            : 
     245                 :            : struct dwarf_fde *
     246                 :            : internal_function
     247                 :       6475 : __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
     248                 :            : {
     249                 :            :   /* Look for a cached FDE covering this address.  */
     250                 :            : 
     251                 :       6475 :   const struct dwarf_fde fde_key = { .start = address, .end = 0 };
     252                 :       6475 :   struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
     253         [ +  + ]:       6475 :   if (found != NULL)
     254                 :         71 :     return *found;
     255                 :            : 
     256                 :            :   /* Use .eh_frame_hdr binary search table if possible.  */
     257         [ +  + ]:       6404 :   if (cache->search_table != NULL)
     258                 :            :     {
     259                 :       6242 :       Dwarf_Off offset = binary_search_fde (cache, address);
     260         [ +  + ]:       6242 :       if (offset == (Dwarf_Off) -1l)
     261                 :          3 :         goto no_match;
     262                 :       6239 :       struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
     263         [ +  - ]:       6239 :       if (likely (fde != NULL))
     264                 :            :         {
     265                 :            :           /* Sanity check the address range.  */
     266         [ -  + ]:       6239 :           if (unlikely (address < fde->start))
     267                 :            :             {
     268                 :          0 :               __libdw_seterrno (DWARF_E_INVALID_DWARF);
     269                 :          0 :               return NULL;
     270                 :            :             }
     271                 :            :           /* .eh_frame_hdr does not indicate length covered by FDE.  */
     272         [ +  + ]:       6239 :           if (unlikely (address >= fde->end))
     273                 :         10 :             goto no_match;
     274                 :            :         }
     275                 :            :       return fde;
     276                 :            :     }
     277                 :            : 
     278                 :            :   /* It's not there.  Read more CFI entries until we find it.  */
     279                 :      12995 :   while (1)
     280                 :            :     {
     281                 :      12995 :       Dwarf_Off last_offset = cache->next_offset;
     282                 :      12995 :       Dwarf_CFI_Entry entry;
     283                 :      25990 :       int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
     284                 :      12995 :                                            &cache->data->d, CFI_IS_EH (cache),
     285                 :            :                                            last_offset, &cache->next_offset,
     286                 :            :                                            &entry);
     287         [ +  + ]:      12995 :       if (result > 0)
     288                 :            :         break;
     289         [ -  + ]:      12874 :       if (result < 0)
     290                 :            :         {
     291         [ #  # ]:          0 :           if (cache->next_offset == last_offset)
     292                 :            :             /* We couldn't progress past the bogus FDE.  */
     293                 :            :             break;
     294                 :            :           /* Skip the loser and look at the next entry.  */
     295                 :        102 :           continue;
     296                 :            :         }
     297                 :            : 
     298         [ +  + ]:      12874 :       if (dwarf_cfi_cie_p (&entry))
     299                 :            :         {
     300                 :            :           /* This is a CIE, not an FDE.  We eagerly intern these
     301                 :            :              because the next FDE will usually refer to this CIE.  */
     302                 :         98 :           __libdw_intern_cie (cache, last_offset, &entry.cie);
     303                 :         98 :           continue;
     304                 :            :         }
     305                 :            : 
     306                 :            :       /* We have a new FDE to consider.  */
     307                 :      12776 :       struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
     308                 :            : 
     309         [ +  + ]:      12776 :       if (fde == (void *) -1l)  /* Bad FDE, but we can keep looking.  */
     310                 :          4 :         continue;
     311                 :            : 
     312         [ +  - ]:      12772 :       if (fde == NULL)          /* Bad data.  */
     313                 :         41 :         return NULL;
     314                 :            : 
     315                 :            :       /* Is this the one we're looking for?  */
     316   [ +  +  +  + ]:      12772 :       if (fde->start <= address && fde->end > address)
     317                 :         41 :         return fde;
     318                 :            :     }
     319                 :            : 
     320                 :        134 :  no_match:
     321                 :            :   /* We found no FDE covering this address.  */
     322                 :        134 :   __libdw_seterrno (DWARF_E_NO_MATCH);
     323                 :        134 :   return NULL;
     324                 :            : }

Generated by: LCOV version 1.14