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