LCOV - code coverage report
Current view: top level - libdw - fde.c (source / functions) Hit Total Coverage
Test: elfutils-0.176 Lines: 93 112 83.0 %
Date: 2019-02-15 17:57:54 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          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      254063 : compare_fde (const void *a, const void *b)
      41             : {
      42      254063 :   const struct dwarf_fde *fde1 = a;
      43      254063 :   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      254063 :   if (fde1->end == 0)
      48             :     {
      49       46018 :       if (fde1->start < fde2->start)
      50             :         return -1;
      51       39329 :       if (fde1->start >= fde2->end)
      52             :         return 1;
      53             :     }
      54             :   else
      55             :     {
      56      208045 :       if (fde2->start < fde1->start)
      57             :         return 1;
      58       18683 :       if (fde2->start >= fde1->end)
      59             :         return -1;
      60             :     }
      61             : 
      62          74 :   return 0;
      63             : }
      64             : 
      65             : static struct dwarf_fde *
      66       17441 : intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
      67             : {
      68             :   /* Look up the new entry's CIE.  */
      69       17441 :   struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
      70       17441 :   if (cie == NULL)
      71             :     return (void *) -1l;
      72             : 
      73       17441 :   struct dwarf_fde *fde = malloc (sizeof (struct dwarf_fde));
      74       17441 :   if (fde == NULL)
      75             :     {
      76           0 :       __libdw_seterrno (DWARF_E_NOMEM);
      77           0 :       return NULL;
      78             :     }
      79             : 
      80       17441 :   fde->instructions = entry->start;
      81       17441 :   fde->instructions_end = entry->end;
      82       17441 :   if (unlikely (read_encoded_value (cache, cie->fde_encoding,
      83             :                                     &fde->instructions, &fde->start))
      84       17441 :       || 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       17441 :   fde->end += fde->start;
      92             : 
      93             :   /* Make sure the fde actually covers a real code range.  */
      94       17441 :   if (fde->start >= fde->end)
      95             :     {
      96           4 :       free (fde);
      97           4 :       return (void *) -1;
      98             :     }
      99             : 
     100       17437 :   fde->cie = cie;
     101             : 
     102       17437 :   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             :       Dwarf_Word len;
     107       17343 :       get_uleb128 (len, fde->instructions, fde->instructions_end);
     108       17343 :       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       17343 :       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          94 :     fde->instructions += cie->fde_augmentation_data_size;
     120             : 
     121             :   /* Add the new entry to the search tree.  */
     122       17437 :   struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde);
     123       17437 :   if (tres == NULL)
     124             :     {
     125           0 :       free (fde);
     126           0 :       __libdw_seterrno (DWARF_E_NOMEM);
     127           0 :       return NULL;
     128             :     }
     129       17437 :   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           0 :       free (fde);
     135           0 :       return *tres;
     136             :     }
     137             : 
     138             :   return fde;
     139             : }
     140             : 
     141             : struct dwarf_fde *
     142             : internal_function
     143        4665 : __libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset)
     144             : {
     145             :   Dwarf_CFI_Entry entry;
     146             :   Dwarf_Off next_offset;
     147        9330 :   int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
     148        9330 :                                        &cache->data->d, CFI_IS_EH (cache),
     149             :                                        offset, &next_offset, &entry);
     150        4665 :   if (result != 0)
     151             :     {
     152           0 :       if (result > 0)
     153           0 :       invalid:
     154           0 :         __libdw_seterrno (DWARF_E_INVALID_DWARF);
     155             :       return NULL;
     156             :     }
     157             : 
     158        4665 :   if (unlikely (dwarf_cfi_cie_p (&entry)))
     159             :     goto invalid;
     160             : 
     161             :   /* We have a new FDE to consider.  */
     162        4665 :   struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
     163        4665 :   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        4665 :   if (cache->next_offset == offset)
     168           9 :     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        4668 : binary_search_fde (Dwarf_CFI *cache, Dwarf_Addr address)
     176             : {
     177        9336 :   const size_t size = 2 * encoded_value_size (&cache->data->d, cache->e_ident,
     178        4668 :                                               cache->search_table_encoding,
     179             :                                               NULL);
     180        4668 :   if (unlikely (size == 0))
     181             :     return (Dwarf_Off) -1l;
     182             : 
     183             :   /* Dummy used by read_encoded_value.  */
     184       14004 :   Elf_Data_Scn dummy_cfi_hdr_data =
     185             :     {
     186        4668 :       .d = { .d_buf = (void *) cache->search_table,
     187        4668 :              .d_size = cache->search_table_len }
     188             :     };
     189             : 
     190        9336 :   Dwarf_CFI dummy_cfi =
     191             :     {
     192             :       .e_ident = cache->e_ident,
     193             :       .datarel = cache->search_table_vaddr,
     194        4668 :       .frame_vaddr = cache->search_table_vaddr,
     195             :       .data = &dummy_cfi_hdr_data
     196             :     };
     197             : 
     198        4668 :   size_t l = 0, u = cache->search_table_entries;
     199       42669 :   while (l < u)
     200             :     {
     201       37998 :       size_t idx = (l + u) / 2;
     202             : 
     203             :       /* Max idx * size is checked against search_table len when
     204             :          loading eh_frame_hdr.  */
     205       37998 :       const uint8_t *p = &cache->search_table[idx * size];
     206             :       Dwarf_Addr start;
     207       37998 :       if (unlikely (read_encoded_value (&dummy_cfi,
     208             :                                         cache->search_table_encoding, &p,
     209             :                                         &start)))
     210             :         break;
     211       37998 :       if (address < start)
     212       16152 :         u = idx;
     213             :       else
     214             :         {
     215       21846 :           l = idx + 1;
     216             : 
     217             :           Dwarf_Addr fde;
     218       21846 :           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       21846 :           if (l < cache->search_table_entries)
     227             :             {
     228             :               /* Look at the start address in the following entry.  */
     229             :               Dwarf_Addr end;
     230       21839 :               if (unlikely (read_encoded_value
     231             :                             (&dummy_cfi, cache->search_table_encoding, &p,
     232             :                              &end)))
     233             :                 break;
     234       21839 :               if (address >= end)
     235       17181 :                 continue;
     236             :             }
     237             : 
     238        4665 :           return fde - cache->frame_vaddr;
     239             :         }
     240             :     }
     241             : 
     242             :   return (Dwarf_Off) -1l;
     243             : }
     244             : 
     245             : struct dwarf_fde *
     246             : internal_function
     247        4903 : __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
     248             : {
     249             :   /* Look for a cached FDE covering this address.  */
     250             : 
     251        4903 :   const struct dwarf_fde fde_key = { .start = address, .end = 0 };
     252        4903 :   struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
     253        4903 :   if (found != NULL)
     254          74 :     return *found;
     255             : 
     256             :   /* Use .eh_frame_hdr binary search table if possible.  */
     257        4829 :   if (cache->search_table != NULL)
     258             :     {
     259        4668 :       Dwarf_Off offset = binary_search_fde (cache, address);
     260        4668 :       if (offset == (Dwarf_Off) -1l)
     261             :         goto no_match;
     262        4665 :       struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
     263        4665 :       if (likely (fde != NULL))
     264             :         {
     265             :           /* Sanity check the address range.  */
     266        4665 :           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        4665 :           if (unlikely (address >= fde->end))
     273             :             goto no_match;
     274             :         }
     275             :       return fde;
     276             :     }
     277             : 
     278             :   /* It's not there.  Read more CFI entries until we find it.  */
     279             :   while (1)
     280             :     {
     281       12993 :       Dwarf_Off last_offset = cache->next_offset;
     282             :       Dwarf_CFI_Entry entry;
     283       38979 :       int result = INTUSE(dwarf_next_cfi) (cache->e_ident,
     284       25986 :                                            &cache->data->d, CFI_IS_EH (cache),
     285             :                                            last_offset, &cache->next_offset,
     286             :                                            &entry);
     287       12993 :       if (result > 0)
     288             :         break;
     289       12872 :       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         100 :           continue;
     296             :         }
     297             : 
     298       12872 :       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          96 :           __libdw_intern_cie (cache, last_offset, &entry.cie);
     303          96 :           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          40 :         return NULL;
     314             : 
     315             :       /* Is this the one we're looking for?  */
     316       12772 :       if (fde->start <= address && fde->end > address)
     317             :         return fde;
     318             :     }
     319             : 
     320           3 :  no_match:
     321             :   /* We found no FDE covering this address.  */
     322         124 :   __libdw_seterrno (DWARF_E_NO_MATCH);
     323         124 :   return NULL;
     324             : }

Generated by: LCOV version 1.13