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, ®no)) 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, ®no)) 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, ®_ops, 565da0c48c4Sopenharmony_ci ®_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, ®val) != 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, ®val, 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