1d4e76214Sopenharmony_ci/* libunwind - a platform-independent unwind library 2d4e76214Sopenharmony_ci Copyright (C) 2008 CodeSourcery 3d4e76214Sopenharmony_ci Copyright 2011 Linaro Limited 4d4e76214Sopenharmony_ci Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com> 5d4e76214Sopenharmony_ci 6d4e76214Sopenharmony_ciThis file is part of libunwind. 7d4e76214Sopenharmony_ci 8d4e76214Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining 9d4e76214Sopenharmony_cia copy of this software and associated documentation files (the 10d4e76214Sopenharmony_ci"Software"), to deal in the Software without restriction, including 11d4e76214Sopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish, 12d4e76214Sopenharmony_cidistribute, sublicense, and/or sell copies of the Software, and to 13d4e76214Sopenharmony_cipermit persons to whom the Software is furnished to do so, subject to 14d4e76214Sopenharmony_cithe following conditions: 15d4e76214Sopenharmony_ci 16d4e76214Sopenharmony_ciThe above copyright notice and this permission notice shall be 17d4e76214Sopenharmony_ciincluded in all copies or substantial portions of the Software. 18d4e76214Sopenharmony_ci 19d4e76214Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20d4e76214Sopenharmony_ciEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d4e76214Sopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22d4e76214Sopenharmony_ciNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23d4e76214Sopenharmony_ciLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24d4e76214Sopenharmony_ciOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25d4e76214Sopenharmony_ciWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 26d4e76214Sopenharmony_ci 27d4e76214Sopenharmony_ci#include "unwind_i.h" 28d4e76214Sopenharmony_ci#include "offsets.h" 29d4e76214Sopenharmony_ci#include "ex_tables.h" 30d4e76214Sopenharmony_ci 31d4e76214Sopenharmony_ci#include <signal.h> 32d4e76214Sopenharmony_ci 33d4e76214Sopenharmony_ci#define arm_exidx_step UNW_OBJ(arm_exidx_step) 34d4e76214Sopenharmony_ci 35d4e76214Sopenharmony_cistatic inline int 36d4e76214Sopenharmony_ciarm_exidx_step (struct cursor *c) 37d4e76214Sopenharmony_ci{ 38d4e76214Sopenharmony_ci unw_word_t old_ip, old_cfa; 39d4e76214Sopenharmony_ci uint8_t buf[32]; 40d4e76214Sopenharmony_ci int ret; 41d4e76214Sopenharmony_ci 42d4e76214Sopenharmony_ci old_ip = c->dwarf.ip; 43d4e76214Sopenharmony_ci old_cfa = c->dwarf.cfa; 44d4e76214Sopenharmony_ci 45d4e76214Sopenharmony_ci /* mark PC unsaved */ 46d4e76214Sopenharmony_ci c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC; 47d4e76214Sopenharmony_ci unw_word_t ip = c->dwarf.ip; 48d4e76214Sopenharmony_ci if (c->dwarf.use_prev_instr) 49d4e76214Sopenharmony_ci /* The least bit denotes thumb/arm mode, clear it. */ 50d4e76214Sopenharmony_ci ip = (ip & ~(unw_word_t)0x1) - 1; 51d4e76214Sopenharmony_ci 52d4e76214Sopenharmony_ci /* check dynamic info first --- it overrides everything else */ 53d4e76214Sopenharmony_ci ret = unwi_find_dynamic_proc_info (c->dwarf.as, ip, &c->dwarf.pi, 1, 54d4e76214Sopenharmony_ci c->dwarf.as_arg); 55d4e76214Sopenharmony_ci if (ret == -UNW_ENOINFO) 56d4e76214Sopenharmony_ci { 57d4e76214Sopenharmony_ci if ((ret = tdep_find_proc_info (&c->dwarf, ip, 1)) < 0) 58d4e76214Sopenharmony_ci return ret; 59d4e76214Sopenharmony_ci } 60d4e76214Sopenharmony_ci 61d4e76214Sopenharmony_ci if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX) 62d4e76214Sopenharmony_ci return -UNW_ENOINFO; 63d4e76214Sopenharmony_ci 64d4e76214Sopenharmony_ci ret = arm_exidx_extract (&c->dwarf, buf); 65d4e76214Sopenharmony_ci if (ret == -UNW_ESTOPUNWIND) 66d4e76214Sopenharmony_ci return 0; 67d4e76214Sopenharmony_ci else if (ret < 0) 68d4e76214Sopenharmony_ci return ret; 69d4e76214Sopenharmony_ci 70d4e76214Sopenharmony_ci ret = arm_exidx_decode (buf, ret, &c->dwarf); 71d4e76214Sopenharmony_ci if (ret < 0) 72d4e76214Sopenharmony_ci return ret; 73d4e76214Sopenharmony_ci 74d4e76214Sopenharmony_ci if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa) 75d4e76214Sopenharmony_ci { 76d4e76214Sopenharmony_ci Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n", 77d4e76214Sopenharmony_ci __FUNCTION__, (long) c->dwarf.ip); 78d4e76214Sopenharmony_ci return -UNW_EBADFRAME; 79d4e76214Sopenharmony_ci } 80d4e76214Sopenharmony_ci 81d4e76214Sopenharmony_ci c->dwarf.pi_valid = 0; 82d4e76214Sopenharmony_ci 83d4e76214Sopenharmony_ci return (c->dwarf.ip == 0) ? 0 : 1; 84d4e76214Sopenharmony_ci} 85d4e76214Sopenharmony_ci 86d4e76214Sopenharmony_ciint 87d4e76214Sopenharmony_ciunw_step (unw_cursor_t *cursor) 88d4e76214Sopenharmony_ci{ 89d4e76214Sopenharmony_ci struct cursor *c = (struct cursor *) cursor; 90d4e76214Sopenharmony_ci int ret = -UNW_EUNSPEC; 91d4e76214Sopenharmony_ci 92d4e76214Sopenharmony_ci Debug (1, "(cursor=%p)\n", c); 93d4e76214Sopenharmony_ci 94d4e76214Sopenharmony_ci /* Check if this is a signal frame. */ 95d4e76214Sopenharmony_ci if (unw_is_signal_frame (cursor) > 0) 96d4e76214Sopenharmony_ci return arm_handle_signal_frame (cursor); 97d4e76214Sopenharmony_ci 98d4e76214Sopenharmony_ci#ifdef CONFIG_DEBUG_FRAME 99d4e76214Sopenharmony_ci /* First, try DWARF-based unwinding. */ 100d4e76214Sopenharmony_ci if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF)) 101d4e76214Sopenharmony_ci { 102d4e76214Sopenharmony_ci ret = dwarf_step (&c->dwarf); 103d4e76214Sopenharmony_ci Debug(1, "dwarf_step()=%d\n", ret); 104d4e76214Sopenharmony_ci 105d4e76214Sopenharmony_ci if (likely (ret > 0)) 106d4e76214Sopenharmony_ci return 1; 107d4e76214Sopenharmony_ci else if (unlikely (ret == -UNW_ESTOPUNWIND)) 108d4e76214Sopenharmony_ci return ret; 109d4e76214Sopenharmony_ci 110d4e76214Sopenharmony_ci if (ret < 0 && ret != -UNW_ENOINFO) 111d4e76214Sopenharmony_ci { 112d4e76214Sopenharmony_ci Debug (2, "returning %d\n", ret); 113d4e76214Sopenharmony_ci return ret; 114d4e76214Sopenharmony_ci } 115d4e76214Sopenharmony_ci } 116d4e76214Sopenharmony_ci#endif /* CONFIG_DEBUG_FRAME */ 117d4e76214Sopenharmony_ci 118d4e76214Sopenharmony_ci /* Next, try extbl-based unwinding. */ 119d4e76214Sopenharmony_ci if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX)) 120d4e76214Sopenharmony_ci { 121d4e76214Sopenharmony_ci Debug (13, "%s(ret=%d), trying extbl\n", 122d4e76214Sopenharmony_ci UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() failed " : "", 123d4e76214Sopenharmony_ci ret); 124d4e76214Sopenharmony_ci ret = arm_exidx_step (c); 125d4e76214Sopenharmony_ci if (ret > 0) 126d4e76214Sopenharmony_ci return 1; 127d4e76214Sopenharmony_ci if (ret == -UNW_ESTOPUNWIND || ret == 0) 128d4e76214Sopenharmony_ci return ret; 129d4e76214Sopenharmony_ci } 130d4e76214Sopenharmony_ci 131d4e76214Sopenharmony_ci /* Fall back on APCS frame parsing. 132d4e76214Sopenharmony_ci Note: This won't work in case the ARM EABI is used. */ 133d4e76214Sopenharmony_ci#ifdef __FreeBSD__ 134d4e76214Sopenharmony_ci if (0) 135d4e76214Sopenharmony_ci#else 136d4e76214Sopenharmony_ci if (unlikely (ret < 0)) 137d4e76214Sopenharmony_ci#endif 138d4e76214Sopenharmony_ci { 139d4e76214Sopenharmony_ci if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME)) 140d4e76214Sopenharmony_ci { 141d4e76214Sopenharmony_ci Debug (13, "%s%s%s%s(ret=%d), trying frame-chain\n", 142d4e76214Sopenharmony_ci UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() " : "", 143d4e76214Sopenharmony_ci (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) && UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "and " : "", 144d4e76214Sopenharmony_ci UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX) ? "arm_exidx_step() " : "", 145d4e76214Sopenharmony_ci (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) || UNW_TRY_METHOD(UNW_ARM_METHOD_EXIDX)) ? "failed " : "", 146d4e76214Sopenharmony_ci ret); 147d4e76214Sopenharmony_ci ret = UNW_ESUCCESS; 148d4e76214Sopenharmony_ci /* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */ 149d4e76214Sopenharmony_ci unw_word_t instr, i; 150d4e76214Sopenharmony_ci dwarf_loc_t ip_loc, fp_loc; 151d4e76214Sopenharmony_ci unw_word_t frame; 152d4e76214Sopenharmony_ci /* Mark all registers unsaved, since we don't know where 153d4e76214Sopenharmony_ci they are saved (if at all), except for the EBP and 154d4e76214Sopenharmony_ci EIP. */ 155d4e76214Sopenharmony_ci if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R11], &frame) < 0) 156d4e76214Sopenharmony_ci { 157d4e76214Sopenharmony_ci return 0; 158d4e76214Sopenharmony_ci } 159d4e76214Sopenharmony_ci for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) { 160d4e76214Sopenharmony_ci c->dwarf.loc[i] = DWARF_NULL_LOC; 161d4e76214Sopenharmony_ci } 162d4e76214Sopenharmony_ci if (frame) 163d4e76214Sopenharmony_ci { 164d4e76214Sopenharmony_ci if (dwarf_get(&c->dwarf, DWARF_LOC(frame, 0), &instr) < 0) 165d4e76214Sopenharmony_ci { 166d4e76214Sopenharmony_ci return 0; 167d4e76214Sopenharmony_ci } 168d4e76214Sopenharmony_ci instr -= 8; 169d4e76214Sopenharmony_ci if (dwarf_get(&c->dwarf, DWARF_LOC(instr, 0), &instr) < 0) 170d4e76214Sopenharmony_ci { 171d4e76214Sopenharmony_ci return 0; 172d4e76214Sopenharmony_ci } 173d4e76214Sopenharmony_ci if ((instr & 0xFFFFD800) == 0xE92DD800) 174d4e76214Sopenharmony_ci { 175d4e76214Sopenharmony_ci /* Standard APCS frame. */ 176d4e76214Sopenharmony_ci ip_loc = DWARF_LOC(frame - 4, 0); 177d4e76214Sopenharmony_ci fp_loc = DWARF_LOC(frame - 12, 0); 178d4e76214Sopenharmony_ci } 179d4e76214Sopenharmony_ci else 180d4e76214Sopenharmony_ci { 181d4e76214Sopenharmony_ci /* Codesourcery optimized normal frame. */ 182d4e76214Sopenharmony_ci ip_loc = DWARF_LOC(frame, 0); 183d4e76214Sopenharmony_ci fp_loc = DWARF_LOC(frame - 4, 0); 184d4e76214Sopenharmony_ci } 185d4e76214Sopenharmony_ci if (dwarf_get(&c->dwarf, ip_loc, &c->dwarf.ip) < 0) 186d4e76214Sopenharmony_ci { 187d4e76214Sopenharmony_ci return 0; 188d4e76214Sopenharmony_ci } 189d4e76214Sopenharmony_ci c->dwarf.loc[UNW_ARM_R12] = ip_loc; 190d4e76214Sopenharmony_ci c->dwarf.loc[UNW_ARM_R11] = fp_loc; 191d4e76214Sopenharmony_ci c->dwarf.pi_valid = 0; 192d4e76214Sopenharmony_ci Debug(15, "ip=%x\n", c->dwarf.ip); 193d4e76214Sopenharmony_ci } 194d4e76214Sopenharmony_ci else 195d4e76214Sopenharmony_ci { 196d4e76214Sopenharmony_ci ret = -UNW_ENOINFO; 197d4e76214Sopenharmony_ci } 198d4e76214Sopenharmony_ci } 199d4e76214Sopenharmony_ci } 200d4e76214Sopenharmony_ci return ret == -UNW_ENOINFO ? 0 : ret; 201d4e76214Sopenharmony_ci} 202