LCOV - code coverage report
Current view: top level - libdw - dwarf_getcfi_elf.c (source / functions) Hit Total Coverage
Test: elfutils-0.172 Lines: 102 127 80.3 %
Date: 2018-06-11 22:52:14 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13