Blame libdw/cfi.c

Packit Service 97d2fb
/* CFI program execution.
Packit Service 97d2fb
   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include "../libebl/libebl.h"
Packit Service 97d2fb
#include "cfi.h"
Packit Service 97d2fb
#include "memory-access.h"
Packit Service 97d2fb
#include "encoded-value.h"
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
Packit Service 97d2fb
#define CFI_PRIMARY_MAX	0x3f
Packit Service 97d2fb
Packit Service 97d2fb
static Dwarf_Frame *
Packit Service 97d2fb
duplicate_frame_state (const Dwarf_Frame *original,
Packit Service 97d2fb
		       Dwarf_Frame *prev)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t size = offsetof (Dwarf_Frame, regs[original->nregs]);
Packit Service 97d2fb
  Dwarf_Frame *copy = malloc (size);
Packit Service 97d2fb
  if (likely (copy != NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      memcpy (copy, original, size);
Packit Service 97d2fb
      copy->prev = prev;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return copy;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline bool
Packit Service 97d2fb
enough_registers (Dwarf_Word reg, Dwarf_Frame **pfs, int *result)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Don't allow insanely large register numbers.  268435456 registers
Packit Service 97d2fb
     should be enough for anybody.  And very large values might overflow
Packit Service 97d2fb
     the array size and offsetof calculations below.  */
Packit Service 97d2fb
  if (unlikely (reg >= INT32_MAX / sizeof ((*pfs)->regs[0])))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *result = DWARF_E_INVALID_CFI;
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if ((*pfs)->nregs <= reg)
Packit Service 97d2fb
    {
Packit Service 97d2fb
       size_t size = offsetof (Dwarf_Frame, regs[reg + 1]);
Packit Service 97d2fb
       Dwarf_Frame *bigger = realloc (*pfs, size);
Packit Service 97d2fb
       if (unlikely (bigger == NULL))
Packit Service 97d2fb
         {
Packit Service 97d2fb
           *result = DWARF_E_NOMEM;
Packit Service 97d2fb
           return false;
Packit Service 97d2fb
         }
Packit Service 97d2fb
       else
Packit Service 97d2fb
         {
Packit Service 97d2fb
           eu_static_assert (reg_unspecified == 0);
Packit Service 97d2fb
           memset (bigger->regs + bigger->nregs, 0,
Packit Service 97d2fb
                   (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]);
Packit Service 97d2fb
           bigger->nregs = reg + 1;
Packit Service 97d2fb
           *pfs = bigger;
Packit Service 97d2fb
         }
Packit Service 97d2fb
     }
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline void
Packit Service 97d2fb
require_cfa_offset (Dwarf_Frame *fs)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (unlikely (fs->cfa_rule != cfa_offset))
Packit Service 97d2fb
    fs->cfa_rule = cfa_invalid;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI.
Packit Service 97d2fb
   Frees *STATE on failure.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
execute_cfi (Dwarf_CFI *cache,
Packit Service 97d2fb
	     const struct dwarf_cie *cie,
Packit Service 97d2fb
	     Dwarf_Frame **state,
Packit Service 97d2fb
	     const uint8_t *program, const uint8_t *const end, bool abi_cfi,
Packit Service 97d2fb
	     Dwarf_Addr loc, Dwarf_Addr find_pc)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The caller should not give us anything out of range.  */
Packit Service 97d2fb
  assert (loc <= find_pc);
Packit Service 97d2fb
Packit Service 97d2fb
  int result = DWARF_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
#define cfi_assert(ok) do {						      \
Packit Service 97d2fb
    if (likely (ok)) break;						      \
Packit Service 97d2fb
    result = DWARF_E_INVALID_CFI;					      \
Packit Service 97d2fb
    goto out;								      \
Packit Service 97d2fb
  } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Frame *fs = *state;
Packit Service 97d2fb
Packit Service 97d2fb
#define register_rule(regno, r_rule, r_value) do {	\
Packit Service 97d2fb
    if (unlikely (! enough_registers (regno, &fs, &result)))	\
