Blame libdw/dwarf_next_cfi.c

Packit 032894
/* Advance to next CFI entry.
Packit 032894
   Copyright (C) 2009-2010, 2014 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include "cfi.h"
Packit 032894
#include "encoded-value.h"
Packit 032894
Packit 032894
#include <string.h>
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
dwarf_next_cfi (const unsigned char e_ident[],
Packit 032894
		Elf_Data *data,
Packit 032894
		bool eh_frame_p,
Packit 032894
		Dwarf_Off off,
Packit 032894
		Dwarf_Off *next_off,
Packit 032894
		Dwarf_CFI_Entry *entry)
Packit 032894
{
Packit 032894
  /* Dummy struct for memory-access.h macros.  */
Packit 032894
  BYTE_ORDER_DUMMY (dw, e_ident);
Packit 032894
Packit 032894
  /* If we reached the end before don't do anything.  */
Packit 032894
  if (off == (Dwarf_Off) -1l
Packit 032894
      /* Make sure there is enough space in the .debug_frame section
Packit 032894
	 for at least the initial word.  We cannot test the rest since
Packit 032894
	 we don't know yet whether this is a 64-bit object or not.  */
Packit 032894
      || unlikely (off + 4 >= data->d_size))
Packit 032894
    {
Packit 032894
    done:
Packit 032894
      *next_off = (Dwarf_Off) -1l;
Packit 032894
      return 1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* This points into the .debug_frame section at the start of the entry.  */
Packit 032894
  const uint8_t *bytes = data->d_buf + off;
Packit 032894
  const uint8_t *limit = data->d_buf + data->d_size;
Packit 032894
Packit 032894
  /* The format of a CFI entry is described in DWARF3 6.4.1:
Packit 032894
   */
Packit 032894
Packit 032894
  uint64_t length = read_4ubyte_unaligned_inc (&dw, bytes);
Packit 032894
  size_t offset_size = 4;
Packit 032894
  if (length == DWARF3_LENGTH_64_BIT)
Packit 032894
    {
Packit 032894
      /* This is the 64-bit DWARF format.  */
Packit 032894
      offset_size = 8;
Packit 032894
      if (unlikely (limit - bytes < 8))
Packit 032894
	{
Packit 032894
	invalid:
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      length = read_8ubyte_unaligned_inc (&dw, bytes);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Not explicitly in the DWARF spec, but mentioned in the LSB exception
Packit 032894
     frames (.eh_frame) spec. If Length contains the value 0, then this
Packit 032894
     CIE shall be considered a terminator and processing shall end.  */
Packit 032894
  if (length == 0)
Packit 032894
    goto done;
Packit 032894
Packit 032894
  if (unlikely ((uint64_t) (limit - bytes) < length)
Packit 032894
      || unlikely (length < offset_size + 1))
Packit 032894
    goto invalid;
Packit 032894
Packit 032894
  /* Now we know how large the entry is.  Note the trick in the
Packit 032894
     computation.  If the offset_size is 4 the '- 4' term undoes the
Packit 032894
     '2 *'.  If offset_size is 8 this term computes the size of the
Packit 032894
     escape value plus the 8 byte offset.  */
Packit 032894
  *next_off = off + (2 * offset_size - 4) + length;
Packit 032894
Packit 032894
  limit = bytes + length;
Packit 032894
Packit 032894
  const uint8_t *const cie_pointer_start = bytes;
Packit 032894
  if (offset_size == 8)
Packit 032894
    entry->cie.CIE_id = read_8ubyte_unaligned_inc (&dw, bytes);
Packit 032894
  else
Packit 032894
    {
Packit 032894
      entry->cie.CIE_id = read_4ubyte_unaligned_inc (&dw, bytes);
Packit 032894
      /* Canonicalize the 32-bit CIE_ID value to 64 bits.  */
Packit 032894
      if (!eh_frame_p && entry->cie.CIE_id == DW_CIE_ID_32)
Packit 032894
	entry->cie.CIE_id = DW_CIE_ID_64;
Packit 032894
    }
Packit 032894
  if (eh_frame_p)
Packit 032894
    {
Packit 032894
      /* Canonicalize the .eh_frame CIE pointer to .debug_frame format.  */
Packit 032894
      if (entry->cie.CIE_id == 0)
Packit 032894
	entry->cie.CIE_id = DW_CIE_ID_64;
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  /* In .eh_frame format, a CIE pointer is the distance from where
Packit 032894
	     it appears back to the beginning of the CIE.  */
Packit 032894
	  ptrdiff_t pos = cie_pointer_start - (const uint8_t *) data->d_buf;
Packit 032894
	  if (unlikely (entry->cie.CIE_id > (Dwarf_Off) pos)
Packit 032894
	      || unlikely (pos <= (ptrdiff_t) offset_size))
Packit 032894
	    goto invalid;
Packit 032894
	  entry->cie.CIE_id = pos - entry->cie.CIE_id;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (entry->cie.CIE_id == DW_CIE_ID_64)
Packit 032894
    {
Packit 032894
      /* Read the version stamp.  Always an 8-bit value.  */
Packit 032894
      uint8_t version = *bytes++;
Packit 032894
Packit 032894
      if (version != 1 && (unlikely (version < 3) || unlikely (version > 4)))
Packit 032894
	goto invalid;
Packit 032894
Packit 032894
      entry->cie.augmentation = (const char *) bytes;
Packit 032894
Packit 032894
      bytes = memchr (bytes, '\0', limit - bytes);
Packit 032894
      if (unlikely (bytes == NULL))
Packit 032894
	goto invalid;
Packit 032894
      ++bytes;
Packit 032894
Packit 032894
      /* The address size for CFI is implicit in the ELF class.  */
Packit 032894
      uint_fast8_t address_size = e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
Packit 032894
      uint_fast8_t segment_size = 0;
Packit 032894
      if (version >= 4)
Packit 032894
	{
Packit 032894
	  if (unlikely (limit - bytes < 5))
Packit 032894
	    goto invalid;
Packit 032894
	  /* XXX We don't actually support address_size not matching the class.
Packit 032894
	     To do so, we'd have to return it here so that intern_new_cie
Packit 032894
	     could use it choose a specific fde_encoding.  */
Packit 032894
	  if (unlikely (*bytes != address_size))
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_VERSION);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	  address_size = *bytes++;
Packit 032894
	  segment_size = *bytes++;
Packit 032894
	  /* We don't actually support segment selectors.  We'd have to
Packit 032894
	     roll this into the fde_encoding bits or something.  */
Packit 032894
	  if (unlikely (segment_size != 0))
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (DWARF_E_VERSION);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      const char *ap = entry->cie.augmentation;
Packit 032894
Packit 032894
      /* g++ v2 "eh" has pointer immediately following augmentation string,
Packit 032894
	 so it must be handled first.  */
Packit 032894
      if (unlikely (ap[0] == 'e' && ap[1] == 'h'))
Packit 032894
	{
Packit 032894
	  ap += 2;
Packit 032894
	  bytes += address_size;
Packit 032894
	}
Packit 032894
Packit 032894
      if (bytes >= limit)
Packit 032894
	goto invalid;
Packit 032894
      get_uleb128 (entry->cie.code_alignment_factor, bytes, limit);
Packit 032894
Packit 032894
      if (bytes >= limit)
Packit 032894
	goto invalid;
Packit 032894
      get_sleb128 (entry->cie.data_alignment_factor, bytes, limit);
Packit 032894
Packit 032894
      if (bytes >= limit)
Packit 032894
	goto invalid;
Packit 032894
Packit 032894
      if (version >= 3)		/* DWARF 3+ */
Packit 032894
	get_uleb128 (entry->cie.return_address_register, bytes, limit);
Packit 032894
      else			/* DWARF 2 */
Packit 032894
	entry->cie.return_address_register = *bytes++;
Packit 032894
Packit 032894
      /* If we have sized augmentation data,
Packit 032894
	 we don't need to grok it all.  */
Packit 032894
      entry->cie.fde_augmentation_data_size = 0;
Packit 032894
      bool sized_augmentation = *ap == 'z';
Packit 032894
      if (sized_augmentation)
Packit 032894
	{
Packit 032894
	  if (bytes >= limit)
Packit 032894
	    goto invalid;
Packit 032894
	  get_uleb128 (entry->cie.augmentation_data_size, bytes, limit);
Packit 032894
	  if ((Dwarf_Word) (limit - bytes) < entry->cie.augmentation_data_size)
Packit 032894
	    goto invalid;
Packit 032894
	  entry->cie.augmentation_data = bytes;
Packit 032894
	  bytes += entry->cie.augmentation_data_size;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  entry->cie.augmentation_data = bytes;
Packit 032894
Packit 032894
	  for (; *ap != '\0'; ++ap)
Packit 032894
	    {
Packit 032894
	      uint8_t encoding;
Packit 032894
	      switch (*ap)
Packit 032894
		{
Packit 032894
		case 'L':		/* Skip LSDA pointer encoding byte.  */
Packit 032894
		case 'R':		/* Skip FDE address encoding byte.  */
Packit 032894
		  encoding = *bytes++;
Packit 032894
		  entry->cie.fde_augmentation_data_size
Packit 032894
		    += encoded_value_size (data, e_ident, encoding, NULL);
Packit 032894
		  continue;
Packit 032894
		case 'P':   /* Skip encoded personality routine pointer. */
Packit 032894
		  encoding = *bytes++;
Packit 032894
		  bytes += encoded_value_size (data, e_ident, encoding, bytes);
Packit 032894
		  continue;
Packit 032894
		case 'S':		/* Skip signal-frame flag.  */
Packit 032894
		  continue;
Packit 032894
		default:
Packit 032894
		  /* Unknown augmentation string.  initial_instructions might
Packit 032894
		     actually start with some augmentation data.  */
Packit 032894
		  break;
Packit 032894
		}
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	  entry->cie.augmentation_data_size
Packit 032894
	    = bytes - entry->cie.augmentation_data;
Packit 032894
	}
Packit 032894
Packit 032894
      entry->cie.initial_instructions = bytes;
Packit 032894
      entry->cie.initial_instructions_end = limit;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      entry->fde.start = bytes;
Packit 032894
      entry->fde.end = limit;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
INTDEF (dwarf_next_cfi)