LCOV - code coverage report
Current view: top level - libdw - dwarf_getcfi_elf.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 118 143 82.5 %
Date: 2024-04-15 17:09:43 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 90 61.1 %

           Branch data     Line data    Source code
       1                 :            : /* Get CFI from ELF file's exception-handling info.
       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 <stdlib.h>
      34                 :            : #include <string.h>
      35                 :            : #include <assert.h>
      36                 :            : 
      37                 :            : #include "libdwP.h"
      38                 :            : #include "cfi.h"
      39                 :            : #include "encoded-value.h"
      40                 :            : #include <dwarf.h>
      41                 :            : 
      42                 :            : 
      43                 :            : static Dwarf_CFI *
      44                 :        152 : allocate_cfi (Elf *elf, const GElf_Ehdr *ehdr, GElf_Addr vaddr)
      45                 :            : {
      46                 :        152 :   Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
      47         [ -  + ]:        152 :   if (cfi == NULL)
      48                 :            :     {
      49                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
      50                 :          0 :       return NULL;
      51                 :            :     }
      52                 :            : 
      53                 :        152 :   cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
      54         [ -  + ]:        152 :   if (cfi->e_ident == NULL)
      55                 :            :     {
      56                 :          0 :       free (cfi);
      57                 :          0 :       __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
      58                 :          0 :       return NULL;
      59                 :            :     }
      60                 :            : 
      61                 :        152 :   cfi->e_machine = ehdr->e_machine;
      62                 :            : 
      63         [ +  + ]:        152 :   if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
      64                 :            :       || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
      65                 :         18 :     cfi->other_byte_order = true;
      66                 :            : 
      67                 :        152 :   cfi->frame_vaddr = vaddr;
      68                 :        152 :   cfi->textrel = 0;          /* XXX ? */
      69                 :        152 :   cfi->datarel = 0;          /* XXX ? */
      70                 :            : 
      71                 :        152 :   return cfi;
      72                 :            : }
      73                 :            : 
      74                 :            : static const uint8_t *
      75                 :        118 : parse_eh_frame_hdr (const uint8_t *hdr, size_t hdr_size, GElf_Addr hdr_vaddr,
      76                 :            :                     const GElf_Ehdr *ehdr, GElf_Addr *eh_frame_vaddr,
      77                 :            :                     size_t *table_entries, uint8_t *table_encoding)
      78                 :            : {
      79                 :        118 :   const uint8_t *h = hdr;
      80                 :            : 
      81   [ +  -  -  + ]:        118 :   if (hdr_size < 4 || *h++ != 1)             /* version */
      82                 :            :     return (void *) -1l;
      83                 :            : 
      84                 :        118 :   uint8_t eh_frame_ptr_encoding = *h++;
      85                 :        118 :   uint8_t fde_count_encoding = *h++;
      86                 :        118 :   uint8_t fde_table_encoding = *h++;
      87                 :            : 
      88         [ -  + ]:        118 :   if (eh_frame_ptr_encoding == DW_EH_PE_omit)
      89                 :            :     return (void *) -1l;
      90                 :            : 
      91                 :            :   /* Dummy used by read_encoded_value.  */
      92                 :        118 :   Elf_Data_Scn dummy_cfi_hdr_data =
      93                 :            :     {
      94                 :            :       .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
      95                 :            :     };
      96                 :        118 :   Dwarf_CFI dummy_cfi =
      97                 :            :     {
      98                 :        118 :       .e_ident = ehdr->e_ident,
      99                 :            :       .datarel = hdr_vaddr,
     100                 :            :       .frame_vaddr = hdr_vaddr,
     101                 :            :       .data = &dummy_cfi_hdr_data,
     102                 :            :     };
     103                 :            : 
     104         [ -  + ]:        118 :   if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
     105                 :            :                                     eh_frame_vaddr)))
     106                 :            :     return (void *) -1l;
     107                 :            : 
     108         [ +  - ]:        118 :   if (fde_count_encoding != DW_EH_PE_omit)
     109                 :            :     {
     110                 :        118 :       Dwarf_Word fde_count;
     111         [ +  - ]:        118 :       if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
     112                 :            :                                         &fde_count)))
     113                 :        118 :         return (void *) -1l;
     114         [ +  - ]:        118 :       if (fde_count != 0 && (size_t) fde_count == fde_count
     115         [ +  - ]:        118 :           && fde_table_encoding != DW_EH_PE_omit
     116         [ +  - ]:        118 :           && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
     117                 :            :         {
     118                 :        118 :           *table_entries = fde_count;
     119                 :        118 :           *table_encoding = fde_table_encoding;
     120                 :        118 :           return h;
     121                 :            :         }
     122                 :            :     }
     123                 :            : 
     124                 :            :   return NULL;
     125                 :            : }
     126                 :            : 
     127                 :            : static Dwarf_CFI *
     128                 :          2 : getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
     129                 :            : {
     130                 :          2 :   Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
     131                 :            :                                          ELF_T_BYTE);
     132   [ -  +  -  + ]:          2 :   if (data == NULL || data->d_buf == NULL)
     133                 :            :     {
     134                 :          0 :     invalid_hdr:
     135                 :            :       /* XXX might be read error or corrupt phdr */
     136                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_CFI);
     137                 :          0 :       return NULL;
     138                 :            :     }
     139                 :            : 
     140                 :          2 :   size_t vsize, dmax;
     141                 :          2 :   Dwarf_Addr eh_frame_ptr;
     142                 :          2 :   size_t search_table_entries = 0;
     143                 :          2 :   uint8_t search_table_encoding = 0;
     144                 :          4 :   const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
     145                 :          2 :                                                     phdr->p_vaddr, ehdr,
     146                 :            :                                                     &eh_frame_ptr,
     147                 :            :                                                     &search_table_entries,
     148                 :            :                                                     &search_table_encoding);
     149                 :            : 
     150                 :            :   /* Make sure there is enough room for the entries in the table,
     151                 :            :      each entry consists of 2 encoded values.  */
     152                 :          2 :   vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
     153                 :            :                               NULL);
     154                 :          2 :   dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
     155   [ +  -  -  + ]:          2 :   if (unlikely (search_table == (void *) -1l
     156                 :            :                 || vsize == 0
     157                 :            :                 || search_table_entries > (dmax / vsize) / 2))
     158                 :          0 :     goto invalid_hdr;
     159                 :            : 
     160                 :          2 :   Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
     161                 :          2 :   Dwarf_Word eh_frame_size = 0;
     162                 :            : 
     163                 :            :   /* XXX we have no way without section headers to know the size
     164                 :            :      of the .eh_frame data.  Calculate the largest it might possibly be.
     165                 :            :      This won't be wasteful if the file is already mmap'd, but if it isn't
     166                 :            :      it might be quite excessive.  */
     167                 :          2 :   size_t filesize;
     168         [ +  - ]:          2 :   if (elf_rawfile (elf, &filesize) != NULL)
     169                 :          2 :     eh_frame_size = filesize - eh_frame_offset;
     170                 :            : 
     171                 :          2 :   data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
     172         [ -  + ]:          2 :   if (data == NULL)
     173                 :            :     {
     174                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
     175                 :          0 :       return NULL;
     176                 :            :     }
     177                 :          2 :   Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, eh_frame_ptr);
     178         [ +  - ]:          2 :   if (cfi != NULL)
     179                 :            :     {
     180                 :          2 :       cfi->data = (Elf_Data_Scn *) data;
     181                 :            : 
     182         [ -  + ]:          2 :       if (search_table != NULL)
     183                 :            :         {
     184                 :          2 :           cfi->search_table = search_table;
     185                 :          2 :           cfi->search_table_len = phdr->p_filesz;
     186                 :          2 :           cfi->search_table_vaddr = phdr->p_vaddr;
     187                 :          2 :           cfi->search_table_encoding = search_table_encoding;
     188                 :          2 :           cfi->search_table_entries = search_table_entries;
     189                 :            :         }
     190                 :            :     }
     191                 :            :   return cfi;
     192                 :            : }
     193                 :            : 
     194                 :            : /* Search the phdrs for PT_GNU_EH_FRAME.  */
     195                 :            : static Dwarf_CFI *
     196                 :         18 : getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
     197                 :            : {
     198                 :         18 :   size_t phnum;
     199         [ -  + ]:         18 :   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
     200                 :            :     return NULL;
     201                 :            : 
     202         [ +  + ]:         30 :   for (size_t i = 0; i < phnum; ++i)
     203                 :            :     {
     204                 :         14 :       GElf_Phdr phdr_mem;
     205                 :         14 :       GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
     206         [ +  - ]:         14 :       if (unlikely (phdr == NULL))
     207                 :          2 :         return NULL;
     208         [ +  + ]:         14 :       if (phdr->p_type == PT_GNU_EH_FRAME)
     209                 :          2 :         return getcfi_gnu_eh_frame (elf, ehdr, phdr);
     210                 :            :     }
     211                 :            : 
     212                 :         16 :   __libdw_seterrno (DWARF_E_NO_DWARF);
     213                 :         16 :   return NULL;
     214                 :            : }
     215                 :            : 
     216                 :            : static Dwarf_CFI *
     217                 :        150 : getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
     218                 :            :                      Elf_Scn *scn, GElf_Shdr *shdr,
     219                 :            :                      Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
     220                 :            : {
     221                 :        150 :   Elf_Data *data = elf_rawdata (scn, NULL);
     222   [ +  -  -  + ]:        150 :   if (data == NULL || data->d_buf == NULL)
     223                 :            :     {
     224                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_ELF);
     225                 :          0 :       return NULL;
     226                 :            :     }
     227                 :        150 :   Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, shdr->sh_addr);
     228         [ +  - ]:        150 :   if (cfi != NULL)
     229                 :            :     {
     230                 :        150 :       cfi->data = (Elf_Data_Scn *) data;
     231         [ +  + ]:        150 :       if (hdr_scn != NULL)
     232                 :            :         {
     233                 :        116 :           Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
     234   [ -  +  -  + ]:        116 :           if (hdr_data != NULL && hdr_data->d_buf != NULL)
     235                 :            :             {
     236                 :        116 :               size_t vsize, dmax;
     237                 :        116 :               GElf_Addr eh_frame_vaddr;
     238                 :        116 :               cfi->search_table_vaddr = hdr_vaddr;
     239                 :        116 :               cfi->search_table
     240                 :        116 :                 = parse_eh_frame_hdr (hdr_data->d_buf, hdr_data->d_size,
     241                 :            :                                       hdr_vaddr, ehdr, &eh_frame_vaddr,
     242                 :            :                                       &cfi->search_table_entries,
     243                 :            :                                       &cfi->search_table_encoding);
     244                 :        116 :               cfi->search_table_len = hdr_data->d_size;
     245                 :            : 
     246                 :            :               /* Make sure there is enough room for the entries in the table,
     247                 :            :                  each entry consists of 2 encoded values.  */
     248                 :        232 :               vsize = encoded_value_size (hdr_data, ehdr->e_ident,
     249                 :        116 :                                           cfi->search_table_encoding, NULL);
     250                 :        116 :               dmax = hdr_data->d_size - (cfi->search_table
     251                 :        116 :                                          - (const uint8_t *) hdr_data->d_buf);
     252   [ +  -  +  -  :        116 :               if (unlikely (cfi->search_table == (void *) -1l
                   -  + ]
     253                 :            :                             || vsize == 0
     254                 :            :                             || cfi->search_table_entries > (dmax / vsize) / 2))
     255                 :            :                 {
     256                 :          0 :                   free (cfi);
     257                 :            :                   /* XXX might be read error or corrupt phdr */
     258                 :          0 :                   __libdw_seterrno (DWARF_E_INVALID_CFI);
     259                 :          0 :                   return NULL;
     260                 :            :                 }
     261                 :            : 
     262                 :            :               /* Sanity check.  */
     263         [ -  + ]:        116 :               if (unlikely (eh_frame_vaddr != shdr->sh_addr))
     264                 :          0 :                 cfi->search_table = NULL;
     265                 :            :             }
     266                 :            :         }
     267                 :            :     }
     268                 :            :   return cfi;
     269                 :            : }
     270                 :            : 
     271                 :            : /* Search for the sections named ".eh_frame" and ".eh_frame_hdr".  */
     272                 :            : static Dwarf_CFI *
     273                 :        184 : getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
     274                 :            : {
     275                 :        184 :   size_t shstrndx;
     276         [ -  + ]:        184 :   if (elf_getshdrstrndx (elf, &shstrndx) != 0)
     277                 :            :     {
     278                 :          0 :       __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
     279                 :          0 :       return NULL;
     280                 :            :     }
     281                 :            : 
     282         [ +  + ]:        184 :   if (shstrndx != 0)
     283                 :            :     {
     284                 :            :       Elf_Scn *hdr_scn = NULL;
     285                 :            :       GElf_Addr hdr_vaddr = 0;
     286                 :            :       Elf_Scn *scn = NULL;
     287         [ +  + ]:       3244 :       while ((scn = elf_nextscn (elf, scn)) != NULL)
     288                 :            :         {
     289                 :       3228 :           GElf_Shdr shdr_mem;
     290                 :       3228 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     291         [ -  + ]:       3228 :           if (shdr == NULL)
     292                 :          0 :             continue;
     293                 :       3228 :           const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
     294         [ -  + ]:       3228 :           if (name == NULL)
     295                 :          0 :             continue;
     296         [ +  + ]:       3228 :           if (!strcmp (name, ".eh_frame_hdr"))
     297                 :            :             {
     298                 :        132 :               hdr_scn = scn;
     299                 :        132 :               hdr_vaddr = shdr->sh_addr;
     300                 :            :             }
     301         [ +  + ]:       3096 :           else if (!strcmp (name, ".eh_frame"))
     302                 :            :             {
     303         [ +  + ]:        166 :               if (shdr->sh_type != SHT_NOBITS)
     304                 :        166 :                 return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
     305                 :            :                                             hdr_scn, hdr_vaddr);
     306                 :            :               else
     307                 :            :                 return NULL;
     308                 :            :             }
     309                 :            :         }
     310                 :            :     }
     311                 :            : 
     312                 :            :   return (void *) -1l;
     313                 :            : }
     314                 :            : 
     315                 :            : Dwarf_CFI *
     316                 :        184 : dwarf_getcfi_elf (Elf *elf)
     317                 :            : {
     318         [ -  + ]:        184 :   if (elf_kind (elf) != ELF_K_ELF)
     319                 :            :     {
     320                 :          0 :       __libdw_seterrno (DWARF_E_NOELF);
     321                 :          0 :       return NULL;
     322                 :            :     }
     323                 :            : 
     324                 :        184 :   GElf_Ehdr ehdr_mem;
     325                 :        184 :   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     326         [ -  + ]:        184 :   if (unlikely (ehdr == NULL))
     327                 :            :     {
     328                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_ELF);
     329                 :          0 :       return NULL;
     330                 :            :     }
     331                 :            : 
     332                 :        184 :   Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
     333         [ +  + ]:        184 :   if (result == (void *) -1l)
     334                 :         18 :     result = getcfi_phdr (elf, ehdr);
     335                 :            : 
     336                 :            :   return result;
     337                 :            : }
     338                 :            : INTDEF (dwarf_getcfi_elf)

Generated by: LCOV version 1.16