1da0c48c4Sopenharmony_ci/* CFI program execution.
2da0c48c4Sopenharmony_ci   Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include <dwarf.h>
34da0c48c4Sopenharmony_ci#include "../libebl/libebl.h"
35da0c48c4Sopenharmony_ci#include "cfi.h"
36da0c48c4Sopenharmony_ci#include "memory-access.h"
37da0c48c4Sopenharmony_ci#include "encoded-value.h"
38da0c48c4Sopenharmony_ci#include "system.h"
39da0c48c4Sopenharmony_ci#include <assert.h>
40da0c48c4Sopenharmony_ci#include <stdlib.h>
41da0c48c4Sopenharmony_ci#include <string.h>
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci#define CFI_PRIMARY_MAX	0x3f
44da0c48c4Sopenharmony_ci
45da0c48c4Sopenharmony_cistatic Dwarf_Frame *
46da0c48c4Sopenharmony_ciduplicate_frame_state (const Dwarf_Frame *original,
47da0c48c4Sopenharmony_ci		       Dwarf_Frame *prev)
48da0c48c4Sopenharmony_ci{
49da0c48c4Sopenharmony_ci  size_t size = offsetof (Dwarf_Frame, regs[original->nregs]);
50da0c48c4Sopenharmony_ci  Dwarf_Frame *copy = malloc (size);
51da0c48c4Sopenharmony_ci  if (likely (copy != NULL))
52da0c48c4Sopenharmony_ci    {
53da0c48c4Sopenharmony_ci      memcpy (copy, original, size);
54da0c48c4Sopenharmony_ci      copy->prev = prev;
55da0c48c4Sopenharmony_ci    }
56da0c48c4Sopenharmony_ci  return copy;
57da0c48c4Sopenharmony_ci}
58da0c48c4Sopenharmony_ci
59da0c48c4Sopenharmony_cistatic inline bool
60da0c48c4Sopenharmony_cienough_registers (Dwarf_Word reg, Dwarf_Frame **pfs, int *result)
61da0c48c4Sopenharmony_ci{
62da0c48c4Sopenharmony_ci  /* Don't allow insanely large register numbers.  268435456 registers
63da0c48c4Sopenharmony_ci     should be enough for anybody.  And very large values might overflow
64da0c48c4Sopenharmony_ci     the array size and offsetof calculations below.  */
65da0c48c4Sopenharmony_ci  if (unlikely (reg >= INT32_MAX / sizeof ((*pfs)->regs[0])))
66da0c48c4Sopenharmony_ci    {
67da0c48c4Sopenharmony_ci      *result = DWARF_E_INVALID_CFI;
68da0c48c4Sopenharmony_ci      return false;
69da0c48c4Sopenharmony_ci    }
70da0c48c4Sopenharmony_ci
71da0c48c4Sopenharmony_ci  if ((*pfs)->nregs <= reg)
72da0c48c4Sopenharmony_ci    {
73da0c48c4Sopenharmony_ci       size_t size = offsetof (Dwarf_Frame, regs[reg + 1]);
74da0c48c4Sopenharmony_ci       Dwarf_Frame *bigger = realloc (*pfs, size);
75da0c48c4Sopenharmony_ci       if (unlikely (bigger == NULL))
76da0c48c4Sopenharmony_ci         {
77da0c48c4Sopenharmony_ci           *result = DWARF_E_NOMEM;
78da0c48c4Sopenharmony_ci           return false;
79da0c48c4Sopenharmony_ci         }
80da0c48c4Sopenharmony_ci       else
81da0c48c4Sopenharmony_ci         {
82da0c48c4Sopenharmony_ci           eu_static_assert (reg_unspecified == 0);
83da0c48c4Sopenharmony_ci           memset (bigger->regs + bigger->nregs, 0,
84da0c48c4Sopenharmony_ci                   (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]);
85da0c48c4Sopenharmony_ci           bigger->nregs = reg + 1;
86da0c48c4Sopenharmony_ci           *pfs = bigger;
87da0c48c4Sopenharmony_ci         }
88da0c48c4Sopenharmony_ci     }
89da0c48c4Sopenharmony_ci  return true;
90da0c48c4Sopenharmony_ci}
91da0c48c4Sopenharmony_ci
92da0c48c4Sopenharmony_cistatic inline void
93da0c48c4Sopenharmony_cirequire_cfa_offset (Dwarf_Frame *fs)
94da0c48c4Sopenharmony_ci{
95da0c48c4Sopenharmony_ci  if (unlikely (fs->cfa_rule != cfa_offset))
96da0c48c4Sopenharmony_ci    fs->cfa_rule = cfa_invalid;
97da0c48c4Sopenharmony_ci}
98da0c48c4Sopenharmony_ci
99da0c48c4Sopenharmony_ci/* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI.
100da0c48c4Sopenharmony_ci   Frees *STATE on failure.  */
101da0c48c4Sopenharmony_cistatic int
102da0c48c4Sopenharmony_ciexecute_cfi (Dwarf_CFI *cache,
103da0c48c4Sopenharmony_ci	     const struct dwarf_cie *cie,
104da0c48c4Sopenharmony_ci	     Dwarf_Frame **state,
105da0c48c4Sopenharmony_ci	     const uint8_t *program, const uint8_t *const end, bool abi_cfi,
106da0c48c4Sopenharmony_ci	     Dwarf_Addr loc, Dwarf_Addr find_pc)
107da0c48c4Sopenharmony_ci{
108da0c48c4Sopenharmony_ci  /* The caller should not give us anything out of range.  */
109da0c48c4Sopenharmony_ci  assert (loc <= find_pc);
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci  int result = DWARF_E_NOERROR;
112da0c48c4Sopenharmony_ci
113da0c48c4Sopenharmony_ci#define cfi_assert(ok) do {						      \
114da0c48c4Sopenharmony_ci    if (likely (ok)) break;						      \
115da0c48c4Sopenharmony_ci    result = DWARF_E_INVALID_CFI;					      \
116da0c48c4Sopenharmony_ci    goto out;								      \
117da0c48c4Sopenharmony_ci  } while (0)
118da0c48c4Sopenharmony_ci
119da0c48c4Sopenharmony_ci  Dwarf_Frame *fs = *state;
120da0c48c4Sopenharmony_ci
121da0c48c4Sopenharmony_ci#define register_rule(regno, r_rule, r_value) do {	\
122da0c48c4Sopenharmony_ci    if (unlikely (! enough_registers (regno, &fs, &result)))	\
123da0c48c4Sopenharmony_ci      goto out;						\
124da0c48c4Sopenharmony_ci    fs->regs[regno].rule = reg_##r_rule;		\
125da0c48c4Sopenharmony_ci    fs->regs[regno].value = (r_value);			\
126da0c48c4Sopenharmony_ci  } while (0)
127da0c48c4Sopenharmony_ci
128da0c48c4Sopenharmony_ci  while (program < end)
129da0c48c4Sopenharmony_ci    {
130da0c48c4Sopenharmony_ci      uint8_t opcode = *program++;
131da0c48c4Sopenharmony_ci      Dwarf_Word regno;
132da0c48c4Sopenharmony_ci      Dwarf_Word offset;
133da0c48c4Sopenharmony_ci      Dwarf_Word sf_offset;
134da0c48c4Sopenharmony_ci      Dwarf_Word operand = opcode & CFI_PRIMARY_MAX;
135da0c48c4Sopenharmony_ci      switch (opcode)
136da0c48c4Sopenharmony_ci	{
137da0c48c4Sopenharmony_ci	  /* These cases move LOC, i.e. "create a new table row".  */
138da0c48c4Sopenharmony_ci
139da0c48c4Sopenharmony_ci	case DW_CFA_advance_loc1:
140da0c48c4Sopenharmony_ci	  operand = *program++;
141da0c48c4Sopenharmony_ci	  FALLTHROUGH;
142da0c48c4Sopenharmony_ci	case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX:
143da0c48c4Sopenharmony_ci	advance_loc:
144da0c48c4Sopenharmony_ci	  loc += operand * cie->code_alignment_factor;
145da0c48c4Sopenharmony_ci	  break;
146da0c48c4Sopenharmony_ci
147da0c48c4Sopenharmony_ci	case DW_CFA_advance_loc2:
148da0c48c4Sopenharmony_ci	  cfi_assert (program + 2 <= end);
149da0c48c4Sopenharmony_ci	  operand = read_2ubyte_unaligned_inc (cache, program);
150da0c48c4Sopenharmony_ci	  goto advance_loc;
151da0c48c4Sopenharmony_ci	case DW_CFA_advance_loc4:
152da0c48c4Sopenharmony_ci	  cfi_assert (program + 4 <= end);
153da0c48c4Sopenharmony_ci	  operand = read_4ubyte_unaligned_inc (cache, program);
154da0c48c4Sopenharmony_ci	  goto advance_loc;
155da0c48c4Sopenharmony_ci	case DW_CFA_MIPS_advance_loc8:
156da0c48c4Sopenharmony_ci	  cfi_assert (program + 8 <= end);
157da0c48c4Sopenharmony_ci	  operand = read_8ubyte_unaligned_inc (cache, program);
158da0c48c4Sopenharmony_ci	  goto advance_loc;
159da0c48c4Sopenharmony_ci
160da0c48c4Sopenharmony_ci	case DW_CFA_set_loc:
161da0c48c4Sopenharmony_ci	  if (likely (!read_encoded_value (cache, cie->fde_encoding,
162da0c48c4Sopenharmony_ci					   &program, &loc)))
163da0c48c4Sopenharmony_ci	    break;
164da0c48c4Sopenharmony_ci	  result = INTUSE(dwarf_errno) ();
165da0c48c4Sopenharmony_ci	  goto out;
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci	  /* Now all following cases affect this row, but do not touch LOC.
168da0c48c4Sopenharmony_ci	     These cases end with 'continue'.  We only get out of the
169da0c48c4Sopenharmony_ci	     switch block for the row-copying (LOC-moving) cases above.  */
170da0c48c4Sopenharmony_ci
171da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa:
172da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
173da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
174da0c48c4Sopenharmony_ci	  get_uleb128 (offset, program, end);
175da0c48c4Sopenharmony_ci	def_cfa:
176da0c48c4Sopenharmony_ci	  fs->cfa_rule = cfa_offset;
177da0c48c4Sopenharmony_ci	  fs->cfa_val_reg = operand;
178da0c48c4Sopenharmony_ci	  fs->cfa_val_offset = offset;
179da0c48c4Sopenharmony_ci	  /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it.  */
180da0c48c4Sopenharmony_ci	  fs->cfa_data.offset.atom = DW_OP_bregx;
181da0c48c4Sopenharmony_ci	  fs->cfa_data.offset.offset = 0;
182da0c48c4Sopenharmony_ci	  continue;
183da0c48c4Sopenharmony_ci
184da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa_register:
185da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
186da0c48c4Sopenharmony_ci	  require_cfa_offset (fs);
187da0c48c4Sopenharmony_ci	  fs->cfa_val_reg = regno;
188da0c48c4Sopenharmony_ci	  continue;
189da0c48c4Sopenharmony_ci
190da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa_sf:
191da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
192da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
193da0c48c4Sopenharmony_ci	  get_sleb128 (sf_offset, program, end);
194da0c48c4Sopenharmony_ci	  offset = sf_offset * cie->data_alignment_factor;
195da0c48c4Sopenharmony_ci	  goto def_cfa;
196da0c48c4Sopenharmony_ci
197da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa_offset:
198da0c48c4Sopenharmony_ci	  get_uleb128 (offset, program, end);
199da0c48c4Sopenharmony_ci	def_cfa_offset:
200da0c48c4Sopenharmony_ci	  require_cfa_offset (fs);
201da0c48c4Sopenharmony_ci	  fs->cfa_val_offset = offset;
202da0c48c4Sopenharmony_ci	  continue;
203da0c48c4Sopenharmony_ci
204da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa_offset_sf:
205da0c48c4Sopenharmony_ci	  get_sleb128 (sf_offset, program, end);
206da0c48c4Sopenharmony_ci	  offset = sf_offset * cie->data_alignment_factor;
207da0c48c4Sopenharmony_ci	  goto def_cfa_offset;
208da0c48c4Sopenharmony_ci
209da0c48c4Sopenharmony_ci	case DW_CFA_def_cfa_expression:
210da0c48c4Sopenharmony_ci	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
211da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
212da0c48c4Sopenharmony_ci	  cfi_assert (operand <= (Dwarf_Word) (end - program));
213da0c48c4Sopenharmony_ci	  fs->cfa_rule = cfa_expr;
214da0c48c4Sopenharmony_ci	  fs->cfa_data.expr.data = (unsigned char *) program;
215da0c48c4Sopenharmony_ci	  fs->cfa_data.expr.length = operand;
216da0c48c4Sopenharmony_ci	  program += operand;
217da0c48c4Sopenharmony_ci	  continue;
218da0c48c4Sopenharmony_ci
219da0c48c4Sopenharmony_ci	case DW_CFA_undefined:
220da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
221da0c48c4Sopenharmony_ci	  register_rule (regno, undefined, 0);
222da0c48c4Sopenharmony_ci	  continue;
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci	case DW_CFA_same_value:
225da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
226da0c48c4Sopenharmony_ci	  register_rule (regno, same_value, 0);
227da0c48c4Sopenharmony_ci	  continue;
228da0c48c4Sopenharmony_ci
229da0c48c4Sopenharmony_ci	case DW_CFA_offset_extended:
230da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
231da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
232da0c48c4Sopenharmony_ci	  FALLTHROUGH;
233da0c48c4Sopenharmony_ci	case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX:
234da0c48c4Sopenharmony_ci	  get_uleb128 (offset, program, end);
235da0c48c4Sopenharmony_ci	  offset *= cie->data_alignment_factor;
236da0c48c4Sopenharmony_ci	offset_extended:
237da0c48c4Sopenharmony_ci	  register_rule (operand, offset, offset);
238da0c48c4Sopenharmony_ci	  continue;
239da0c48c4Sopenharmony_ci
240da0c48c4Sopenharmony_ci	case DW_CFA_offset_extended_sf:
241da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
242da0c48c4Sopenharmony_ci	  get_sleb128 (sf_offset, program, end);
243da0c48c4Sopenharmony_ci	offset_extended_sf:
244da0c48c4Sopenharmony_ci	  offset = sf_offset * cie->data_alignment_factor;
245da0c48c4Sopenharmony_ci	  goto offset_extended;
246da0c48c4Sopenharmony_ci
247da0c48c4Sopenharmony_ci	case DW_CFA_GNU_negative_offset_extended:
248da0c48c4Sopenharmony_ci	  /* GNU extension obsoleted by DW_CFA_offset_extended_sf.  */
249da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
250da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
251da0c48c4Sopenharmony_ci	  get_uleb128 (offset, program, end);
252da0c48c4Sopenharmony_ci	  sf_offset = -offset;
253da0c48c4Sopenharmony_ci	  goto offset_extended_sf;
254da0c48c4Sopenharmony_ci
255da0c48c4Sopenharmony_ci	case DW_CFA_val_offset:
256da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
257da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
258da0c48c4Sopenharmony_ci	  get_uleb128 (offset, program, end);
259da0c48c4Sopenharmony_ci	  offset *= cie->data_alignment_factor;
260da0c48c4Sopenharmony_ci	val_offset:
261da0c48c4Sopenharmony_ci	  register_rule (operand, val_offset, offset);
262da0c48c4Sopenharmony_ci	  continue;
263da0c48c4Sopenharmony_ci
264da0c48c4Sopenharmony_ci	case DW_CFA_val_offset_sf:
265da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
266da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
267da0c48c4Sopenharmony_ci	  get_sleb128 (sf_offset, program, end);
268da0c48c4Sopenharmony_ci	  offset = sf_offset * cie->data_alignment_factor;
269da0c48c4Sopenharmony_ci	  goto val_offset;
270da0c48c4Sopenharmony_ci
271da0c48c4Sopenharmony_ci	case DW_CFA_register:
272da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
273da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
274da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
275da0c48c4Sopenharmony_ci	  register_rule (regno, register, operand);
276da0c48c4Sopenharmony_ci	  continue;
277da0c48c4Sopenharmony_ci
278da0c48c4Sopenharmony_ci	case DW_CFA_expression:
279da0c48c4Sopenharmony_ci	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
280da0c48c4Sopenharmony_ci	  assert (! abi_cfi);
281da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
282da0c48c4Sopenharmony_ci	  offset = program - (const uint8_t *) cache->data->d.d_buf;
283da0c48c4Sopenharmony_ci	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
284da0c48c4Sopenharmony_ci	  cfi_assert (program < end);
285da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
286da0c48c4Sopenharmony_ci	  cfi_assert (operand <= (Dwarf_Word) (end - program));
287da0c48c4Sopenharmony_ci	  program += operand;
288da0c48c4Sopenharmony_ci	  register_rule (regno, expression, offset);
289da0c48c4Sopenharmony_ci	  continue;
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci	case DW_CFA_val_expression:
292da0c48c4Sopenharmony_ci	  /* Expression rule relies on section data, abi_cfi cannot use it.  */
293da0c48c4Sopenharmony_ci	  assert (! abi_cfi);
294da0c48c4Sopenharmony_ci	  get_uleb128 (regno, program, end);
295da0c48c4Sopenharmony_ci	  /* DW_FORM_block is a ULEB128 length followed by that many bytes.  */
296da0c48c4Sopenharmony_ci	  offset = program - (const uint8_t *) cache->data->d.d_buf;
297da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
298da0c48c4Sopenharmony_ci	  cfi_assert (operand <= (Dwarf_Word) (end - program));
299da0c48c4Sopenharmony_ci	  program += operand;
300da0c48c4Sopenharmony_ci	  register_rule (regno, val_expression, offset);
301da0c48c4Sopenharmony_ci	  continue;
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci	case DW_CFA_restore_extended:
304da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
305da0c48c4Sopenharmony_ci	  FALLTHROUGH;
306da0c48c4Sopenharmony_ci	case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX:
307da0c48c4Sopenharmony_ci
308da0c48c4Sopenharmony_ci	  if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore))
309da0c48c4Sopenharmony_ci	    {
310da0c48c4Sopenharmony_ci	      /* Special case hack to give backend abi_cfi a shorthand.  */
311da0c48c4Sopenharmony_ci	      cache->default_same_value = true;
312da0c48c4Sopenharmony_ci	      continue;
313da0c48c4Sopenharmony_ci	    }
314da0c48c4Sopenharmony_ci
315da0c48c4Sopenharmony_ci	  /* This can't be used in the CIE's own initial instructions.  */
316da0c48c4Sopenharmony_ci	  cfi_assert (cie->initial_state != NULL);
317da0c48c4Sopenharmony_ci
318da0c48c4Sopenharmony_ci	  /* Restore the CIE's initial rule for this register.  */
319da0c48c4Sopenharmony_ci	  if (unlikely (! enough_registers (operand, &fs, &result)))
320da0c48c4Sopenharmony_ci	    goto out;
321da0c48c4Sopenharmony_ci	  if (cie->initial_state->nregs > operand)
322da0c48c4Sopenharmony_ci	    fs->regs[operand] = cie->initial_state->regs[operand];
323da0c48c4Sopenharmony_ci	  else
324da0c48c4Sopenharmony_ci	    fs->regs[operand].rule = reg_unspecified;
325da0c48c4Sopenharmony_ci	  continue;
326da0c48c4Sopenharmony_ci
327da0c48c4Sopenharmony_ci	case DW_CFA_remember_state:
328da0c48c4Sopenharmony_ci	  {
329da0c48c4Sopenharmony_ci	    /* Duplicate the state and chain the copy on.  */
330da0c48c4Sopenharmony_ci	    Dwarf_Frame *copy = duplicate_frame_state (fs, fs);
331da0c48c4Sopenharmony_ci	    if (unlikely (copy == NULL))
332da0c48c4Sopenharmony_ci	      {
333da0c48c4Sopenharmony_ci		result = DWARF_E_NOMEM;
334da0c48c4Sopenharmony_ci		goto out;
335da0c48c4Sopenharmony_ci	      }
336da0c48c4Sopenharmony_ci	    fs = copy;
337da0c48c4Sopenharmony_ci	    continue;
338da0c48c4Sopenharmony_ci	  }
339da0c48c4Sopenharmony_ci
340da0c48c4Sopenharmony_ci	case DW_CFA_restore_state:
341da0c48c4Sopenharmony_ci	  {
342da0c48c4Sopenharmony_ci	    /* Pop the current state off and use the old one instead.  */
343da0c48c4Sopenharmony_ci	    Dwarf_Frame *prev = fs->prev;
344da0c48c4Sopenharmony_ci	    cfi_assert (prev != NULL);
345da0c48c4Sopenharmony_ci	    free (fs);
346da0c48c4Sopenharmony_ci	    fs = prev;
347da0c48c4Sopenharmony_ci	    continue;
348da0c48c4Sopenharmony_ci	  }
349da0c48c4Sopenharmony_ci
350da0c48c4Sopenharmony_ci	case DW_CFA_nop:
351da0c48c4Sopenharmony_ci	  continue;
352da0c48c4Sopenharmony_ci
353da0c48c4Sopenharmony_ci	case DW_CFA_GNU_window_save: /* DW_CFA_AARCH64_negate_ra_state */
354da0c48c4Sopenharmony_ci	  if (cache->e_machine == EM_AARCH64)
355da0c48c4Sopenharmony_ci	    {
356da0c48c4Sopenharmony_ci	      /* Toggles the return address state, indicating whether
357da0c48c4Sopenharmony_ci		 the return address is encrypted or not on
358da0c48c4Sopenharmony_ci		 aarch64. XXX not handled yet.  */
359da0c48c4Sopenharmony_ci	    }
360da0c48c4Sopenharmony_ci	  else
361da0c48c4Sopenharmony_ci	    {
362da0c48c4Sopenharmony_ci	      /* This is magic shorthand used only by SPARC.  It's
363da0c48c4Sopenharmony_ci		 equivalent to a bunch of DW_CFA_register and
364da0c48c4Sopenharmony_ci		 DW_CFA_offset operations.  */
365da0c48c4Sopenharmony_ci	      if (unlikely (! enough_registers (31, &fs, &result)))
366da0c48c4Sopenharmony_ci		goto out;
367da0c48c4Sopenharmony_ci	      for (regno = 8; regno < 16; ++regno)
368da0c48c4Sopenharmony_ci		{
369da0c48c4Sopenharmony_ci		  /* Find each %oN in %iN.  */
370da0c48c4Sopenharmony_ci		  fs->regs[regno].rule = reg_register;
371da0c48c4Sopenharmony_ci		  fs->regs[regno].value = regno + 16;
372da0c48c4Sopenharmony_ci		}
373da0c48c4Sopenharmony_ci	      unsigned int address_size;
374da0c48c4Sopenharmony_ci	      address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32
375da0c48c4Sopenharmony_ci			      ? 4 : 8);
376da0c48c4Sopenharmony_ci	      for (; regno < 32; ++regno)
377da0c48c4Sopenharmony_ci		{
378da0c48c4Sopenharmony_ci		  /* Find %l0..%l7 and %i0..%i7 in a block at the CFA.  */
379da0c48c4Sopenharmony_ci		  fs->regs[regno].rule = reg_offset;
380da0c48c4Sopenharmony_ci		  fs->regs[regno].value = (regno - 16) * address_size;
381da0c48c4Sopenharmony_ci		}
382da0c48c4Sopenharmony_ci	    }
383da0c48c4Sopenharmony_ci	  continue;
384da0c48c4Sopenharmony_ci
385da0c48c4Sopenharmony_ci	case DW_CFA_GNU_args_size:
386da0c48c4Sopenharmony_ci	  /* XXX is this useful for anything? */
387da0c48c4Sopenharmony_ci	  get_uleb128 (operand, program, end);
388da0c48c4Sopenharmony_ci	  continue;
389da0c48c4Sopenharmony_ci
390da0c48c4Sopenharmony_ci	default:
391da0c48c4Sopenharmony_ci	  cfi_assert (false);
392da0c48c4Sopenharmony_ci	  continue;
393da0c48c4Sopenharmony_ci	}
394da0c48c4Sopenharmony_ci
395da0c48c4Sopenharmony_ci      /* We get here only for the cases that have just moved LOC.  */
396da0c48c4Sopenharmony_ci      cfi_assert (cie->initial_state != NULL);
397da0c48c4Sopenharmony_ci      if (find_pc >= loc)
398da0c48c4Sopenharmony_ci	/* This advance has not yet reached FIND_PC.  */
399da0c48c4Sopenharmony_ci	fs->start = loc;
400da0c48c4Sopenharmony_ci      else
401da0c48c4Sopenharmony_ci	{
402da0c48c4Sopenharmony_ci	  /* We have just advanced past the address we're looking for.
403da0c48c4Sopenharmony_ci	     The state currently described is what we want to see.  */
404da0c48c4Sopenharmony_ci	  fs->end = loc;
405da0c48c4Sopenharmony_ci	  break;
406da0c48c4Sopenharmony_ci	}
407da0c48c4Sopenharmony_ci    }
408da0c48c4Sopenharmony_ci
409da0c48c4Sopenharmony_ci  /* "The end of the instruction stream can be thought of as a
410da0c48c4Sopenharmony_ci     DW_CFA_set_loc (initial_location + address_range) instruction."
411da0c48c4Sopenharmony_ci     (DWARF 3.0 Section 6.4.3)
412da0c48c4Sopenharmony_ci
413da0c48c4Sopenharmony_ci     When we fall off the end of the program without an advance_loc/set_loc
414da0c48c4Sopenharmony_ci     that put us past FIND_PC, the final state left by the FDE program
415da0c48c4Sopenharmony_ci     applies to this address (the caller ensured it was inside the FDE).
416da0c48c4Sopenharmony_ci     This address (FDE->end) is already in FS->end as set by the caller.  */
417da0c48c4Sopenharmony_ci
418da0c48c4Sopenharmony_ci#undef register_rule
419da0c48c4Sopenharmony_ci#undef cfi_assert
420da0c48c4Sopenharmony_ci
421da0c48c4Sopenharmony_ci out:
422da0c48c4Sopenharmony_ci
423da0c48c4Sopenharmony_ci  /* Pop any remembered states left on the stack.  */
424da0c48c4Sopenharmony_ci  while (fs->prev != NULL)
425da0c48c4Sopenharmony_ci    {
426da0c48c4Sopenharmony_ci      Dwarf_Frame *prev = fs->prev;
427da0c48c4Sopenharmony_ci      fs->prev = prev->prev;
428da0c48c4Sopenharmony_ci      free (prev);
429da0c48c4Sopenharmony_ci    }
430da0c48c4Sopenharmony_ci
431da0c48c4Sopenharmony_ci  if (likely (result == DWARF_E_NOERROR))
432da0c48c4Sopenharmony_ci    *state = fs;
433da0c48c4Sopenharmony_ci  else
434da0c48c4Sopenharmony_ci    free (fs);
435da0c48c4Sopenharmony_ci
436da0c48c4Sopenharmony_ci  return result;
437da0c48c4Sopenharmony_ci}
438da0c48c4Sopenharmony_ci
439da0c48c4Sopenharmony_cistatic int
440da0c48c4Sopenharmony_cicie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie)
441da0c48c4Sopenharmony_ci{
442da0c48c4Sopenharmony_ci  int result = DWARF_E_NOERROR;
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_ci  if (likely (cie->initial_state != NULL))
445da0c48c4Sopenharmony_ci    return result;
446da0c48c4Sopenharmony_ci
447da0c48c4Sopenharmony_ci  /* This CIE has not been used before.  Play out its initial
448da0c48c4Sopenharmony_ci     instructions and cache the initial state that results.
449da0c48c4Sopenharmony_ci     First we'll let the backend fill in the default initial
450da0c48c4Sopenharmony_ci     state for this machine's ABI.  */
451da0c48c4Sopenharmony_ci
452da0c48c4Sopenharmony_ci  Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 };
453da0c48c4Sopenharmony_ci
454da0c48c4Sopenharmony_ci  /* Make sure we have a backend handle cached.  */
455da0c48c4Sopenharmony_ci  if (unlikely (cache->ebl == NULL))
456da0c48c4Sopenharmony_ci    {
457da0c48c4Sopenharmony_ci      cache->ebl = ebl_openbackend (cache->data->s->elf);
458da0c48c4Sopenharmony_ci      if (unlikely (cache->ebl == NULL))
459da0c48c4Sopenharmony_ci	cache->ebl = (void *) -1l;
460da0c48c4Sopenharmony_ci    }
461da0c48c4Sopenharmony_ci
462da0c48c4Sopenharmony_ci  /* Fetch the ABI's default CFI program.  */
463da0c48c4Sopenharmony_ci  if (likely (cache->ebl != (void *) -1l)
464da0c48c4Sopenharmony_ci      && unlikely (ebl_abi_cfi (cache->ebl, &abi_info) < 0))
465da0c48c4Sopenharmony_ci    return DWARF_E_UNKNOWN_ERROR;
466da0c48c4Sopenharmony_ci
467da0c48c4Sopenharmony_ci  Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame));
468da0c48c4Sopenharmony_ci  if (unlikely (cie_fs == NULL))
469da0c48c4Sopenharmony_ci    return DWARF_E_NOMEM;
470da0c48c4Sopenharmony_ci
471da0c48c4Sopenharmony_ci  /* If the default state of any register is not "undefined"
472da0c48c4Sopenharmony_ci     (i.e. call-clobbered), then the backend supplies instructions
473da0c48c4Sopenharmony_ci     for the standard initial state.  */
474da0c48c4Sopenharmony_ci  if (abi_info.initial_instructions_end > abi_info.initial_instructions)
475da0c48c4Sopenharmony_ci    {
476da0c48c4Sopenharmony_ci      /* Dummy CIE for backend's instructions.  */
477da0c48c4Sopenharmony_ci      struct dwarf_cie abi_cie =
478da0c48c4Sopenharmony_ci	{
479da0c48c4Sopenharmony_ci	  .code_alignment_factor = abi_info.code_alignment_factor,
480da0c48c4Sopenharmony_ci	  .data_alignment_factor = abi_info.data_alignment_factor,
481da0c48c4Sopenharmony_ci	};
482da0c48c4Sopenharmony_ci      result = execute_cfi (cache, &abi_cie, &cie_fs,
483da0c48c4Sopenharmony_ci			    abi_info.initial_instructions,
484da0c48c4Sopenharmony_ci			    abi_info.initial_instructions_end, true,
485da0c48c4Sopenharmony_ci			    0, (Dwarf_Addr) -1l);
486da0c48c4Sopenharmony_ci    }
487da0c48c4Sopenharmony_ci
488da0c48c4Sopenharmony_ci  /* Now run the CIE's initial instructions.  */
489da0c48c4Sopenharmony_ci  if (cie->initial_instructions_end > cie->initial_instructions
490da0c48c4Sopenharmony_ci      && likely (result == DWARF_E_NOERROR))
491da0c48c4Sopenharmony_ci    result = execute_cfi (cache, cie, &cie_fs,
492da0c48c4Sopenharmony_ci			  cie->initial_instructions,
493da0c48c4Sopenharmony_ci			  cie->initial_instructions_end, false,
494da0c48c4Sopenharmony_ci			  0, (Dwarf_Addr) -1l);
495da0c48c4Sopenharmony_ci
496da0c48c4Sopenharmony_ci  if (likely (result == DWARF_E_NOERROR))
497da0c48c4Sopenharmony_ci    {
498da0c48c4Sopenharmony_ci      /* Now we have the initial state of things that all
499da0c48c4Sopenharmony_ci	 FDEs using this CIE will start from.  */
500da0c48c4Sopenharmony_ci      cie_fs->cache = cache;
501da0c48c4Sopenharmony_ci      cie->initial_state = cie_fs;
502da0c48c4Sopenharmony_ci    }
503da0c48c4Sopenharmony_ci
504da0c48c4Sopenharmony_ci  return result;
505da0c48c4Sopenharmony_ci}
506da0c48c4Sopenharmony_ci
507da0c48c4Sopenharmony_ciint
508da0c48c4Sopenharmony_ciinternal_function
509da0c48c4Sopenharmony_ci__libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
510da0c48c4Sopenharmony_ci			  Dwarf_Addr address, Dwarf_Frame **frame)
511da0c48c4Sopenharmony_ci{
512da0c48c4Sopenharmony_ci  int result = cie_cache_initial_state (cache, fde->cie);
513da0c48c4Sopenharmony_ci  if (likely (result == DWARF_E_NOERROR))
514da0c48c4Sopenharmony_ci    {
515da0c48c4Sopenharmony_ci      Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL);
516da0c48c4Sopenharmony_ci      if (unlikely (fs == NULL))
517da0c48c4Sopenharmony_ci	return DWARF_E_NOMEM;
518da0c48c4Sopenharmony_ci
519da0c48c4Sopenharmony_ci      fs->fde = fde;
520da0c48c4Sopenharmony_ci      fs->start = fde->start;
521da0c48c4Sopenharmony_ci      fs->end = fde->end;
522da0c48c4Sopenharmony_ci
523da0c48c4Sopenharmony_ci      result = execute_cfi (cache, fde->cie, &fs,
524da0c48c4Sopenharmony_ci			    fde->instructions, fde->instructions_end, false,
525da0c48c4Sopenharmony_ci			    fde->start, address);
526da0c48c4Sopenharmony_ci      if (likely (result == DWARF_E_NOERROR))
527da0c48c4Sopenharmony_ci	*frame = fs;
528da0c48c4Sopenharmony_ci    }
529da0c48c4Sopenharmony_ci  return result;
530da0c48c4Sopenharmony_ci}
531