Packit Service 97d2fb
      goto out;						\
Packit Service 97d2fb
    fs->regs[regno].rule = reg_##r_rule;		\
Packit Service 97d2fb
    fs->regs[regno].value = (r_value);			\
Packit Service 97d2fb
  } while (0)
Packit Service 97d2fb
Packit Service 97d2fb
  while (program < end)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      uint8_t opcode = *program++;
Packit Service 97d2fb
      Dwarf_Word regno;
Packit Service 97d2fb
      Dwarf_Word offset;
Packit Service 97d2fb
      Dwarf_Word sf_offset;
Packit Service 97d2fb
      Dwarf_Word operand = opcode & CFI_PRIMARY_MAX;
Packit Service 97d2fb
      switch (opcode)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* These cases move LOC, i.e. "create a new table row".  */
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_advance_loc1:
Packit Service 97d2fb
	  operand = *program++;
Packit Service 97d2fb
	  FALLTHROUGH;
Packit Service 97d2fb
	case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
Packit Service 97d2fb
	advance_loc:
Packit Service 97d2fb
	  loc += operand * cie->code_alignment_factor;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_advance_loc2:
Packit Service 97d2fb
	  cfi_assert (program + 2 <= end);
Packit Service 97d2fb
	  operand = read_2ubyte_unaligned_inc (cache, program);
Packit Service 97d2fb
	  goto advance_loc;
Packit Service 97d2fb
	case DW_CFA_advance_loc4:
Packit Service 97d2fb
	  cfi_assert (program + 4 <= end);
Packit Service 97d2fb
	  operand = read_4ubyte_unaligned_inc (cache, program);
Packit Service 97d2fb
	  goto advance_loc;
Packit Service 97d2fb
	case DW_CFA_MIPS_advance_loc8:
Packit Service 97d2fb
	  cfi_assert (program + 8 <= end);
Packit Service 97d2fb
	  operand = read_8ubyte_unaligned_inc (cache, program);
Packit Service 97d2fb
	  goto advance_loc;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_set_loc:
Packit Service 97d2fb
	  if (likely (!read_encoded_value (cache, cie->fde_encoding,
Packit Service 97d2fb
					   &program, &loc)))
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  result = INTUSE(dwarf_errno) ();
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Now all following cases affect this row, but do not touch LOC.
Packit Service 97d2fb
	     These cases end with 'continue'.  We only get out of the
Packit Service 97d2fb
	     switch block for the row-copying (LOC-moving) cases above.  */
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_uleb128 (offset, program, end);
Packit Service 97d2fb
	def_cfa:
Packit Service 97d2fb
	  fs->cfa_rule = cfa_offset;
Packit Service 97d2fb
	  fs->cfa_val_reg = operand;
Packit Service 97d2fb
	  fs->cfa_val_offset = offset;
Packit Service 97d2fb
	  /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it.  */
Packit Service 97d2fb
	  fs->cfa_data.offset.atom = DW_OP_bregx;
Packit Service 97d2fb
	  fs->cfa_data.offset.offset = 0;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa_register:
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  require_cfa_offset (fs);
Packit Service 97d2fb
	  fs->cfa_val_reg = regno;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa_sf:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_sleb128 (sf_offset, program, end);
Packit Service 97d2fb
	  offset = sf_offset * cie->data_alignment_factor;
Packit Service 97d2fb
	  goto def_cfa;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa_offset:
Packit Service 97d2fb
	  get_uleb128 (offset, program, end);
Packit Service 97d2fb
	def_cfa_offset:
Packit Service 97d2fb
	  require_cfa_offset (fs);
Packit Service 97d2fb
	  fs->cfa_val_offset = offset;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa_offset_sf:
Packit Service 97d2fb
	  get_sleb128 (sf_offset, program, end);
Packit Service 97d2fb
	  offset = sf_offset * cie->data_alignment_factor;
Packit Service 97d2fb
	  goto def_cfa_offset;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_def_cfa_expression:
