LCOV - code coverage report
Current view: top level - libdw - dwarf_getcfi_elf.c (source / functions) Hit Total Coverage
Test: elfutils-0.181 Lines: 82 141 58.2 %
Date: 2020-09-08 14:07:57 Functions: 5 7 71.4 %
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           0 : allocate_cfi (Elf *elf, const GElf_Ehdr *ehdr, GElf_Addr vaddr)
      45             : {
      46           0 :   Dwarf_CFI *cfi = calloc (1, sizeof *cfi);
      47           0 :   if (cfi == NULL)
      48             :     {
      49           0 :       __libdw_seterrno (DWARF_E_NOMEM);
      50           0 :       return NULL;
      51             :     }
      52             : 
      53           0 :   cfi->e_ident = (unsigned char *) elf_getident (elf, NULL);
      54           0 :   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           0 :   cfi->e_machine = ehdr->e_machine;
      62             : 
      63           0 :   if ((BYTE_ORDER == LITTLE_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2MSB)
      64             :       || (BYTE_ORDER == BIG_ENDIAN && cfi->e_ident[EI_DATA] == ELFDATA2LSB))
      65           0 :     cfi->other_byte_order = true;
      66             : 
      67           0 :   cfi->frame_vaddr = vaddr;
      68           0 :   cfi->textrel = 0;          /* XXX ? */
      69           0 :   cfi->datarel = 0;          /* XXX ? */
      70             : 
      71           0 :   return cfi;
      72             : }
      73             : 
      74             : static const uint8_t *
      75          67 : 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          67 :   const uint8_t *h = hdr;
      80             : 
      81          67 :   if (hdr_size < 4 || *h++ != 1)             /* version */
      82           0 :     return (void *) -1l;
      83             : 
      84          67 :   uint8_t eh_frame_ptr_encoding = *h++;
      85          67 :   uint8_t fde_count_encoding = *h++;
      86          67 :   uint8_t fde_table_encoding = *h++;
      87             : 
      88          67 :   if (eh_frame_ptr_encoding == DW_EH_PE_omit)
      89             :     return (void *) -1l;
      90             : 
      91             :   /* Dummy used by read_encoded_value.  */
      92          67 :   Elf_Data_Scn dummy_cfi_hdr_data =
      93             :     {
      94             :       .d = { .d_buf = (void *) hdr, .d_size = hdr_size }
      95             :     };
      96         134 :   Dwarf_CFI dummy_cfi =
      97             :     {
      98          67 :       .e_ident = ehdr->e_ident,
      99             :       .datarel = hdr_vaddr,
     100             :       .frame_vaddr = hdr_vaddr,
     101             :       .data = &dummy_cfi_hdr_data,
     102             :     };
     103             : 
     104          67 :   if (unlikely (read_encoded_value (&dummy_cfi, eh_frame_ptr_encoding, &h,
     105             :                                     eh_frame_vaddr)))
     106             :     return (void *) -1l;
     107             : 
     108          67 :   if (fde_count_encoding != DW_EH_PE_omit)
     109             :     {
     110          67 :       Dwarf_Word fde_count;
     111          67 :       if (unlikely (read_encoded_value (&dummy_cfi, fde_count_encoding, &h,
     112             :                                         &fde_count)))
     113          67 :         return (void *) -1l;
     114          67 :       if (fde_count != 0 && (size_t) fde_count == fde_count
     115          67 :           && fde_table_encoding != DW_EH_PE_omit
     116          67 :           && (fde_table_encoding &~ DW_EH_PE_signed) != DW_EH_PE_uleb128)
     117             :         {
     118          67 :           *table_entries = fde_count;
     119          67 :           *table_encoding = fde_table_encoding;
     120          67 :           return h;
     121             :         }
     122             :     }
     123             : 
     124             :   return NULL;
     125             : }
     126             : 
     127             : static Dwarf_CFI *
     128           1 : getcfi_gnu_eh_frame (Elf *elf, const GElf_Ehdr *ehdr, const GElf_Phdr *phdr)
     129             : {
     130           1 :   Elf_Data *data = elf_getdata_rawchunk (elf, phdr->p_offset, phdr->p_filesz,
     131             :                                          ELF_T_BYTE);
     132           1 :   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           1 :   size_t vsize, dmax;
     141           1 :   Dwarf_Addr eh_frame_ptr;
     142           1 :   size_t search_table_entries = 0;
     143           1 :   uint8_t search_table_encoding = 0;
     144           1 :   const uint8_t *search_table = parse_eh_frame_hdr (data->d_buf, phdr->p_filesz,
     145             :                                                     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           1 :   vsize = encoded_value_size (data, ehdr->e_ident, search_table_encoding,
     153             :                               NULL);
     154           1 :   dmax = phdr->p_filesz - (search_table - (const uint8_t *) data->d_buf);
     155           1 :   if (unlikely (search_table == (void *) -1l
     156             :                 || vsize == 0
     157             :                 || search_table_entries > (dmax / vsize) / 2))
     158             :     goto invalid_hdr;
     159             : 
     160           1 :   Dwarf_Off eh_frame_offset = eh_frame_ptr - phdr->p_vaddr + phdr->p_offset;
     161           1 :   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           1 :   size_t filesize;
     168           1 :   if (elf_rawfile (elf, &filesize) != NULL)
     169           1 :     eh_frame_size = filesize - eh_frame_offset;
     170             : 
     171           1 :   data = elf_getdata_rawchunk (elf, eh_frame_offset, eh_frame_size, ELF_T_BYTE);
     172           1 :   if (data == NULL)
     173             :     {
     174           0 :       __libdw_seterrno (DWARF_E_INVALID_ELF); /* XXX might be read error */
     175           0 :       return NULL;
     176             :     }
     177           1 :   Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, eh_frame_ptr);
     178           1 :   if (cfi != NULL)
     179             :     {
     180           1 :       cfi->data = (Elf_Data_Scn *) data;
     181             : 
     182           1 :       if (search_table != NULL)
     183             :         {
     184           1 :           cfi->search_table = search_table;
     185           1 :           cfi->search_table_len = phdr->p_filesz;
     186           1 :           cfi->search_table_vaddr = phdr->p_vaddr;
     187           1 :           cfi->search_table_encoding = search_table_encoding;
     188           1 :           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           1 : getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
     197             : {
     198           1 :   size_t phnum;
     199           1 :   if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
     200             :     return NULL;
     201             : 
     202           7 :   for (size_t i = 0; i < phnum; ++i)
     203             :     {
     204           7 :       GElf_Phdr phdr_mem;
     205           7 :       GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
     206           7 :       if (unlikely (phdr == NULL))
     207           1 :         return NULL;
     208           7 :       if (phdr->p_type == PT_GNU_EH_FRAME)
     209           1 :         return getcfi_gnu_eh_frame (elf, ehdr, phdr);
     210             :     }
     211             : 
     212           0 :   __libdw_seterrno (DWARF_E_NO_DWARF);
     213           0 :   return NULL;
     214             : }
     215             : 
     216             : static Dwarf_CFI *
     217           0 : 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           0 :   Elf_Data *data = elf_rawdata (scn, NULL);
     222           0 :   if (data == NULL || data->d_buf == NULL)
     223             :     {
     224           0 :       __libdw_seterrno (DWARF_E_INVALID_ELF);
     225           0 :       return NULL;
     226             :     }
     227           0 :   Dwarf_CFI *cfi = allocate_cfi (elf, ehdr, shdr->sh_addr);
     228           0 :   if (cfi != NULL)
     229             :     {
     230           0 :       cfi->data = (Elf_Data_Scn *) data;
     231           0 :       if (hdr_scn != NULL)
     232             :         {
     233           0 :           Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
     234           0 :           if (hdr_data != NULL && hdr_data->d_buf != NULL)
     235             :             {
     236           0 :               size_t vsize, dmax;
     237           0 :               GElf_Addr eh_frame_vaddr;
     238           0 :               cfi->search_table_vaddr = hdr_vaddr;
     239           0 :               cfi->search_table
     240           0 :                 = 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           0 :               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           0 :               vsize = encoded_value_size (hdr_data, ehdr->e_ident,
     249           0 :                                           cfi->search_table_encoding, NULL);
     250           0 :               dmax = hdr_data->d_size - (cfi->search_table
     251           0 :                                          - (const uint8_t *) hdr_data->d_buf);
     252           0 :               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           0 :               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          92 : getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
     274             : {
     275          92 :   size_t shstrndx;
     276          92 :   if (elf_getshdrstrndx (elf, &shstrndx) != 0)
     277             :     {
     278           0 :       __libdw_seterrno (DWARF_E_GETEHDR_ERROR);
     279           0 :       return NULL;
     280             :     }
     281             : 
     282          92 :   if (shstrndx != 0)
     283             :     {
     284             :       Elf_Scn *hdr_scn = NULL;
     285             :       GElf_Addr hdr_vaddr = 0;
     286             :       Elf_Scn *scn = NULL;
     287        1600 :       while ((scn = elf_nextscn (elf, scn)) != NULL)
     288             :         {
     289        1600 :           GElf_Shdr shdr_mem;
     290        1600 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     291        1600 :           if (shdr == NULL)
     292           0 :             continue;
     293        1600 :           const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
     294        1600 :           if (name == NULL)
     295             :             continue;
     296        1600 :           if (!strcmp (name, ".eh_frame_hdr"))
     297             :             {
     298          74 :               hdr_scn = scn;
     299          74 :               hdr_vaddr = shdr->sh_addr;
     300             :             }
     301        1526 :           else if (!strcmp (name, ".eh_frame"))
     302             :             {
     303          91 :               if (shdr->sh_type != SHT_NOBITS)
     304          91 :                 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          92 : dwarf_getcfi_elf (Elf *elf)
     317             : {
     318          92 :   if (elf_kind (elf) != ELF_K_ELF)
     319             :     {
     320           0 :       __libdw_seterrno (DWARF_E_NOELF);
     321           0 :       return NULL;
     322             :     }
     323             : 
     324          92 :   GElf_Ehdr ehdr_mem;
     325          92 :   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     326          92 :   if (unlikely (ehdr == NULL))
     327             :     {
     328           0 :       __libdw_seterrno (DWARF_E_INVALID_ELF);
     329           0 :       return NULL;
     330             :     }
     331             : 
     332          92 :   Dwarf_CFI *result = getcfi_shdr (elf, ehdr);
     333          92 :   if (result == (void *) -1l)
     334           1 :     result = getcfi_phdr (elf, ehdr);
     335             : 
     336             :   return result;
     337             : }
     338             : INTDEF (dwarf_getcfi_elf)

Generated by: LCOV version 1.13