1d4e76214Sopenharmony_ci/* libunwind - a platform-independent unwind library 2d4e76214Sopenharmony_ci Copyright (C) 2015 Imagination Technologies Limited 3d4e76214Sopenharmony_ci Copyright (C) 2008 CodeSourcery 4d4e76214Sopenharmony_ci 5d4e76214Sopenharmony_ciThis file is part of libunwind. 6d4e76214Sopenharmony_ci 7d4e76214Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining 8d4e76214Sopenharmony_cia copy of this software and associated documentation files (the 9d4e76214Sopenharmony_ci"Software"), to deal in the Software without restriction, including 10d4e76214Sopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish, 11d4e76214Sopenharmony_cidistribute, sublicense, and/or sell copies of the Software, and to 12d4e76214Sopenharmony_cipermit persons to whom the Software is furnished to do so, subject to 13d4e76214Sopenharmony_cithe following conditions: 14d4e76214Sopenharmony_ci 15d4e76214Sopenharmony_ciThe above copyright notice and this permission notice shall be 16d4e76214Sopenharmony_ciincluded in all copies or substantial portions of the Software. 17d4e76214Sopenharmony_ci 18d4e76214Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19d4e76214Sopenharmony_ciEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20d4e76214Sopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21d4e76214Sopenharmony_ciNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22d4e76214Sopenharmony_ciLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23d4e76214Sopenharmony_ciOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24d4e76214Sopenharmony_ciWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25d4e76214Sopenharmony_ci 26d4e76214Sopenharmony_ci#include "unwind_i.h" 27d4e76214Sopenharmony_ci#include "offsets.h" 28d4e76214Sopenharmony_ci 29d4e76214Sopenharmony_cistatic int 30d4e76214Sopenharmony_cimips_handle_signal_frame (unw_cursor_t *cursor) 31d4e76214Sopenharmony_ci{ 32d4e76214Sopenharmony_ci struct cursor *c = (struct cursor *) cursor; 33d4e76214Sopenharmony_ci unw_word_t sc_addr, sp_addr = c->dwarf.cfa; 34d4e76214Sopenharmony_ci unw_word_t ra, fp; 35d4e76214Sopenharmony_ci int ret; 36d4e76214Sopenharmony_ci 37d4e76214Sopenharmony_ci switch (unw_is_signal_frame (cursor)) { 38d4e76214Sopenharmony_ci case 1: 39d4e76214Sopenharmony_ci sc_addr = sp_addr + LINUX_SF_TRAMP_SIZE + sizeof (siginfo_t) + 40d4e76214Sopenharmony_ci LINUX_UC_MCONTEXT_OFF; 41d4e76214Sopenharmony_ci break; 42d4e76214Sopenharmony_ci case 2: 43d4e76214Sopenharmony_ci sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF; 44d4e76214Sopenharmony_ci break; 45d4e76214Sopenharmony_ci default: 46d4e76214Sopenharmony_ci return -UNW_EUNSPEC; 47d4e76214Sopenharmony_ci } 48d4e76214Sopenharmony_ci 49d4e76214Sopenharmony_ci if (tdep_big_endian(c->dwarf.as)) 50d4e76214Sopenharmony_ci sc_addr += 4; 51d4e76214Sopenharmony_ci 52d4e76214Sopenharmony_ci c->sigcontext_addr = sc_addr; 53d4e76214Sopenharmony_ci 54d4e76214Sopenharmony_ci /* Update the dwarf cursor. */ 55d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0); 56d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0); 57d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0); 58d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0); 59d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0); 60d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0); 61d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0); 62d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0); 63d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0); 64d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0); 65d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0); 66d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R11] = DWARF_LOC (sc_addr + LINUX_SC_R11_OFF, 0); 67d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R12] = DWARF_LOC (sc_addr + LINUX_SC_R12_OFF, 0); 68d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R13] = DWARF_LOC (sc_addr + LINUX_SC_R13_OFF, 0); 69d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R14] = DWARF_LOC (sc_addr + LINUX_SC_R14_OFF, 0); 70d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R15] = DWARF_LOC (sc_addr + LINUX_SC_R15_OFF, 0); 71d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R16] = DWARF_LOC (sc_addr + LINUX_SC_R16_OFF, 0); 72d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R17] = DWARF_LOC (sc_addr + LINUX_SC_R17_OFF, 0); 73d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R18] = DWARF_LOC (sc_addr + LINUX_SC_R18_OFF, 0); 74d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R19] = DWARF_LOC (sc_addr + LINUX_SC_R19_OFF, 0); 75d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R20] = DWARF_LOC (sc_addr + LINUX_SC_R20_OFF, 0); 76d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R21] = DWARF_LOC (sc_addr + LINUX_SC_R21_OFF, 0); 77d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R22] = DWARF_LOC (sc_addr + LINUX_SC_R22_OFF, 0); 78d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R23] = DWARF_LOC (sc_addr + LINUX_SC_R23_OFF, 0); 79d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R24] = DWARF_LOC (sc_addr + LINUX_SC_R24_OFF, 0); 80d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R25] = DWARF_LOC (sc_addr + LINUX_SC_R25_OFF, 0); 81d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R26] = DWARF_LOC (sc_addr + LINUX_SC_R26_OFF, 0); 82d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R27] = DWARF_LOC (sc_addr + LINUX_SC_R27_OFF, 0); 83d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R28] = DWARF_LOC (sc_addr + LINUX_SC_R28_OFF, 0); 84d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R29] = DWARF_LOC (sc_addr + LINUX_SC_R29_OFF, 0); 85d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R30] = DWARF_LOC (sc_addr + LINUX_SC_R30_OFF, 0); 86d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_R31] = DWARF_LOC (sc_addr + LINUX_SC_R31_OFF, 0); 87d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0); 88d4e76214Sopenharmony_ci 89d4e76214Sopenharmony_ci /* Set SP/CFA and PC/IP. */ 90d4e76214Sopenharmony_ci dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R29], &c->dwarf.cfa); 91d4e76214Sopenharmony_ci 92d4e76214Sopenharmony_ci if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_PC_OFF, 0), 93d4e76214Sopenharmony_ci &c->dwarf.ip)) < 0) 94d4e76214Sopenharmony_ci return ret; 95d4e76214Sopenharmony_ci 96d4e76214Sopenharmony_ci if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R31_OFF, 0), 97d4e76214Sopenharmony_ci &ra)) < 0) 98d4e76214Sopenharmony_ci return ret; 99d4e76214Sopenharmony_ci if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R30_OFF, 0), 100d4e76214Sopenharmony_ci &fp)) < 0) 101d4e76214Sopenharmony_ci return ret; 102d4e76214Sopenharmony_ci 103d4e76214Sopenharmony_ci Debug (2, "SH (ip=0x%016llx, ra=0x%016llx, sp=0x%016llx, fp=0x%016llx)\n", 104d4e76214Sopenharmony_ci (unsigned long long)c->dwarf.ip, (unsigned long long)ra, 105d4e76214Sopenharmony_ci (unsigned long long)c->dwarf.cfa, (unsigned long long)fp); 106d4e76214Sopenharmony_ci 107d4e76214Sopenharmony_ci c->dwarf.pi_valid = 0; 108d4e76214Sopenharmony_ci c->dwarf.use_prev_instr = 0; 109d4e76214Sopenharmony_ci 110d4e76214Sopenharmony_ci return 1; 111d4e76214Sopenharmony_ci} 112d4e76214Sopenharmony_ci 113d4e76214Sopenharmony_ci 114d4e76214Sopenharmony_ci 115d4e76214Sopenharmony_cistatic inline 116d4e76214Sopenharmony_ciint is_valid_fp_val(unw_word_t cfa_val, unw_word_t fp_val) 117d4e76214Sopenharmony_ci{ 118d4e76214Sopenharmony_ci return fp_val > 0 && cfa_val > 0 && fp_val >cfa_val && (fp_val - cfa_val < 0x4000); 119d4e76214Sopenharmony_ci} 120d4e76214Sopenharmony_ci 121d4e76214Sopenharmony_cistatic int _step_n64(struct cursor *c) 122d4e76214Sopenharmony_ci{ 123d4e76214Sopenharmony_ci #define FP_REG UNW_MIPS_R30 124d4e76214Sopenharmony_ci #define SP_REG UNW_MIPS_R29 125d4e76214Sopenharmony_ci #define RA_REG UNW_MIPS_R31 126d4e76214Sopenharmony_ci 127d4e76214Sopenharmony_ci //TODO:handle plt entry 128d4e76214Sopenharmony_ci int ret; 129d4e76214Sopenharmony_ci unw_word_t current_fp_val = 0; 130d4e76214Sopenharmony_ci unw_word_t current_ra_val = 0; 131d4e76214Sopenharmony_ci unw_word_t current_sp_val = 0; 132d4e76214Sopenharmony_ci struct dwarf_loc up_fp_loc = DWARF_NULL_LOC; 133d4e76214Sopenharmony_ci struct dwarf_loc up_ra_loc = DWARF_NULL_LOC; 134d4e76214Sopenharmony_ci 135d4e76214Sopenharmony_ci ret = dwarf_get (&c->dwarf, c->dwarf.loc[SP_REG], ¤t_sp_val); 136d4e76214Sopenharmony_ci if (ret < 0) 137d4e76214Sopenharmony_ci { 138d4e76214Sopenharmony_ci Debug (2, "returning %d [SP=0x%lx]\n", ret, 139d4e76214Sopenharmony_ci DWARF_GET_LOC (c->dwarf.loc[FP_REG])); 140d4e76214Sopenharmony_ci return ret; 141d4e76214Sopenharmony_ci } 142d4e76214Sopenharmony_ci ret = dwarf_get (&c->dwarf, c->dwarf.loc[FP_REG], ¤t_fp_val); 143d4e76214Sopenharmony_ci if (ret < 0) 144d4e76214Sopenharmony_ci { 145d4e76214Sopenharmony_ci Debug (2, "returning %d [FP=0x%lx]\n", ret, 146d4e76214Sopenharmony_ci DWARF_GET_LOC (c->dwarf.loc[FP_REG])); 147d4e76214Sopenharmony_ci return ret; 148d4e76214Sopenharmony_ci } 149d4e76214Sopenharmony_ci ret = dwarf_get (&c->dwarf, c->dwarf.loc[RA_REG], ¤t_ra_val); 150d4e76214Sopenharmony_ci if (ret < 0) 151d4e76214Sopenharmony_ci { 152d4e76214Sopenharmony_ci Debug (2, "returning %d [RA=0x%lx]\n", ret, 153d4e76214Sopenharmony_ci DWARF_GET_LOC (c->dwarf.loc[RA_REG])); 154d4e76214Sopenharmony_ci return ret; 155d4e76214Sopenharmony_ci } 156d4e76214Sopenharmony_ci 157d4e76214Sopenharmony_ci Debug(2, "BEGIN GUESSING WITH SP:%p FP:%p CFA:%p at %p, RA:%p\n", 158d4e76214Sopenharmony_ci current_sp_val, current_fp_val, c->dwarf.cfa, 159d4e76214Sopenharmony_ci c->dwarf.ip, current_ra_val 160d4e76214Sopenharmony_ci ); 161d4e76214Sopenharmony_ci 162d4e76214Sopenharmony_ci if (current_fp_val == current_sp_val) { 163d4e76214Sopenharmony_ci // Don't adjust FP 164d4e76214Sopenharmony_ci up_fp_loc = c->dwarf.loc[FP_REG]; 165d4e76214Sopenharmony_ci up_ra_loc = c->dwarf.loc[RA_REG]; 166d4e76214Sopenharmony_ci } else if (is_valid_fp_val(c->dwarf.cfa, current_fp_val)) { 167d4e76214Sopenharmony_ci /* Heuristic to determine incorrect guess. For FP to be a 168d4e76214Sopenharmony_ci valid frame it needs to be above current CFA, but don't 169d4e76214Sopenharmony_ci let it go more than a little. Note that we can't deduce 170d4e76214Sopenharmony_ci anything about new FP (fp1) since it may not be a frame 171d4e76214Sopenharmony_ci pointer in the frame above. Just check we get the value. */ 172d4e76214Sopenharmony_ci up_fp_loc = DWARF_MEM_LOC (c, current_fp_val+16); 173d4e76214Sopenharmony_ci up_ra_loc = DWARF_MEM_LOC (c, current_fp_val+24); 174d4e76214Sopenharmony_ci unw_word_t up_fp_val = 0; 175d4e76214Sopenharmony_ci ret = dwarf_get (&c->dwarf, up_fp_loc, &up_fp_val); 176d4e76214Sopenharmony_ci if (ret > 0 && is_valid_fp_val(current_fp_val, up_fp_val)) { 177d4e76214Sopenharmony_ci c->dwarf.loc[FP_REG] = up_fp_loc; 178d4e76214Sopenharmony_ci } 179d4e76214Sopenharmony_ci } 180d4e76214Sopenharmony_ci 181d4e76214Sopenharmony_ci if (DWARF_IS_NULL_LOC (up_fp_loc)) 182d4e76214Sopenharmony_ci { 183d4e76214Sopenharmony_ci ret = 0; 184d4e76214Sopenharmony_ci Debug (2, "NULL %%fp loc, returning %d\n", ret); 185d4e76214Sopenharmony_ci return ret; 186d4e76214Sopenharmony_ci } 187d4e76214Sopenharmony_ci 188d4e76214Sopenharmony_ci c->dwarf.loc[UNW_MIPS_PC] = c->dwarf.loc[RA_REG]; 189d4e76214Sopenharmony_ci c->dwarf.loc[RA_REG] = up_ra_loc; 190d4e76214Sopenharmony_ci c->dwarf.loc[SP_REG] = up_fp_loc; 191d4e76214Sopenharmony_ci c->dwarf.loc[FP_REG] = up_fp_loc; 192d4e76214Sopenharmony_ci c->dwarf.use_prev_instr = 1; 193d4e76214Sopenharmony_ci 194d4e76214Sopenharmony_ci if (c->dwarf.ip == current_ra_val && current_fp_val == current_sp_val) { 195d4e76214Sopenharmony_ci // Backtrace stopped: frame did not save the PC 196d4e76214Sopenharmony_ci c->dwarf.ip = 0; 197d4e76214Sopenharmony_ci } else { 198d4e76214Sopenharmony_ci c->dwarf.ip = current_ra_val; 199d4e76214Sopenharmony_ci } 200d4e76214Sopenharmony_ci return (c->dwarf.ip == 0) ? 0 : 1; 201d4e76214Sopenharmony_ci} 202d4e76214Sopenharmony_ci 203d4e76214Sopenharmony_ciint 204d4e76214Sopenharmony_ciunw_step (unw_cursor_t *cursor) 205d4e76214Sopenharmony_ci{ 206d4e76214Sopenharmony_ci struct cursor *c = (struct cursor *) cursor; 207d4e76214Sopenharmony_ci int ret; 208d4e76214Sopenharmony_ci 209d4e76214Sopenharmony_ci ret = mips_handle_signal_frame (cursor); 210d4e76214Sopenharmony_ci if (ret < 0) 211d4e76214Sopenharmony_ci /* Not a signal frame, try DWARF-based unwinding. */ 212d4e76214Sopenharmony_ci ret = dwarf_step (&c->dwarf); 213d4e76214Sopenharmony_ci 214d4e76214Sopenharmony_ci if (unlikely (ret == -UNW_ESTOPUNWIND)) 215d4e76214Sopenharmony_ci return ret; 216d4e76214Sopenharmony_ci 217d4e76214Sopenharmony_ci if (unlikely (ret < 0)) 218d4e76214Sopenharmony_ci { 219d4e76214Sopenharmony_ci#if _MIPS_SIM == _ABI64 220d4e76214Sopenharmony_ci return _step_n64(c); 221d4e76214Sopenharmony_ci#else 222d4e76214Sopenharmony_ci return ret; 223d4e76214Sopenharmony_ci#endif 224d4e76214Sopenharmony_ci } 225d4e76214Sopenharmony_ci 226d4e76214Sopenharmony_ci return (c->dwarf.ip == 0) ? 0 : 1; 227d4e76214Sopenharmony_ci} 228