Packit Service 97d2fb
	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (operand <= (Dwarf_Word) (end - program));
Packit Service 97d2fb
	  fs->cfa_rule = cfa_expr;
Packit Service 97d2fb
	  fs->cfa_data.expr.data = (unsigned char *) program;
Packit Service 97d2fb
	  fs->cfa_data.expr.length = operand;
Packit Service 97d2fb
	  program += operand;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_undefined:
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  register_rule (regno, undefined, 0);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_same_value:
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  register_rule (regno, same_value, 0);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_offset_extended:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  FALLTHROUGH;
Packit Service 97d2fb
	case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX:
Packit Service 97d2fb
	  get_uleb128 (offset, program, end);
Packit Service 97d2fb
	  offset *= cie->data_alignment_factor;
Packit Service 97d2fb
	offset_extended:
Packit Service 97d2fb
	  register_rule (operand, offset, offset);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_offset_extended_sf:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  get_sleb128 (sf_offset, program, end);
Packit Service 97d2fb
	offset_extended_sf:
Packit Service 97d2fb
	  offset = sf_offset * cie->data_alignment_factor;
Packit Service 97d2fb
	  goto offset_extended;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_GNU_negative_offset_extended:
Packit Service 97d2fb
	  /* GNU extension obsoleted by DW_CFA_offset_extended_sf.  */
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_uleb128 (offset, program, end);
Packit Service 97d2fb
	  sf_offset = -offset;
Packit Service 97d2fb
	  goto offset_extended_sf;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_val_offset:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_uleb128 (offset, program, end);
Packit Service 97d2fb
	  offset *= cie->data_alignment_factor;
Packit Service 97d2fb
	val_offset:
Packit Service 97d2fb
	  register_rule (operand, val_offset, offset);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_val_offset_sf:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_sleb128 (sf_offset, program, end);
Packit Service 97d2fb
	  offset = sf_offset * cie->data_alignment_factor;
Packit Service 97d2fb
	  goto val_offset;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_register:
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  register_rule (regno, register, operand);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_expression:
Packit Service 97d2fb
	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
Packit Service 97d2fb
	  assert (! abi_cfi);
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  offset = program - (const uint8_t *) cache->data->d.d_buf;
Packit Service 97d2fb
	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
Packit Service 97d2fb
	  cfi_assert (program < end);
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (operand <= (Dwarf_Word) (end - program));
Packit Service 97d2fb
	  program += operand;
Packit Service 97d2fb
	  register_rule (regno, expression, offset);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_val_expression:
Packit Service 97d2fb
	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
Packit Service 97d2fb
	  assert (! abi_cfi);
Packit Service 97d2fb
	  get_uleb128 (regno, program, end);
Packit Service 97d2fb
	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
Packit Service 97d2fb
	  offset = program - (const uint8_t *) cache->data->d.d_buf;
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  cfi_assert (operand <= (Dwarf_Word) (end - program));
Packit Service 97d2fb
	  program += operand;
Packit Service 97d2fb
	  register_rule (regno, val_expression, offset);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_restore_extended:
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  FALLTHROUGH;
Packit Service 97d2fb
	case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX:
Packit Service 97d2fb
Packit Service 97d2fb
	  if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Special case hack to give backend abi_cfi a shorthand.  */
Packit Service 97d2fb
	      cache->default_same_value = true;
Packit Service 97d2fb
	      continue;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* This can't be used in the CIE's own initial instructions.  */
