1da0c48c4Sopenharmony_ci/* Get previous frame state for an existing frame state.
2da0c48c4Sopenharmony_ci   Copyright (C) 2013, 2014, 2016 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 "cfi.h"
34da0c48c4Sopenharmony_ci#include <stdlib.h>
35da0c48c4Sopenharmony_ci#include "libdwflP.h"
36da0c48c4Sopenharmony_ci#include "../libdw/dwarf.h"
37da0c48c4Sopenharmony_ci#include <system.h>
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci/* Maximum number of DWARF expression stack slots before returning an error.  */
40da0c48c4Sopenharmony_ci#define DWARF_EXPR_STACK_MAX 0x100
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci/* Maximum number of DWARF expression executed operations before returning an
43da0c48c4Sopenharmony_ci   error.  */
44da0c48c4Sopenharmony_ci#define DWARF_EXPR_STEPS_MAX 0x1000
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ciint
47da0c48c4Sopenharmony_ciinternal_function
48da0c48c4Sopenharmony_ci__libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val)
49da0c48c4Sopenharmony_ci{
50da0c48c4Sopenharmony_ci  Ebl *ebl = state->thread->process->ebl;
51da0c48c4Sopenharmony_ci  if (! ebl_dwarf_to_regno (ebl, &regno))
52da0c48c4Sopenharmony_ci    return -1;
53da0c48c4Sopenharmony_ci  if (regno >= ebl_frame_nregs (ebl))
54da0c48c4Sopenharmony_ci    return -1;
55da0c48c4Sopenharmony_ci  if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
56da0c48c4Sopenharmony_ci       & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)))) == 0)
57da0c48c4Sopenharmony_ci    return 1;
58da0c48c4Sopenharmony_ci  if (val)
59da0c48c4Sopenharmony_ci    *val = state->regs[regno];
60da0c48c4Sopenharmony_ci  return 0;
61da0c48c4Sopenharmony_ci}
62da0c48c4Sopenharmony_ci
63da0c48c4Sopenharmony_cibool
64da0c48c4Sopenharmony_ciinternal_function
65da0c48c4Sopenharmony_ci__libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val)
66da0c48c4Sopenharmony_ci{
67da0c48c4Sopenharmony_ci  Ebl *ebl = state->thread->process->ebl;
68da0c48c4Sopenharmony_ci  if (! ebl_dwarf_to_regno (ebl, &regno))
69da0c48c4Sopenharmony_ci    return false;
70da0c48c4Sopenharmony_ci  if (regno >= ebl_frame_nregs (ebl))
71da0c48c4Sopenharmony_ci    return false;
72da0c48c4Sopenharmony_ci  /* For example i386 user_regs_struct has signed fields.  */
73da0c48c4Sopenharmony_ci  if (ebl_get_elfclass (ebl) == ELFCLASS32)
74da0c48c4Sopenharmony_ci    val &= 0xffffffff;
75da0c48c4Sopenharmony_ci  state->regs_set[regno / sizeof (*state->regs_set) / 8] |=
76da0c48c4Sopenharmony_ci		((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)));
77da0c48c4Sopenharmony_ci  state->regs[regno] = val;
78da0c48c4Sopenharmony_ci  return true;
79da0c48c4Sopenharmony_ci}
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_cistatic int
82da0c48c4Sopenharmony_cibra_compar (const void *key_voidp, const void *elem_voidp)
83da0c48c4Sopenharmony_ci{
84da0c48c4Sopenharmony_ci  Dwarf_Word offset = (uintptr_t) key_voidp;
85da0c48c4Sopenharmony_ci  const Dwarf_Op *op = elem_voidp;
86da0c48c4Sopenharmony_ci  return (offset > op->offset) - (offset < op->offset);
87da0c48c4Sopenharmony_ci}
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_cistruct eval_stack {
90da0c48c4Sopenharmony_ci  Dwarf_Addr *addrs;
91da0c48c4Sopenharmony_ci  size_t used;
92da0c48c4Sopenharmony_ci  size_t allocated;
93da0c48c4Sopenharmony_ci};
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_cistatic bool
96da0c48c4Sopenharmony_cido_push (struct eval_stack *stack, Dwarf_Addr val)
97da0c48c4Sopenharmony_ci{
98da0c48c4Sopenharmony_ci  if (stack->used >= DWARF_EXPR_STACK_MAX)
99da0c48c4Sopenharmony_ci    {
100da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
101da0c48c4Sopenharmony_ci      return false;
102da0c48c4Sopenharmony_ci    }
103da0c48c4Sopenharmony_ci  if (stack->used == stack->allocated)
104da0c48c4Sopenharmony_ci    {
105da0c48c4Sopenharmony_ci      stack->allocated = MAX (stack->allocated * 2, 32);
106da0c48c4Sopenharmony_ci      Dwarf_Addr *new_addrs;
107da0c48c4Sopenharmony_ci      new_addrs = realloc (stack->addrs,
108da0c48c4Sopenharmony_ci			   stack->allocated * sizeof (*stack->addrs));
109da0c48c4Sopenharmony_ci      if (new_addrs == NULL)
110da0c48c4Sopenharmony_ci        {
111da0c48c4Sopenharmony_ci          __libdwfl_seterrno (DWFL_E_NOMEM);
112da0c48c4Sopenharmony_ci          return false;
113da0c48c4Sopenharmony_ci        }
114da0c48c4Sopenharmony_ci      stack->addrs = new_addrs;
115da0c48c4Sopenharmony_ci    }
116da0c48c4Sopenharmony_ci  stack->addrs[stack->used++] = val;
117da0c48c4Sopenharmony_ci  return true;
118da0c48c4Sopenharmony_ci}
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_cistatic bool
121da0c48c4Sopenharmony_cido_pop (struct eval_stack *stack, Dwarf_Addr *val)
122da0c48c4Sopenharmony_ci{
123da0c48c4Sopenharmony_ci  if (stack->used == 0)
124da0c48c4Sopenharmony_ci    {
125da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
126da0c48c4Sopenharmony_ci      return false;
127da0c48c4Sopenharmony_ci    }
128da0c48c4Sopenharmony_ci  *val = stack->addrs[--stack->used];
129da0c48c4Sopenharmony_ci  return true;
130da0c48c4Sopenharmony_ci}
131da0c48c4Sopenharmony_ci
132da0c48c4Sopenharmony_ci/* If FRAME is NULL is are computing CFI frame base.  In such case another
133da0c48c4Sopenharmony_ci   DW_OP_call_frame_cfa is no longer permitted.  */
134da0c48c4Sopenharmony_ci
135da0c48c4Sopenharmony_cistatic bool
136da0c48c4Sopenharmony_ciexpr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
137da0c48c4Sopenharmony_ci	   size_t nops, Dwarf_Addr *result, Dwarf_Addr bias)
138da0c48c4Sopenharmony_ci{
139da0c48c4Sopenharmony_ci  Dwfl_Process *process = state->thread->process;
140da0c48c4Sopenharmony_ci  if (nops == 0)
141da0c48c4Sopenharmony_ci    {
142da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
143da0c48c4Sopenharmony_ci      return false;
144da0c48c4Sopenharmony_ci    }
145da0c48c4Sopenharmony_ci  struct eval_stack stack =
146da0c48c4Sopenharmony_ci    {
147da0c48c4Sopenharmony_ci      .addrs = NULL,
148da0c48c4Sopenharmony_ci      .used = 0,
149da0c48c4Sopenharmony_ci      .allocated = 0
150da0c48c4Sopenharmony_ci    };
151da0c48c4Sopenharmony_ci
152da0c48c4Sopenharmony_ci#define pop(x) do_pop(&stack, x)
153da0c48c4Sopenharmony_ci#define push(x) do_push(&stack, x)
154da0c48c4Sopenharmony_ci
155da0c48c4Sopenharmony_ci  Dwarf_Addr val1, val2;
156da0c48c4Sopenharmony_ci  bool is_location = false;
157da0c48c4Sopenharmony_ci  size_t steps_count = 0;
158da0c48c4Sopenharmony_ci  for (const Dwarf_Op *op = ops; op < ops + nops; op++)
159da0c48c4Sopenharmony_ci    {
160da0c48c4Sopenharmony_ci      if (++steps_count > DWARF_EXPR_STEPS_MAX)
161da0c48c4Sopenharmony_ci	{
162da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
163da0c48c4Sopenharmony_ci	  return false;
164da0c48c4Sopenharmony_ci	}
165da0c48c4Sopenharmony_ci      switch (op->atom)
166da0c48c4Sopenharmony_ci      {
167da0c48c4Sopenharmony_ci	/* DW_OP_* order matches libgcc/unwind-dw2.c execute_stack_op:  */
168da0c48c4Sopenharmony_ci	case DW_OP_lit0 ... DW_OP_lit31:
169da0c48c4Sopenharmony_ci	  if (! push (op->atom - DW_OP_lit0))
170da0c48c4Sopenharmony_ci	    {
171da0c48c4Sopenharmony_ci	      free (stack.addrs);
172da0c48c4Sopenharmony_ci	      return false;
173da0c48c4Sopenharmony_ci	    }
174da0c48c4Sopenharmony_ci	  break;
175da0c48c4Sopenharmony_ci	case DW_OP_addr:
176da0c48c4Sopenharmony_ci	  if (! push (op->number + bias))
177da0c48c4Sopenharmony_ci	    {
178da0c48c4Sopenharmony_ci	      free (stack.addrs);
179da0c48c4Sopenharmony_ci	      return false;
180da0c48c4Sopenharmony_ci	    }
181da0c48c4Sopenharmony_ci	  break;
182da0c48c4Sopenharmony_ci	case DW_OP_GNU_encoded_addr:
183da0c48c4Sopenharmony_ci	  /* Missing support in the rest of elfutils.  */
184da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_UNSUPPORTED_DWARF);
185da0c48c4Sopenharmony_ci	  return false;
186da0c48c4Sopenharmony_ci	case DW_OP_const1u:
187da0c48c4Sopenharmony_ci	case DW_OP_const1s:
188da0c48c4Sopenharmony_ci	case DW_OP_const2u:
189da0c48c4Sopenharmony_ci	case DW_OP_const2s:
190da0c48c4Sopenharmony_ci	case DW_OP_const4u:
191da0c48c4Sopenharmony_ci	case DW_OP_const4s:
192da0c48c4Sopenharmony_ci	case DW_OP_const8u:
193da0c48c4Sopenharmony_ci	case DW_OP_const8s:
194da0c48c4Sopenharmony_ci	case DW_OP_constu:
195da0c48c4Sopenharmony_ci	case DW_OP_consts:
196da0c48c4Sopenharmony_ci	  if (! push (op->number))
197da0c48c4Sopenharmony_ci	    {
198da0c48c4Sopenharmony_ci	      free (stack.addrs);
199da0c48c4Sopenharmony_ci	      return false;
200da0c48c4Sopenharmony_ci	    }
201da0c48c4Sopenharmony_ci	  break;
202da0c48c4Sopenharmony_ci	case DW_OP_reg0 ... DW_OP_reg31:
203da0c48c4Sopenharmony_ci	  if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_reg0, &val1) != 0
204da0c48c4Sopenharmony_ci	      || ! push (val1))
205da0c48c4Sopenharmony_ci	    {
206da0c48c4Sopenharmony_ci	      free (stack.addrs);
207da0c48c4Sopenharmony_ci	      return false;
208da0c48c4Sopenharmony_ci	    }
209da0c48c4Sopenharmony_ci	  break;
210da0c48c4Sopenharmony_ci	case DW_OP_regx:
211da0c48c4Sopenharmony_ci	  if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0 || ! push (val1))
212da0c48c4Sopenharmony_ci	    {
213da0c48c4Sopenharmony_ci	      free (stack.addrs);
214da0c48c4Sopenharmony_ci	      return false;
215da0c48c4Sopenharmony_ci	    }
216da0c48c4Sopenharmony_ci	  break;
217da0c48c4Sopenharmony_ci	case DW_OP_breg0 ... DW_OP_breg31:
218da0c48c4Sopenharmony_ci	  if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_breg0, &val1) != 0)
219da0c48c4Sopenharmony_ci	    {
220da0c48c4Sopenharmony_ci	      free (stack.addrs);
221da0c48c4Sopenharmony_ci	      return false;
222da0c48c4Sopenharmony_ci	    }
223da0c48c4Sopenharmony_ci	  val1 += op->number;
224da0c48c4Sopenharmony_ci	  if (! push (val1))
225da0c48c4Sopenharmony_ci	    {
226da0c48c4Sopenharmony_ci	      free (stack.addrs);
227da0c48c4Sopenharmony_ci	      return false;
228da0c48c4Sopenharmony_ci	    }
229da0c48c4Sopenharmony_ci	  break;
230da0c48c4Sopenharmony_ci	case DW_OP_bregx:
231da0c48c4Sopenharmony_ci	  if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0)
232da0c48c4Sopenharmony_ci	    {
233da0c48c4Sopenharmony_ci	      free (stack.addrs);
234da0c48c4Sopenharmony_ci	      return false;
235da0c48c4Sopenharmony_ci	    }
236da0c48c4Sopenharmony_ci	  val1 += op->number2;
237da0c48c4Sopenharmony_ci	  if (! push (val1))
238da0c48c4Sopenharmony_ci	    {
239da0c48c4Sopenharmony_ci	      free (stack.addrs);
240da0c48c4Sopenharmony_ci	      return false;
241da0c48c4Sopenharmony_ci	    }
242da0c48c4Sopenharmony_ci	  break;
243da0c48c4Sopenharmony_ci	case DW_OP_dup:
244da0c48c4Sopenharmony_ci	  if (! pop (&val1) || ! push (val1) || ! push (val1))
245da0c48c4Sopenharmony_ci	    {
246da0c48c4Sopenharmony_ci	      free (stack.addrs);
247da0c48c4Sopenharmony_ci	      return false;
248da0c48c4Sopenharmony_ci	    }
249da0c48c4Sopenharmony_ci	  break;
250da0c48c4Sopenharmony_ci	case DW_OP_drop:
251da0c48c4Sopenharmony_ci	  if (! pop (&val1))
252da0c48c4Sopenharmony_ci	    {
253da0c48c4Sopenharmony_ci	      free (stack.addrs);
254da0c48c4Sopenharmony_ci	      return false;
255da0c48c4Sopenharmony_ci	    }
256da0c48c4Sopenharmony_ci	  break;
257da0c48c4Sopenharmony_ci	case DW_OP_pick:
258da0c48c4Sopenharmony_ci	  if (stack.used <= op->number)
259da0c48c4Sopenharmony_ci	    {
260da0c48c4Sopenharmony_ci	      free (stack.addrs);
261da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
262da0c48c4Sopenharmony_ci	      return false;
263da0c48c4Sopenharmony_ci	    }
264da0c48c4Sopenharmony_ci	  if (! push (stack.addrs[stack.used - 1 - op->number]))
265da0c48c4Sopenharmony_ci	    {
266da0c48c4Sopenharmony_ci	      free (stack.addrs);
267da0c48c4Sopenharmony_ci	      return false;
268da0c48c4Sopenharmony_ci	    }
269da0c48c4Sopenharmony_ci	  break;
270da0c48c4Sopenharmony_ci	case DW_OP_over:
271da0c48c4Sopenharmony_ci	  if (! pop (&val1) || ! pop (&val2)
272da0c48c4Sopenharmony_ci	      || ! push (val2) || ! push (val1) || ! push (val2))
273da0c48c4Sopenharmony_ci	    {
274da0c48c4Sopenharmony_ci	      free (stack.addrs);
275da0c48c4Sopenharmony_ci	      return false;
276da0c48c4Sopenharmony_ci	    }
277da0c48c4Sopenharmony_ci	  break;
278da0c48c4Sopenharmony_ci	case DW_OP_swap:
279da0c48c4Sopenharmony_ci	  if (! pop (&val1) || ! pop (&val2) || ! push (val1) || ! push (val2))
280da0c48c4Sopenharmony_ci	    {
281da0c48c4Sopenharmony_ci	      free (stack.addrs);
282da0c48c4Sopenharmony_ci	      return false;
283da0c48c4Sopenharmony_ci	    }
284da0c48c4Sopenharmony_ci	  break;
285da0c48c4Sopenharmony_ci	case DW_OP_rot:
286da0c48c4Sopenharmony_ci	  {
287da0c48c4Sopenharmony_ci	    Dwarf_Addr val3;
288da0c48c4Sopenharmony_ci	    if (! pop (&val1) || ! pop (&val2) || ! pop (&val3)
289da0c48c4Sopenharmony_ci		|| ! push (val1) || ! push (val3) || ! push (val2))
290da0c48c4Sopenharmony_ci	      {
291da0c48c4Sopenharmony_ci		free (stack.addrs);
292da0c48c4Sopenharmony_ci		return false;
293da0c48c4Sopenharmony_ci	      }
294da0c48c4Sopenharmony_ci	  }
295da0c48c4Sopenharmony_ci	  break;
296da0c48c4Sopenharmony_ci	case DW_OP_deref:
297da0c48c4Sopenharmony_ci	case DW_OP_deref_size:
298da0c48c4Sopenharmony_ci	  if (process->callbacks->memory_read == NULL)
299da0c48c4Sopenharmony_ci	    {
300da0c48c4Sopenharmony_ci	      free (stack.addrs);
301da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT);
302da0c48c4Sopenharmony_ci	      return false;
303da0c48c4Sopenharmony_ci	    }
304da0c48c4Sopenharmony_ci	  if (! pop (&val1)
305da0c48c4Sopenharmony_ci	      || ! process->callbacks->memory_read (process->dwfl, val1, &val1,
306da0c48c4Sopenharmony_ci						    process->callbacks_arg))
307da0c48c4Sopenharmony_ci	    {
308da0c48c4Sopenharmony_ci	      free (stack.addrs);
309da0c48c4Sopenharmony_ci	      return false;
310da0c48c4Sopenharmony_ci	    }
311da0c48c4Sopenharmony_ci	  if (op->atom == DW_OP_deref_size)
312da0c48c4Sopenharmony_ci	    {
313da0c48c4Sopenharmony_ci	      const int elfclass = frame->cache->e_ident[EI_CLASS];
314da0c48c4Sopenharmony_ci	      const unsigned addr_bytes = elfclass == ELFCLASS32 ? 4 : 8;
315da0c48c4Sopenharmony_ci	      if (op->number > addr_bytes)
316da0c48c4Sopenharmony_ci		{
317da0c48c4Sopenharmony_ci		  free (stack.addrs);
318da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
319da0c48c4Sopenharmony_ci		  return false;
320da0c48c4Sopenharmony_ci		}
321da0c48c4Sopenharmony_ci#if BYTE_ORDER == BIG_ENDIAN
322da0c48c4Sopenharmony_ci	      if (op->number == 0)
323da0c48c4Sopenharmony_ci		val1 = 0;
324da0c48c4Sopenharmony_ci	      else
325da0c48c4Sopenharmony_ci		val1 >>= (addr_bytes - op->number) * 8;
326da0c48c4Sopenharmony_ci#else
327da0c48c4Sopenharmony_ci	      if (op->number < 8)
328da0c48c4Sopenharmony_ci		val1 &= (1ULL << (op->number * 8)) - 1;
329da0c48c4Sopenharmony_ci#endif
330da0c48c4Sopenharmony_ci	    }
331da0c48c4Sopenharmony_ci	  if (! push (val1))
332da0c48c4Sopenharmony_ci	    {
333da0c48c4Sopenharmony_ci	      free (stack.addrs);
334da0c48c4Sopenharmony_ci	      return false;
335da0c48c4Sopenharmony_ci	    }
336da0c48c4Sopenharmony_ci	  break;
337da0c48c4Sopenharmony_ci#define UNOP(atom, expr)						\
338da0c48c4Sopenharmony_ci	case atom:							\
339da0c48c4Sopenharmony_ci	  if (! pop (&val1) || ! push (expr))				\
340da0c48c4Sopenharmony_ci	    {								\
341da0c48c4Sopenharmony_ci	      free (stack.addrs);					\
342da0c48c4Sopenharmony_ci	      return false;						\
343da0c48c4Sopenharmony_ci	    }								\
344da0c48c4Sopenharmony_ci	  break;
345da0c48c4Sopenharmony_ci	UNOP (DW_OP_abs, llabs ((int64_t) val1))
346da0c48c4Sopenharmony_ci	UNOP (DW_OP_neg, -(int64_t) val1)
347da0c48c4Sopenharmony_ci	UNOP (DW_OP_not, ~val1)
348da0c48c4Sopenharmony_ci#undef UNOP
349da0c48c4Sopenharmony_ci	case DW_OP_plus_uconst:
350da0c48c4Sopenharmony_ci	  if (! pop (&val1) || ! push (val1 + op->number))
351da0c48c4Sopenharmony_ci	    {
352da0c48c4Sopenharmony_ci	      free (stack.addrs);
353da0c48c4Sopenharmony_ci	      return false;
354da0c48c4Sopenharmony_ci	    }
355da0c48c4Sopenharmony_ci	  break;
356da0c48c4Sopenharmony_ci#define BINOP(atom, op)							\
357da0c48c4Sopenharmony_ci	case atom:							\
358da0c48c4Sopenharmony_ci	  if (! pop (&val2) || ! pop (&val1) || ! push (val1 op val2))	\
359da0c48c4Sopenharmony_ci	    {								\
360da0c48c4Sopenharmony_ci	      free (stack.addrs);					\
361da0c48c4Sopenharmony_ci	      return false;						\
362da0c48c4Sopenharmony_ci	    }								\
363da0c48c4Sopenharmony_ci	  break;
364da0c48c4Sopenharmony_ci#define BINOP_SIGNED(atom, op)						\
365da0c48c4Sopenharmony_ci	case atom:							\
366da0c48c4Sopenharmony_ci	  if (! pop (&val2) || ! pop (&val1)				\
367da0c48c4Sopenharmony_ci	      || ! push ((int64_t) val1 op (int64_t) val2))		\
368da0c48c4Sopenharmony_ci	    {								\
369da0c48c4Sopenharmony_ci	      free (stack.addrs);					\
370da0c48c4Sopenharmony_ci	      return false;						\
371da0c48c4Sopenharmony_ci	    }								\
372da0c48c4Sopenharmony_ci	  break;
373da0c48c4Sopenharmony_ci	BINOP (DW_OP_and, &)
374da0c48c4Sopenharmony_ci	case DW_OP_div:
375da0c48c4Sopenharmony_ci	  if (! pop (&val2) || ! pop (&val1))
376da0c48c4Sopenharmony_ci	    {
377da0c48c4Sopenharmony_ci	      free (stack.addrs);
378da0c48c4Sopenharmony_ci	      return false;
379da0c48c4Sopenharmony_ci	    }
380da0c48c4Sopenharmony_ci	  if (val2 == 0)
381da0c48c4Sopenharmony_ci	    {
382da0c48c4Sopenharmony_ci	      free (stack.addrs);
383da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
384da0c48c4Sopenharmony_ci	      return false;
385da0c48c4Sopenharmony_ci	    }
386da0c48c4Sopenharmony_ci	  if (! push ((int64_t) val1 / (int64_t) val2))
387da0c48c4Sopenharmony_ci	    {
388da0c48c4Sopenharmony_ci	      free (stack.addrs);
389da0c48c4Sopenharmony_ci	      return false;
390da0c48c4Sopenharmony_ci	    }
391da0c48c4Sopenharmony_ci	  break;
392da0c48c4Sopenharmony_ci	BINOP (DW_OP_minus, -)
393da0c48c4Sopenharmony_ci	case DW_OP_mod:
394da0c48c4Sopenharmony_ci	  if (! pop (&val2) || ! pop (&val1))
395da0c48c4Sopenharmony_ci	    {
396da0c48c4Sopenharmony_ci	      free (stack.addrs);
397da0c48c4Sopenharmony_ci	      return false;
398da0c48c4Sopenharmony_ci	    }
399da0c48c4Sopenharmony_ci	  if (val2 == 0)
400da0c48c4Sopenharmony_ci	    {
401da0c48c4Sopenharmony_ci	      free (stack.addrs);
402da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
403da0c48c4Sopenharmony_ci	      return false;
404da0c48c4Sopenharmony_ci	    }
405da0c48c4Sopenharmony_ci	  if (! push (val1 % val2))
406da0c48c4Sopenharmony_ci	    {
407da0c48c4Sopenharmony_ci	      free (stack.addrs);
408da0c48c4Sopenharmony_ci	      return false;
409da0c48c4Sopenharmony_ci	    }
410da0c48c4Sopenharmony_ci	  break;
411da0c48c4Sopenharmony_ci	BINOP (DW_OP_mul, *)
412da0c48c4Sopenharmony_ci	BINOP (DW_OP_or, |)
413da0c48c4Sopenharmony_ci	BINOP (DW_OP_plus, +)
414da0c48c4Sopenharmony_ci	BINOP (DW_OP_shl, <<)
415da0c48c4Sopenharmony_ci	BINOP (DW_OP_shr, >>)
416da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_shra, >>)
417da0c48c4Sopenharmony_ci	BINOP (DW_OP_xor, ^)
418da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_le, <=)
419da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_ge, >=)
420da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_eq, ==)
421da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_lt, <)
422da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_gt, >)
423da0c48c4Sopenharmony_ci	BINOP_SIGNED (DW_OP_ne, !=)
424da0c48c4Sopenharmony_ci#undef BINOP
425da0c48c4Sopenharmony_ci#undef BINOP_SIGNED
426da0c48c4Sopenharmony_ci	case DW_OP_bra:
427da0c48c4Sopenharmony_ci	  if (! pop (&val1))
428da0c48c4Sopenharmony_ci	    {
429da0c48c4Sopenharmony_ci	      free (stack.addrs);
430da0c48c4Sopenharmony_ci	      return false;
431da0c48c4Sopenharmony_ci	    }
432da0c48c4Sopenharmony_ci	  if (val1 == 0)
433da0c48c4Sopenharmony_ci	    break;
434da0c48c4Sopenharmony_ci	  FALLTHROUGH;
435da0c48c4Sopenharmony_ci	case DW_OP_skip:;
436da0c48c4Sopenharmony_ci	  Dwarf_Word offset = op->offset + 1 + 2 + (int16_t) op->number;
437da0c48c4Sopenharmony_ci	  const Dwarf_Op *found = bsearch ((void *) (uintptr_t) offset, ops, nops,
438da0c48c4Sopenharmony_ci					   sizeof (*ops), bra_compar);
439da0c48c4Sopenharmony_ci	  if (found == NULL)
440da0c48c4Sopenharmony_ci	    {
441da0c48c4Sopenharmony_ci	      free (stack.addrs);
442da0c48c4Sopenharmony_ci	      /* PPC32 vDSO has such invalid operations.  */
443da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
444da0c48c4Sopenharmony_ci	      return false;
445da0c48c4Sopenharmony_ci	    }
446da0c48c4Sopenharmony_ci	  /* Undo the 'for' statement increment.  */
447da0c48c4Sopenharmony_ci	  op = found - 1;
448da0c48c4Sopenharmony_ci	  break;
449da0c48c4Sopenharmony_ci	case DW_OP_nop:
450da0c48c4Sopenharmony_ci	  break;
451da0c48c4Sopenharmony_ci	/* DW_OP_* not listed in libgcc/unwind-dw2.c execute_stack_op:  */
452da0c48c4Sopenharmony_ci	case DW_OP_call_frame_cfa:;
453da0c48c4Sopenharmony_ci	  // Not used by CFI itself but it is synthetized by elfutils internation.
454da0c48c4Sopenharmony_ci	  Dwarf_Op *cfa_ops;
455da0c48c4Sopenharmony_ci	  size_t cfa_nops;
456da0c48c4Sopenharmony_ci	  Dwarf_Addr cfa;
457da0c48c4Sopenharmony_ci	  if (frame == NULL
458da0c48c4Sopenharmony_ci	      || dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0
459da0c48c4Sopenharmony_ci	      || ! expr_eval (state, NULL, cfa_ops, cfa_nops, &cfa, bias)
460da0c48c4Sopenharmony_ci	      || ! push (cfa))
461da0c48c4Sopenharmony_ci	    {
462da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_LIBDW);
463da0c48c4Sopenharmony_ci	      free (stack.addrs);
464da0c48c4Sopenharmony_ci	      return false;
465da0c48c4Sopenharmony_ci	    }
466da0c48c4Sopenharmony_ci	  is_location = true;
467da0c48c4Sopenharmony_ci	  break;
468da0c48c4Sopenharmony_ci	case DW_OP_stack_value:
469da0c48c4Sopenharmony_ci	  // Not used by CFI itself but it is synthetized by elfutils internation.
470da0c48c4Sopenharmony_ci	  is_location = false;
471da0c48c4Sopenharmony_ci	  break;
472da0c48c4Sopenharmony_ci	default:
473da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
474da0c48c4Sopenharmony_ci	  return false;
475da0c48c4Sopenharmony_ci      }
476da0c48c4Sopenharmony_ci    }
477da0c48c4Sopenharmony_ci  if (! pop (result))
478da0c48c4Sopenharmony_ci    {
479da0c48c4Sopenharmony_ci      free (stack.addrs);
480da0c48c4Sopenharmony_ci      return false;
481da0c48c4Sopenharmony_ci    }
482da0c48c4Sopenharmony_ci  free (stack.addrs);
483da0c48c4Sopenharmony_ci  if (is_location)
484da0c48c4Sopenharmony_ci    {
485da0c48c4Sopenharmony_ci      if (process->callbacks->memory_read == NULL)
486da0c48c4Sopenharmony_ci	{
487da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT);
488da0c48c4Sopenharmony_ci	  return false;
489da0c48c4Sopenharmony_ci	}
490da0c48c4Sopenharmony_ci      if (! process->callbacks->memory_read (process->dwfl, *result, result,
491da0c48c4Sopenharmony_ci					     process->callbacks_arg))
492da0c48c4Sopenharmony_ci	return false;
493da0c48c4Sopenharmony_ci    }
494da0c48c4Sopenharmony_ci  return true;
495da0c48c4Sopenharmony_ci#undef push
496da0c48c4Sopenharmony_ci#undef pop
497da0c48c4Sopenharmony_ci}
498da0c48c4Sopenharmony_ci
499da0c48c4Sopenharmony_cistatic Dwfl_Frame *
500da0c48c4Sopenharmony_cinew_unwound (Dwfl_Frame *state)
501da0c48c4Sopenharmony_ci{
502da0c48c4Sopenharmony_ci  assert (state->unwound == NULL);
503da0c48c4Sopenharmony_ci  Dwfl_Thread *thread = state->thread;
504da0c48c4Sopenharmony_ci  Dwfl_Process *process = thread->process;
505da0c48c4Sopenharmony_ci  Ebl *ebl = process->ebl;
506da0c48c4Sopenharmony_ci  size_t nregs = ebl_frame_nregs (ebl);
507da0c48c4Sopenharmony_ci  assert (nregs > 0);
508da0c48c4Sopenharmony_ci  Dwfl_Frame *unwound;
509da0c48c4Sopenharmony_ci  unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
510da0c48c4Sopenharmony_ci  if (unlikely (unwound == NULL))
511da0c48c4Sopenharmony_ci    return NULL;
512da0c48c4Sopenharmony_ci  state->unwound = unwound;
513da0c48c4Sopenharmony_ci  unwound->thread = thread;
514da0c48c4Sopenharmony_ci  unwound->unwound = NULL;
515da0c48c4Sopenharmony_ci  unwound->signal_frame = false;
516da0c48c4Sopenharmony_ci  unwound->initial_frame = false;
517da0c48c4Sopenharmony_ci  unwound->pc_state = DWFL_FRAME_STATE_ERROR;
518da0c48c4Sopenharmony_ci  memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
519da0c48c4Sopenharmony_ci  return unwound;
520da0c48c4Sopenharmony_ci}
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ci/* The logic is to call __libdwfl_seterrno for any CFI bytecode interpretation
523da0c48c4Sopenharmony_ci   error so one can easily catch the problem with a debugger.  Still there are
524da0c48c4Sopenharmony_ci   archs with invalid CFI for some registers where the registers are never used
525da0c48c4Sopenharmony_ci   later.  Therefore we continue unwinding leaving the registers undefined.  */
526da0c48c4Sopenharmony_ci
527da0c48c4Sopenharmony_cistatic void
528da0c48c4Sopenharmony_cihandle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
529da0c48c4Sopenharmony_ci{
530da0c48c4Sopenharmony_ci  Dwarf_Frame *frame;
531da0c48c4Sopenharmony_ci  if (INTUSE(dwarf_cfi_addrframe) (cfi, pc, &frame) != 0)
532da0c48c4Sopenharmony_ci    {
533da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_LIBDW);
534da0c48c4Sopenharmony_ci      return;
535da0c48c4Sopenharmony_ci    }
536da0c48c4Sopenharmony_ci
537da0c48c4Sopenharmony_ci  Dwfl_Frame *unwound = new_unwound (state);
538da0c48c4Sopenharmony_ci  if (unwound == NULL)
539da0c48c4Sopenharmony_ci    {
540da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_NOMEM);
541da0c48c4Sopenharmony_ci      return;
542da0c48c4Sopenharmony_ci    }
543da0c48c4Sopenharmony_ci
544da0c48c4Sopenharmony_ci  unwound->signal_frame = frame->fde->cie->signal_frame;
545da0c48c4Sopenharmony_ci  Dwfl_Thread *thread = state->thread;
546da0c48c4Sopenharmony_ci  Dwfl_Process *process = thread->process;
547da0c48c4Sopenharmony_ci  Ebl *ebl = process->ebl;
548da0c48c4Sopenharmony_ci  size_t nregs = ebl_frame_nregs (ebl);
549da0c48c4Sopenharmony_ci  assert (nregs > 0);
550da0c48c4Sopenharmony_ci
551da0c48c4Sopenharmony_ci  /* The return register is special for setting the unwound->pc_state.  */
552da0c48c4Sopenharmony_ci  unsigned ra = frame->fde->cie->return_address_register;
553da0c48c4Sopenharmony_ci  bool ra_set = false;
554da0c48c4Sopenharmony_ci  if (! ebl_dwarf_to_regno (ebl, &ra))
555da0c48c4Sopenharmony_ci    {
556da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
557da0c48c4Sopenharmony_ci      return;
558da0c48c4Sopenharmony_ci    }
559da0c48c4Sopenharmony_ci
560da0c48c4Sopenharmony_ci  for (unsigned regno = 0; regno < nregs; regno++)
561da0c48c4Sopenharmony_ci    {
562da0c48c4Sopenharmony_ci      Dwarf_Op reg_ops_mem[3], *reg_ops;
563da0c48c4Sopenharmony_ci      size_t reg_nops;
564da0c48c4Sopenharmony_ci      if (dwarf_frame_register (frame, regno, reg_ops_mem, &reg_ops,
565da0c48c4Sopenharmony_ci				&reg_nops) != 0)
566da0c48c4Sopenharmony_ci	{
567da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_LIBDW);
568da0c48c4Sopenharmony_ci	  continue;
569da0c48c4Sopenharmony_ci	}
570da0c48c4Sopenharmony_ci      Dwarf_Addr regval;
571da0c48c4Sopenharmony_ci      if (reg_nops == 0)
572da0c48c4Sopenharmony_ci	{
573da0c48c4Sopenharmony_ci	  if (reg_ops == reg_ops_mem)
574da0c48c4Sopenharmony_ci	    {
575da0c48c4Sopenharmony_ci	      /* REGNO is undefined.  */
576da0c48c4Sopenharmony_ci	      if (regno == ra)
577da0c48c4Sopenharmony_ci		unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
578da0c48c4Sopenharmony_ci	      continue;
579da0c48c4Sopenharmony_ci	    }
580da0c48c4Sopenharmony_ci	  else if (reg_ops == NULL)
581da0c48c4Sopenharmony_ci	    {
582da0c48c4Sopenharmony_ci	      /* REGNO is same-value.  */
583da0c48c4Sopenharmony_ci	      if (INTUSE (dwfl_frame_reg) (state, regno, &regval) != 0)
584da0c48c4Sopenharmony_ci		continue;
585da0c48c4Sopenharmony_ci	    }
586da0c48c4Sopenharmony_ci	  else
587da0c48c4Sopenharmony_ci	    {
588da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
589da0c48c4Sopenharmony_ci	      continue;
590da0c48c4Sopenharmony_ci	    }
591da0c48c4Sopenharmony_ci	}
592da0c48c4Sopenharmony_ci      else if (! expr_eval (state, frame, reg_ops, reg_nops, &regval, bias))
593da0c48c4Sopenharmony_ci	{
594da0c48c4Sopenharmony_ci	  /* PPC32 vDSO has various invalid operations, ignore them.  The
595da0c48c4Sopenharmony_ci	     register will look as unset causing an error later, if used.
596da0c48c4Sopenharmony_ci	     But PPC32 does not use such registers.  */
597da0c48c4Sopenharmony_ci	  continue;
598da0c48c4Sopenharmony_ci	}
599da0c48c4Sopenharmony_ci
600da0c48c4Sopenharmony_ci      /* Some architectures encode some extra info in the return address.  */
601da0c48c4Sopenharmony_ci      if (regno == frame->fde->cie->return_address_register)
602da0c48c4Sopenharmony_ci	regval &= ebl_func_addr_mask (ebl);
603da0c48c4Sopenharmony_ci
604da0c48c4Sopenharmony_ci      /* This is another strange PPC[64] case.  There are two
605da0c48c4Sopenharmony_ci	 registers numbers that can represent the same DWARF return
606da0c48c4Sopenharmony_ci	 register number.  We only want one to actually set the return
607da0c48c4Sopenharmony_ci	 register value.  But we always want to override the value if
608da0c48c4Sopenharmony_ci	 the register is the actual CIE return address register.  */
609da0c48c4Sopenharmony_ci      if (ra_set && regno != frame->fde->cie->return_address_register)
610da0c48c4Sopenharmony_ci	{
611da0c48c4Sopenharmony_ci	  unsigned r = regno;
612da0c48c4Sopenharmony_ci	  if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
613da0c48c4Sopenharmony_ci	    continue;
614da0c48c4Sopenharmony_ci	}
615da0c48c4Sopenharmony_ci
616da0c48c4Sopenharmony_ci      if (! __libdwfl_frame_reg_set (unwound, regno, regval))
617da0c48c4Sopenharmony_ci	{
618da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
619da0c48c4Sopenharmony_ci	  continue;
620da0c48c4Sopenharmony_ci	}
621da0c48c4Sopenharmony_ci      else if (! ra_set)
622da0c48c4Sopenharmony_ci	{
623da0c48c4Sopenharmony_ci	  unsigned r = regno;
624da0c48c4Sopenharmony_ci          if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
625da0c48c4Sopenharmony_ci	    ra_set = true;
626da0c48c4Sopenharmony_ci	}
627da0c48c4Sopenharmony_ci    }
628da0c48c4Sopenharmony_ci  if (unwound->pc_state == DWFL_FRAME_STATE_ERROR)
629da0c48c4Sopenharmony_ci    {
630da0c48c4Sopenharmony_ci      int res = INTUSE (dwfl_frame_reg) (unwound,
631da0c48c4Sopenharmony_ci          frame->fde->cie->return_address_register,
632da0c48c4Sopenharmony_ci          &unwound->pc);
633da0c48c4Sopenharmony_ci      if (res == 0)
634da0c48c4Sopenharmony_ci	{
635da0c48c4Sopenharmony_ci	  /* PPC32 __libc_start_main properly CFI-unwinds PC as zero.
636da0c48c4Sopenharmony_ci	     Currently none of the archs supported for unwinding have
637da0c48c4Sopenharmony_ci	     zero as a valid PC.  */
638da0c48c4Sopenharmony_ci	  if (unwound->pc == 0)
639da0c48c4Sopenharmony_ci	    unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
640da0c48c4Sopenharmony_ci	  else
641da0c48c4Sopenharmony_ci	    {
642da0c48c4Sopenharmony_ci	      unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
643da0c48c4Sopenharmony_ci	      /* In SPARC the return address register actually contains
644da0c48c4Sopenharmony_ci		 the address of the call instruction instead of the return
645da0c48c4Sopenharmony_ci		 address.  Therefore we add here an offset defined by the
646da0c48c4Sopenharmony_ci		 backend.  Most likely 0.  */
647da0c48c4Sopenharmony_ci	      unwound->pc += ebl_ra_offset (ebl);
648da0c48c4Sopenharmony_ci	    }
649da0c48c4Sopenharmony_ci	}
650da0c48c4Sopenharmony_ci      else
651da0c48c4Sopenharmony_ci	{
652da0c48c4Sopenharmony_ci	  /* We couldn't set the return register, either it was bogus,
653da0c48c4Sopenharmony_ci	     or the return pc is undefined, maybe end of call stack.  */
654da0c48c4Sopenharmony_ci	  unsigned pcreg = frame->fde->cie->return_address_register;
655da0c48c4Sopenharmony_ci	  if (! ebl_dwarf_to_regno (ebl, &pcreg)
656da0c48c4Sopenharmony_ci	      || pcreg >= ebl_frame_nregs (ebl))
657da0c48c4Sopenharmony_ci	    __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
658da0c48c4Sopenharmony_ci	  else
659da0c48c4Sopenharmony_ci	    unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
660da0c48c4Sopenharmony_ci	}
661da0c48c4Sopenharmony_ci    }
662da0c48c4Sopenharmony_ci  free (frame);
663da0c48c4Sopenharmony_ci}
664da0c48c4Sopenharmony_ci
665da0c48c4Sopenharmony_cistatic bool
666da0c48c4Sopenharmony_cisetfunc (int firstreg, unsigned nregs, const Dwarf_Word *regs, void *arg)
667da0c48c4Sopenharmony_ci{
668da0c48c4Sopenharmony_ci  Dwfl_Frame *state = arg;
669da0c48c4Sopenharmony_ci  Dwfl_Frame *unwound = state->unwound;
670da0c48c4Sopenharmony_ci  if (firstreg < 0)
671da0c48c4Sopenharmony_ci    {
672da0c48c4Sopenharmony_ci      assert (firstreg == -1);
673da0c48c4Sopenharmony_ci      assert (nregs == 1);
674da0c48c4Sopenharmony_ci      assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
675da0c48c4Sopenharmony_ci      unwound->pc = *regs;
676da0c48c4Sopenharmony_ci      unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
677da0c48c4Sopenharmony_ci      return true;
678da0c48c4Sopenharmony_ci    }
679da0c48c4Sopenharmony_ci  while (nregs--)
680da0c48c4Sopenharmony_ci    if (! __libdwfl_frame_reg_set (unwound, firstreg++, *regs++))
681da0c48c4Sopenharmony_ci      return false;
682da0c48c4Sopenharmony_ci  return true;
683da0c48c4Sopenharmony_ci}
684da0c48c4Sopenharmony_ci
685da0c48c4Sopenharmony_cistatic bool
686da0c48c4Sopenharmony_cigetfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg)
687da0c48c4Sopenharmony_ci{
688da0c48c4Sopenharmony_ci  Dwfl_Frame *state = arg;
689da0c48c4Sopenharmony_ci  assert (firstreg >= 0);
690da0c48c4Sopenharmony_ci  while (nregs--)
691da0c48c4Sopenharmony_ci    if (INTUSE (dwfl_frame_reg) (state, firstreg++, regs++) != 0)
692da0c48c4Sopenharmony_ci      return false;
693da0c48c4Sopenharmony_ci  return true;
694da0c48c4Sopenharmony_ci}
695da0c48c4Sopenharmony_ci
696da0c48c4Sopenharmony_cistatic bool
697da0c48c4Sopenharmony_cireadfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg)
698da0c48c4Sopenharmony_ci{
699da0c48c4Sopenharmony_ci  Dwfl_Frame *state = arg;
700da0c48c4Sopenharmony_ci  Dwfl_Thread *thread = state->thread;
701da0c48c4Sopenharmony_ci  Dwfl_Process *process = thread->process;
702da0c48c4Sopenharmony_ci  return process->callbacks->memory_read (process->dwfl, addr, datap,
703da0c48c4Sopenharmony_ci					  process->callbacks_arg);
704da0c48c4Sopenharmony_ci}
705da0c48c4Sopenharmony_ci
706da0c48c4Sopenharmony_civoid
707da0c48c4Sopenharmony_ciinternal_function
708da0c48c4Sopenharmony_ci__libdwfl_frame_unwind (Dwfl_Frame *state)
709da0c48c4Sopenharmony_ci{
710da0c48c4Sopenharmony_ci  if (state->unwound)
711da0c48c4Sopenharmony_ci    return;
712da0c48c4Sopenharmony_ci  /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE
713da0c48c4Sopenharmony_ci     which would deadlock us.  */
714da0c48c4Sopenharmony_ci  Dwarf_Addr pc;
715da0c48c4Sopenharmony_ci  bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL);
716da0c48c4Sopenharmony_ci  if (!ok)
717da0c48c4Sopenharmony_ci    return;
718da0c48c4Sopenharmony_ci  /* Check whether this is the initial frame or a signal frame.
719da0c48c4Sopenharmony_ci     Then we need to unwind from the original, unadjusted PC.  */
720da0c48c4Sopenharmony_ci  if (! state->initial_frame && ! state->signal_frame)
721da0c48c4Sopenharmony_ci    pc--;
722da0c48c4Sopenharmony_ci  Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc);
723da0c48c4Sopenharmony_ci  if (mod == NULL)
724da0c48c4Sopenharmony_ci    __libdwfl_seterrno (DWFL_E_NO_DWARF);
725da0c48c4Sopenharmony_ci  else
726da0c48c4Sopenharmony_ci    {
727da0c48c4Sopenharmony_ci      Dwarf_Addr bias;
728da0c48c4Sopenharmony_ci      Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias);
729da0c48c4Sopenharmony_ci      if (cfi_eh)
730da0c48c4Sopenharmony_ci	{
731da0c48c4Sopenharmony_ci	  handle_cfi (state, pc - bias, cfi_eh, bias);
732da0c48c4Sopenharmony_ci	  if (state->unwound)
733da0c48c4Sopenharmony_ci	    return;
734da0c48c4Sopenharmony_ci	}
735da0c48c4Sopenharmony_ci      Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias);
736da0c48c4Sopenharmony_ci      if (cfi_dwarf)
737da0c48c4Sopenharmony_ci	{
738da0c48c4Sopenharmony_ci	  handle_cfi (state, pc - bias, cfi_dwarf, bias);
739da0c48c4Sopenharmony_ci	  if (state->unwound)
740da0c48c4Sopenharmony_ci	    return;
741da0c48c4Sopenharmony_ci	}
742da0c48c4Sopenharmony_ci    }
743da0c48c4Sopenharmony_ci  assert (state->unwound == NULL);
744da0c48c4Sopenharmony_ci  Dwfl_Thread *thread = state->thread;
745da0c48c4Sopenharmony_ci  Dwfl_Process *process = thread->process;
746da0c48c4Sopenharmony_ci  Ebl *ebl = process->ebl;
747da0c48c4Sopenharmony_ci  if (new_unwound (state) == NULL)
748da0c48c4Sopenharmony_ci    {
749da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_NOMEM);
750da0c48c4Sopenharmony_ci      return;
751da0c48c4Sopenharmony_ci    }
752da0c48c4Sopenharmony_ci  state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
753da0c48c4Sopenharmony_ci  // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield.
754da0c48c4Sopenharmony_ci  bool signal_frame = false;
755da0c48c4Sopenharmony_ci  if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame))
756da0c48c4Sopenharmony_ci    {
757da0c48c4Sopenharmony_ci      // Discard the unwind attempt.  During next __libdwfl_frame_unwind call
758da0c48c4Sopenharmony_ci      // we may have for example the appropriate Dwfl_Module already mapped.
759da0c48c4Sopenharmony_ci      assert (state->unwound->unwound == NULL);
760da0c48c4Sopenharmony_ci      free (state->unwound);
761da0c48c4Sopenharmony_ci      state->unwound = NULL;
762da0c48c4Sopenharmony_ci      // __libdwfl_seterrno has been called above.
763da0c48c4Sopenharmony_ci      return;
764da0c48c4Sopenharmony_ci    }
765da0c48c4Sopenharmony_ci  assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
766da0c48c4Sopenharmony_ci  state->unwound->signal_frame = signal_frame;
767da0c48c4Sopenharmony_ci}
768