1/* ARM EABI compliant unwinding routines 2 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3 Contributed by Paul Brook 4 5 This file is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by the 7 Free Software Foundation; either version 2, or (at your option) any 8 later version. 9 10 In addition to the permissions in the GNU General Public License, the 11 Free Software Foundation gives you unlimited permission to link the 12 compiled version of this file into combinations with other programs, 13 and to distribute those combinations without any restriction coming 14 from the use of this file. (The General Public License restrictions 15 do apply in other respects; for example, they cover modification of 16 the file, and distribution when not linked into a combine 17 executable.) 18 19 This file is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; see the file COPYING. If not, write to 26 the Free Software Foundation, 51 Franklin Street, Fifth Floor, 27 Boston, MA 02110-1301, USA. */ 28 29/**************************************************************************** 30 * The functions here are derived from gcc/config/arm/pr-support.c from the 31 * 4.3.x release. The main changes here involve the use of ptrace to retrieve 32 * memory/processor states from a remote process. 33 ****************************************************************************/ 34 35#include <sys/types.h> 36#include <unwind.h> 37 38#include "utility.h" 39 40/* We add a prototype for abort here to avoid creating a dependency on 41 target headers. */ 42extern void abort (void); 43 44/* Derived from _Unwind_VRS_Pop to use ptrace */ 45extern _Unwind_VRS_Result 46unwind_VRS_Pop_with_ptrace (_Unwind_Context *context, 47 _Unwind_VRS_RegClass regclass, 48 _uw discriminator, 49 _Unwind_VRS_DataRepresentation representation, 50 pid_t pid); 51 52typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ 53 54/* Misc constants. */ 55#define R_IP 12 56#define R_SP 13 57#define R_LR 14 58#define R_PC 15 59 60#define uint32_highbit (((_uw) 1) << 31) 61 62void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); 63 64/* Unwind descriptors. */ 65 66typedef struct 67{ 68 _uw16 length; 69 _uw16 offset; 70} EHT16; 71 72typedef struct 73{ 74 _uw length; 75 _uw offset; 76} EHT32; 77 78/* Personality routine helper functions. */ 79 80#define CODE_FINISH (0xb0) 81 82/* Derived from next_unwind_byte to use ptrace */ 83/* Return the next byte of unwinding information, or CODE_FINISH if there is 84 no data remaining. */ 85static inline _uw8 86next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid) 87{ 88 _uw8 b; 89 90 if (uws->bytes_left == 0) 91 { 92 /* Load another word */ 93 if (uws->words_left == 0) 94 return CODE_FINISH; /* Nothing left. */ 95 uws->words_left--; 96 uws->data = get_remote_word(pid, uws->next); 97 uws->next++; 98 uws->bytes_left = 3; 99 } 100 else 101 uws->bytes_left--; 102 103 /* Extract the most significant byte. */ 104 b = (uws->data >> 24) & 0xff; 105 uws->data <<= 8; 106 return b; 107} 108 109/* Execute the unwinding instructions described by UWS. */ 110_Unwind_Reason_Code 111unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws, 112 pid_t pid) 113{ 114 _uw op; 115 int set_pc; 116 _uw reg; 117 118 set_pc = 0; 119 for (;;) 120 { 121 op = next_unwind_byte_with_ptrace (uws, pid); 122 if (op == CODE_FINISH) 123 { 124 /* If we haven't already set pc then copy it from lr. */ 125 if (!set_pc) 126 { 127 _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, 128 ®); 129 _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, 130 ®); 131 set_pc = 1; 132 } 133 /* Drop out of the loop. */ 134 break; 135 } 136 if ((op & 0x80) == 0) 137 { 138 /* vsp = vsp +- (imm6 << 2 + 4). */ 139 _uw offset; 140 141 offset = ((op & 0x3f) << 2) + 4; 142 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 143 if (op & 0x40) 144 reg -= offset; 145 else 146 reg += offset; 147 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 148 continue; 149 } 150 151 if ((op & 0xf0) == 0x80) 152 { 153 op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid); 154 if (op == 0x8000) 155 { 156 /* Refuse to unwind. */ 157 return _URC_FAILURE; 158 } 159 /* Pop r4-r15 under mask. */ 160 op = (op << 4) & 0xfff0; 161 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32, 162 pid) 163 != _UVRSR_OK) 164 return _URC_FAILURE; 165 if (op & (1 << R_PC)) 166 set_pc = 1; 167 continue; 168 } 169 if ((op & 0xf0) == 0x90) 170 { 171 op &= 0xf; 172 if (op == 13 || op == 15) 173 /* Reserved. */ 174 return _URC_FAILURE; 175 /* vsp = r[nnnn]. */ 176 _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®); 177 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 178 continue; 179 } 180 if ((op & 0xf0) == 0xa0) 181 { 182 /* Pop r4-r[4+nnn], [lr]. */ 183 _uw mask; 184 185 mask = (0xff0 >> (7 - (op & 7))) & 0xff0; 186 if (op & 8) 187 mask |= (1 << R_LR); 188 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32, 189 pid) 190 != _UVRSR_OK) 191 return _URC_FAILURE; 192 continue; 193 } 194 if ((op & 0xf0) == 0xb0) 195 { 196 /* op == 0xb0 already handled. */ 197 if (op == 0xb1) 198 { 199 op = next_unwind_byte_with_ptrace (uws, pid); 200 if (op == 0 || ((op & 0xf0) != 0)) 201 /* Spare. */ 202 return _URC_FAILURE; 203 /* Pop r0-r4 under mask. */ 204 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, 205 _UVRSD_UINT32, pid) 206 != _UVRSR_OK) 207 return _URC_FAILURE; 208 continue; 209 } 210 if (op == 0xb2) 211 { 212 /* vsp = vsp + 0x204 + (uleb128 << 2). */ 213 int shift; 214 215 _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, 216 ®); 217 op = next_unwind_byte_with_ptrace (uws, pid); 218 shift = 2; 219 while (op & 0x80) 220 { 221 reg += ((op & 0x7f) << shift); 222 shift += 7; 223 op = next_unwind_byte_with_ptrace (uws, pid); 224 } 225 reg += ((op & 0x7f) << shift) + 0x204; 226 _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, 227 ®); 228 continue; 229 } 230 if (op == 0xb3) 231 { 232 /* Pop VFP registers with fldmx. */ 233 op = next_unwind_byte_with_ptrace (uws, pid); 234 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 235 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, 236 pid) 237 != _UVRSR_OK) 238 return _URC_FAILURE; 239 continue; 240 } 241 if ((op & 0xfc) == 0xb4) 242 { 243 /* Pop FPA E[4]-E[4+nn]. */ 244 op = 0x40000 | ((op & 3) + 1); 245 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX, 246 pid) 247 != _UVRSR_OK) 248 return _URC_FAILURE; 249 continue; 250 } 251 /* op & 0xf8 == 0xb8. */ 252 /* Pop VFP D[8]-D[8+nnn] with fldmx. */ 253 op = 0x80000 | ((op & 7) + 1); 254 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid) 255 != _UVRSR_OK) 256 return _URC_FAILURE; 257 continue; 258 } 259 if ((op & 0xf0) == 0xc0) 260 { 261 if (op == 0xc6) 262 { 263 /* Pop iWMMXt D registers. */ 264 op = next_unwind_byte_with_ptrace (uws, pid); 265 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 266 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, 267 _UVRSD_UINT64, pid) 268 != _UVRSR_OK) 269 return _URC_FAILURE; 270 continue; 271 } 272 if (op == 0xc7) 273 { 274 op = next_unwind_byte_with_ptrace (uws, pid); 275 if (op == 0 || (op & 0xf0) != 0) 276 /* Spare. */ 277 return _URC_FAILURE; 278 /* Pop iWMMXt wCGR{3,2,1,0} under mask. */ 279 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op, 280 _UVRSD_UINT32, pid) 281 != _UVRSR_OK) 282 return _URC_FAILURE; 283 continue; 284 } 285 if ((op & 0xf8) == 0xc0) 286 { 287 /* Pop iWMMXt wR[10]-wR[10+nnn]. */ 288 op = 0xa0000 | ((op & 0xf) + 1); 289 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, 290 _UVRSD_UINT64, pid) 291 != _UVRSR_OK) 292 return _URC_FAILURE; 293 continue; 294 } 295 if (op == 0xc8) 296 { 297#ifndef __VFP_FP__ 298 /* Pop FPA registers. */ 299 op = next_unwind_byte_with_ptrace (uws, pid); 300 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 301 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX, 302 pid) 303 != _UVRSR_OK) 304 return _URC_FAILURE; 305 continue; 306#else 307 /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */ 308 op = next_unwind_byte_with_ptrace (uws, pid); 309 op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1); 310 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, 311 _UVRSD_DOUBLE, pid) 312 != _UVRSR_OK) 313 return _URC_FAILURE; 314 continue; 315#endif 316 } 317 if (op == 0xc9) 318 { 319 /* Pop VFP registers with fldmd. */ 320 op = next_unwind_byte_with_ptrace (uws, pid); 321 op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 322 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, 323 _UVRSD_DOUBLE, pid) 324 != _UVRSR_OK) 325 return _URC_FAILURE; 326 continue; 327 } 328 /* Spare. */ 329 return _URC_FAILURE; 330 } 331 if ((op & 0xf8) == 0xd0) 332 { 333 /* Pop VFP D[8]-D[8+nnn] with fldmd. */ 334 op = 0x80000 | ((op & 7) + 1); 335 if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE, 336 pid) 337 != _UVRSR_OK) 338 return _URC_FAILURE; 339 continue; 340 } 341 /* Spare. */ 342 return _URC_FAILURE; 343 } 344 return _URC_OK; 345} 346