Packit Service 97d2fb
	  cfi_assert (cie->initial_state != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Restore the CIE's initial rule for this register.  */
Packit Service 97d2fb
	  if (unlikely (! enough_registers (operand, &fs, &result)))
Packit Service 97d2fb
	    goto out;
Packit Service 97d2fb
	  if (cie->initial_state->nregs > operand)
Packit Service 97d2fb
	    fs->regs[operand] = cie->initial_state->regs[operand];
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    fs->regs[operand].rule = reg_unspecified;
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_remember_state:
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* Duplicate the state and chain the copy on.  */
Packit Service 97d2fb
	    Dwarf_Frame *copy = duplicate_frame_state (fs, fs);
Packit Service 97d2fb
	    if (unlikely (copy == NULL))
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		result = DWARF_E_NOMEM;
Packit Service 97d2fb
		goto out;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    fs = copy;
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_restore_state:
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    /* Pop the current state off and use the old one instead.  */
Packit Service 97d2fb
	    Dwarf_Frame *prev = fs->prev;
Packit Service 97d2fb
	    cfi_assert (prev != NULL);
Packit Service 97d2fb
	    free (fs);
Packit Service 97d2fb
	    fs = prev;
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_nop:
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_GNU_window_save: /* DW_CFA_AARCH64_negate_ra_state */
Packit Service 97d2fb
	  if (cache->e_machine == EM_AARCH64)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Toggles the return address state, indicating whether
Packit Service 97d2fb
		 the return address is encrypted or not on
Packit Service 97d2fb
		 aarch64. XXX not handled yet.  */
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This is magic shorthand used only by SPARC.  It's
Packit Service 97d2fb
		 equivalent to a bunch of DW_CFA_register and
Packit Service 97d2fb
		 DW_CFA_offset operations.  */
Packit Service 97d2fb
	      if (unlikely (! enough_registers (31, &fs, &result)))
Packit Service 97d2fb
		goto out;
Packit Service 97d2fb
	      for (regno = 8; regno < 16; ++regno)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Find each %oN in %iN.  */
Packit Service 97d2fb
		  fs->regs[regno].rule = reg_register;
Packit Service 97d2fb
		  fs->regs[regno].value = regno + 16;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      unsigned int address_size;
Packit Service 97d2fb
	      address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32
Packit Service 97d2fb
			      ? 4 : 8);
Packit Service 97d2fb
	      for (; regno < 32; ++regno)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* Find %l0..%l7 and %i0..%i7 in a block at the CFA.  */
Packit Service 97d2fb
		  fs->regs[regno].rule = reg_offset;
Packit Service 97d2fb
		  fs->regs[regno].value = (regno - 16) * address_size;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_CFA_GNU_args_size:
Packit Service 97d2fb
	  /* XXX is this useful for anything? */
Packit Service 97d2fb
	  get_uleb128 (operand, program, end);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  cfi_assert (false);
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We get here only for the cases that have just moved LOC.  */
Packit Service 97d2fb
      cfi_assert (cie->initial_state != NULL);
Packit Service 97d2fb
      if (find_pc >= loc)
Packit Service 97d2fb
	/* This advance has not yet reached FIND_PC.  */
Packit Service 97d2fb
	fs->start = loc;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We have just advanced past the address we're looking for.
Packit Service 97d2fb
	     The state currently described is what we want to see.  */
Packit Service 97d2fb
	  fs->end = loc;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* "The end of the instruction stream can be thought of as a
Packit Service 97d2fb
     DW_CFA_set_loc (initial_location + address_range) instruction."
Packit Service 97d2fb
     (DWARF 3.0 Section 6.4.3)
Packit Service 97d2fb
Packit Service 97d2fb
     When we fall off the end of the program without an advance_loc/set_loc
Packit Service 97d2fb
     that put us past FIND_PC, the final state left by the FDE program
Packit Service 97d2fb
     applies to this address (the caller ensured it was inside the FDE).
Packit Service 97d2fb
     This address (FDE->end) is already in FS->end as set by the caller.  */
Packit Service 97d2fb
Packit Service 97d2fb
#undef register_rule
Packit Service 97d2fb
#undef cfi_assert
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
Packit Service 97d2fb
  /* Pop any remembered states left on the stack.  */
