Blame libdw/encoded-value.h

Packit 032894
/* DW_EH_PE_* support for libdw unwinder.
Packit 032894
   Copyright (C) 2009-2010, 2014, 2015 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
#ifndef _ENCODED_VALUE_H
Packit 032894
#define _ENCODED_VALUE_H 1
Packit 032894
Packit 032894
#include <dwarf.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include "libdwP.h"
Packit 032894
#include "../libelf/common.h"
Packit 032894
Packit 032894
Packit 032894
/* Returns zero if the value is omitted, the encoding is unknown or
Packit 032894
   the (leb128) size cannot be determined.  */
Packit 032894
static size_t __attribute__ ((unused))
Packit 032894
encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
Packit 032894
		    uint8_t encoding, const uint8_t *p)
Packit 032894
{
Packit 032894
  if (encoding == DW_EH_PE_omit)
Packit 032894
    return 0;
Packit 032894
Packit 032894
  switch (encoding & 0x07)
Packit 032894
    {
Packit 032894
    case DW_EH_PE_udata2:
Packit 032894
      return 2;
Packit 032894
    case DW_EH_PE_udata4:
Packit 032894
      return 4;
Packit 032894
    case DW_EH_PE_udata8:
Packit 032894
      return 8;
Packit 032894
Packit 032894
    case DW_EH_PE_absptr:
Packit 032894
      return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
Packit 032894
Packit 032894
    case DW_EH_PE_uleb128:
Packit 032894
      if (p != NULL)
Packit 032894
	{
Packit 032894
	  const uint8_t *end = p;
Packit 032894
	  while (end < (uint8_t *) data->d_buf + data->d_size)
Packit 032894
	    if (*end++ & 0x80u)
Packit 032894
	      return end - p;
Packit 032894
	}
Packit 032894
      return 0;
Packit 032894
Packit 032894
    default:
Packit 032894
      return 0;
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
/* Returns zero when value was read successfully, minus one otherwise.  */
Packit 032894
static inline int __attribute__ ((unused))
Packit 032894
__libdw_cfi_read_address_inc (const Dwarf_CFI *cache,
Packit 032894
			      const unsigned char **addrp,
Packit 032894
			      int width, Dwarf_Addr *ret)
Packit 032894
{
Packit 032894
  width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
Packit 032894
Packit 032894
  if (cache->dbg != NULL)
Packit 032894
    return __libdw_read_address_inc (cache->dbg, IDX_debug_frame,
Packit 032894
				     addrp, width, ret);
Packit 032894
Packit 032894
  /* Only .debug_frame might have relocation to consider.
Packit 032894
     Read plain values from .eh_frame data.  */
Packit 032894
Packit 032894
  const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
Packit 032894
  Dwarf eh_dbg = { .other_byte_order = MY_ELFDATA != cache->e_ident[EI_DATA] };
Packit 032894
Packit 032894
  if (width == 4)
Packit 032894
    {
Packit 032894
      if (unlikely (*addrp + 4 > endp))
Packit 032894
	{
Packit 032894
	invalid_data:
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_CFI);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      *ret = read_4ubyte_unaligned_inc (&eh_dbg, *addrp);
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      if (unlikely (*addrp + 8 > endp))
Packit 032894
	goto invalid_data;
Packit 032894
      *ret = read_8ubyte_unaligned_inc (&eh_dbg, *addrp);
Packit 032894
    }
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Returns true on error, false otherwise. */
Packit 032894
static bool __attribute__ ((unused))
Packit 032894
read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding,
Packit 032894
		    const uint8_t **p, Dwarf_Addr *result)
Packit 032894
{
Packit 032894
  *result = 0;
Packit 032894
  switch (encoding & 0x70)
Packit 032894
    {
Packit 032894
    case DW_EH_PE_absptr:
Packit 032894
      break;
Packit 032894
    case DW_EH_PE_pcrel:
Packit 032894
      *result = (cache->frame_vaddr
Packit 032894
		 + (*p - (const uint8_t *) cache->data->d.d_buf));
Packit 032894
      break;
Packit 032894
    case DW_EH_PE_textrel:
Packit 032894
      // ia64: segrel
Packit 032894
      *result = cache->textrel;
Packit 032894
      break;
Packit 032894
    case DW_EH_PE_datarel:
Packit 032894
      // i386: GOTOFF
Packit 032894
      // ia64: gprel
Packit 032894
      *result = cache->datarel;
Packit 032894
      break;
Packit 032894
    case DW_EH_PE_funcrel:	/* XXX */
Packit 032894
      break;
Packit 032894
    case DW_EH_PE_aligned:
Packit 032894
      {
Packit 032894
	const size_t size = encoded_value_size (&cache->data->d,
Packit 032894
						cache->e_ident,
Packit 032894
						encoding, *p);
Packit 032894
	if (unlikely (size == 0))
Packit 032894
	  return true;
Packit 032894
	size_t align = ((cache->frame_vaddr
Packit 032894
			 + (*p - (const uint8_t *) cache->data->d.d_buf))
Packit 032894
			& (size - 1));
Packit 032894
	if (align != 0)
Packit 032894
	  *p += size - align;
Packit 032894
	break;
Packit 032894
      }
Packit 032894
Packit 032894
    default:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_CFI);
Packit 032894
      return true;
Packit 032894
    }
Packit 032894
Packit 032894
  Dwarf_Addr value = 0;
Packit 032894
  const unsigned char *endp = cache->data->d.d_buf + cache->data->d.d_size;
Packit 032894
  switch (encoding & 0x0f)
Packit 032894
    {
Packit 032894
    case DW_EH_PE_udata2:
Packit 032894
      if (unlikely (*p + 2 > endp))
Packit 032894
	{
Packit 032894
	invalid_data:
Packit 032894
	  __libdw_seterrno (DWARF_E_INVALID_CFI);
Packit 032894
	  return true;
Packit 032894
	}
Packit 032894
      value = read_2ubyte_unaligned_inc (cache, *p);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_sdata2:
Packit 032894
      if (unlikely (*p + 2 > endp))
Packit 032894
	goto invalid_data;
Packit 032894
      value = read_2sbyte_unaligned_inc (cache, *p);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_udata4:
Packit 032894
      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
Packit 032894
	return true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_sdata4:
Packit 032894
      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 4, &value) != 0))
