Home | History | Annotate | Download | only in libdw
      1 /* Advance to next CFI entry.
      2    Copyright (C) 2009-2010, 2014 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 "encoded-value.h"
     35 
     36 #include <string.h>
     37 
     38 
     39 int
     40 dwarf_next_cfi (const unsigned char e_ident[],
     41 		Elf_Data *data,
     42 		bool eh_frame_p,
     43 		Dwarf_Off off,
     44 		Dwarf_Off *next_off,
     45 		Dwarf_CFI_Entry *entry)
     46 {
     47   /* Dummy struct for memory-access.h macros.  */
     48   BYTE_ORDER_DUMMY (dw, e_ident);
     49 
     50   /* If we reached the end before don't do anything.  */
     51   if (off == (Dwarf_Off) -1l
     52       /* Make sure there is enough space in the .debug_frame section
     53 	 for at least the initial word.  We cannot test the rest since
     54 	 we don't know yet whether this is a 64-bit object or not.  */
     55       || unlikely (off + 4 >= data->d_size))
     56     {
     57       *next_off = (Dwarf_Off) -1l;
     58       return 1;
     59     }
     60 
     61   /* This points into the .debug_frame section at the start of the entry.  */
     62   const uint8_t *bytes = data->d_buf + off;
     63   const uint8_t *limit = data->d_buf + data->d_size;
     64 
     65   /* The format of a CFI entry is described in DWARF3 6.4.1:
     66    */
     67 
     68   uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes);
     69   size_t offset_size = 4;
     70   if (length == DWARF3_LENGTH_64_BIT)
     71     {
     72       /* This is the 64-bit DWARF format.  */
     73       offset_size = 8;
     74       if (unlikely (limit - bytes < 8))
     75 	{
     76 	invalid:
     77 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
     78 	  return -1;
     79 	}
     80       length = read_8ubyte_unaligned_inc (&dw, bytes);
     81     }
     82   if (unlikely ((uint64_t) (limit - bytes) < length)
     83       || unlikely (length < offset_size + 1))
     84     goto invalid;
     85 
     86   /* Now we know how large the entry is.  Note the trick in the
     87      computation.  If the offset_size is 4 the '- 4' term undoes the
     88      '2 *'.  If offset_size is 8 this term computes the size of the
     89      escape value plus the 8 byte offset.  */
     90   *next_off = off + (2 * offset_size - 4) + length;
     91 
     92   limit = bytes + length;
     93 
     94   const uint8_t *const cie_pointer_start = bytes;
     95   if (offset_size == 8)
     96     entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes);
     97   else
     98     {
     99       entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
    100       /* Canonicalize the 32-bit CIE_ID value to 64 bits.  */
    101       if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32)
    102 	entry->cie.CIE_id = DW_CIE_ID_64;
    103     }
    104   if (eh_frame_p)
    105     {
    106       /* Canonicalize the .eh_frame CIE pointer to .debug_frame format.  */
    107       if (entry->cie.CIE_id == 0)
    108 	entry->cie.CIE_id = DW_CIE_ID_64;
    109       else
    110 	{
    111 	  /* In .eh_frame format, a CIE pointer is the distance from where
    112 	     it appears back to the beginning of the CIE.  */
    113 	  ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf;
    114 	  if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos)
    115 	      || unlikely (pos <= (ptrdiff_t) offset_size))
    116 	    goto invalid;
    117 	  entry->cie.CIE_id = pos - entry->cie.CIE_id;
    118 	}
    119     }
    120 
    121   if (entry->cie.CIE_id == DW_CIE_ID_64)
    122     {
    123       /* Read the version stamp.  Always an 8-bit value.  */
    124       uint8_t version = *bytes++;
    125 
    126       if (version != 1 && (unlikely (version < 3) || unlikely (version > 4)))
    127 	goto invalid;
    128 
    129       entry->cie.augmentation = (const char *) bytes;
    130 
    131       bytes = memchr (bytes, '\0', limit - bytes);
    132       if (unlikely (bytes == NULL))
    133 	goto invalid;
    134       ++bytes;
    135 
    136       /* The address size for CFI is implicit in the ELF class.  */
    137       uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
    138       uint_fast8_t segment_size = 0;
    139       if (version >= 4)
    140 	{
    141 	  if (unlikely (limit - bytes < 5))
    142 	    goto invalid;
    143 	  /* XXX We don't actually support address_size not matching the class.
    144 	     To do so, we'd have to return it here so that intern_new_cie
    145 	     could use it choose a specific fde_encoding.  */
    146 	  if (unlikely (*bytes != address_size))
    147 	    {
    148 	      __libdw_seterrno (DWARF_E_VERSION);
    149 	      return -1;
    150 	    }
    151 	  address_size = *bytes++;
    152 	  segment_size = *bytes++;
    153 	  /* We don't actually support segment selectors.  We'd have to
    154 	     roll this into the fde_encoding bits or something.  */
    155 	  if (unlikely (segment_size != 0))
    156 	    {
    157 	      __libdw_seterrno (DWARF_E_VERSION);
    158 	      return -1;
    159 	    }
    160 	}
    161 
    162       const char *ap = entry->cie.augmentation;
    163 
    164       /* g++ v2 "eh" has pointer immediately following augmentation string,
    165 	 so it must be handled first.  */
    166       if (unlikely (ap[0] == 'e' && ap[1] == 'h'))
    167 	{
    168 	  ap += 2;
    169 	  bytes += address_size;
    170 	}
    171 
    172       if (bytes >= limit)
    173 	goto invalid;
    174       get_uleb128 (entry->cie.code_alignment_factor, bytes, limit);
    175 
    176       if (bytes >= limit)
    177 	goto invalid;
    178       get_sleb128 (entry->cie.data_alignment_factor, bytes, limit);
    179 
    180       if (bytes >= limit)
    181 	goto invalid;
    182 
    183       if (version >= 3)		/* DWARF 3+ */
    184 	get_uleb128 (entry->cie.return_address_register, bytes, limit);
    185       else			/* DWARF 2 */
    186 	entry->cie.return_address_register = *bytes++;
    187 
    188       /* If we have sized augmentation data,
    189 	 we don't need to grok it all.  */
    190       entry->cie.fde_augmentation_data_size = 0;
    191       bool sized_augmentation = *ap == 'z';
    192       if (sized_augmentation)
    193 	{
    194 	  if (bytes >= limit)
    195 	    goto invalid;
    196 	  get_uleb128 (entry->cie.augmentation_data_size, bytes, limit);
    197 	  if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
    198 	    goto invalid;
    199 	  entry->cie.augmentation_data = bytes;
    200 	  bytes += entry->cie.augmentation_data_size;
    201 	}
    202       else
    203 	{
    204 	  entry->cie.augmentation_data = bytes;
    205 
    206 	  for (; *ap != '\0'; ++ap)
    207 	    {
    208 	      uint8_t encoding;
    209 	      switch (*ap)
    210 		{
    211 		case 'L':		/* Skip LSDA pointer encoding byte.  */
    212 		case 'R':		/* Skip FDE address encoding byte.  */
    213 		  encoding = *bytes++;
    214 		  entry->cie.fde_augmentation_data_size
    215 		    += encoded_value_size (data, e_ident, encoding, NULL);
    216 		  continue;
    217 		case 'P':   /* Skip encoded personality routine pointer. */
    218 		  encoding = *bytes++;
    219 		  bytes += encoded_value_size (data, e_ident, encoding, bytes);
    220 		  continue;
    221 		case 'S':		/* Skip signal-frame flag.  */
    222 		  continue;
    223 		default:
    224 		  /* Unknown augmentation string.  initial_instructions might
    225 		     actually start with some augmentation data.  */
    226 		  break;
    227 		}
    228 	      break;
    229 	    }
    230 	  entry->cie.augmentation_data_size
    231 	    = bytes - entry->cie.augmentation_data;
    232 	}
    233 
    234       entry->cie.initial_instructions = bytes;
    235       entry->cie.initial_instructions_end = limit;
    236     }
    237   else
    238     {
    239       entry->fde.start = bytes;
    240       entry->fde.end = limit;
    241     }
    242 
    243   return 0;
    244 }
    245 INTDEF (dwarf_next_cfi)
    246