Packit Service 97d2fb
  while (fs->prev != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Frame *prev = fs->prev;
Packit Service 97d2fb
      fs->prev = prev->prev;
Packit Service 97d2fb
      free (prev);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (likely (result == DWARF_E_NOERROR))
Packit Service 97d2fb
    *state = fs;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    free (fs);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int result = DWARF_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  if (likely (cie->initial_state != NULL))
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This CIE has not been used before.  Play out its initial
Packit Service 97d2fb
     instructions and cache the initial state that results.
Packit Service 97d2fb
     First we'll let the backend fill in the default initial
Packit Service 97d2fb
     state for this machine's ABI.  */
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 };
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure we have a backend handle cached.  */
Packit Service 97d2fb
  if (unlikely (cache->ebl == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      cache->ebl = ebl_openbackend (cache->data->s->elf);
Packit Service 97d2fb
      if (unlikely (cache->ebl == NULL))
Packit Service 97d2fb
	cache->ebl = (void *) -1l;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Fetch the ABI's default CFI program.  */
Packit Service 97d2fb
  if (likely (cache->ebl != (void *) -1l)
Packit Service 97d2fb
      && unlikely (ebl_abi_cfi (cache->ebl, &abi_info) < 0))
Packit Service 97d2fb
    return DWARF_E_UNKNOWN_ERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame));
Packit Service 97d2fb
  if (unlikely (cie_fs == NULL))
Packit Service 97d2fb
    return DWARF_E_NOMEM;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the default state of any register is not "undefined"
Packit Service 97d2fb
     (i.e. call-clobbered), then the backend supplies instructions
Packit Service 97d2fb
     for the standard initial state.  */
Packit Service 97d2fb
  if (abi_info.initial_instructions_end > abi_info.initial_instructions)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Dummy CIE for backend's instructions.  */
Packit Service 97d2fb
      struct dwarf_cie abi_cie =
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  .code_alignment_factor = abi_info.code_alignment_factor,
Packit Service 97d2fb
	  .data_alignment_factor = abi_info.data_alignment_factor,
Packit Service 97d2fb
	};
Packit Service 97d2fb
      result = execute_cfi (cache, &abi_cie, &cie_fs,
Packit Service 97d2fb
			    abi_info.initial_instructions,
Packit Service 97d2fb
			    abi_info.initial_instructions_end, true,
Packit Service 97d2fb
			    0, (Dwarf_Addr) -1l);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now run the CIE's initial instructions.  */
Packit Service 97d2fb
  if (cie->initial_instructions_end > cie->initial_instructions
Packit Service 97d2fb
      && likely (result == DWARF_E_NOERROR))
Packit Service 97d2fb
    result = execute_cfi (cache, cie, &cie_fs,
Packit Service 97d2fb
			  cie->initial_instructions,
Packit Service 97d2fb
			  cie->initial_instructions_end, false,
Packit Service 97d2fb
			  0, (Dwarf_Addr) -1l);
Packit Service 97d2fb
Packit Service 97d2fb
  if (likely (result == DWARF_E_NOERROR))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Now we have the initial state of things that all
Packit Service 97d2fb
	 FDEs using this CIE will start from.  */
Packit Service 97d2fb
      cie_fs->cache = cache;
Packit Service 97d2fb
      cie->initial_state = cie_fs;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
Packit Service 97d2fb
			  Dwarf_Addr address, Dwarf_Frame **frame)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int result = cie_cache_initial_state (cache, fde->cie);
Packit Service 97d2fb
  if (likely (result == DWARF_E_NOERROR))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL);
Packit Service 97d2fb
      if (unlikely (fs == NULL))
Packit Service 97d2fb
	return DWARF_E_NOMEM;
Packit Service 97d2fb
Packit Service 97d2fb
      fs->fde = fde;
Packit Service 97d2fb
      fs->start = fde->start;
Packit Service 97d2fb
      fs->end = fde->end;
Packit Service 97d2fb
Packit Service 97d2fb
      result = execute_cfi (cache, fde->cie, &fs,
Packit Service 97d2fb
			    fde->instructions, fde->instructions_end, false,
Packit Service 97d2fb
			    fde->start, address);
Packit Service 97d2fb
      if (likely (result == DWARF_E_NOERROR))
Packit Service 97d2fb
	*frame = fs;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}