Packit 032894
	return true;
Packit 032894
      value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend.  */
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_udata8:
Packit 032894
    case DW_EH_PE_sdata8:
Packit 032894
      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 8, &value) != 0))
Packit 032894
	return true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_absptr:
Packit 032894
      if (unlikely (__libdw_cfi_read_address_inc (cache, p, 0, &value) != 0))
Packit 032894
	return true;
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_uleb128:
Packit 032894
      get_uleb128 (value, *p, endp);
Packit 032894
      break;
Packit 032894
Packit 032894
    case DW_EH_PE_sleb128:
Packit 032894
      get_sleb128 (value, *p, endp);
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_CFI);
Packit 032894
      return true;
Packit 032894
    }
Packit 032894
Packit 032894
  *result += value;
Packit 032894
Packit 032894
  if (encoding & DW_EH_PE_indirect)
Packit 032894
    {
Packit 032894
      if (unlikely (*result < cache->frame_vaddr))
Packit 032894
	return true;
Packit 032894
      *result -= cache->frame_vaddr;
Packit 032894
      size_t ptrsize = encoded_value_size (NULL, cache->e_ident,
Packit 032894
					   DW_EH_PE_absptr, NULL);
Packit 032894
      if (unlikely (cache->data->d.d_size < ptrsize
Packit 032894
		    || *result > (cache->data->d.d_size - ptrsize)))
Packit 032894
	return true;
Packit 032894
      const uint8_t *ptr = cache->data->d.d_buf + *result;
Packit 032894
      if (unlikely (__libdw_cfi_read_address_inc (cache, &ptr, 0, result)
Packit 032894
		    != 0))
Packit 032894
	return true;
Packit 032894
    }
Packit 032894
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
#endif	/* encoded-value.h */