1169689Skan/* ARM EABI compliant unwinding routines 2169689Skan Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3169689Skan Contributed by Paul Brook 4169689Skan 5169689Skan This file is free software; you can redistribute it and/or modify it 6169689Skan under the terms of the GNU General Public License as published by the 7169689Skan Free Software Foundation; either version 2, or (at your option) any 8169689Skan later version. 9169689Skan 10169689Skan In addition to the permissions in the GNU General Public License, the 11169689Skan Free Software Foundation gives you unlimited permission to link the 12169689Skan compiled version of this file into combinations with other programs, 13169689Skan and to distribute those combinations without any restriction coming 14169689Skan from the use of this file. (The General Public License restrictions 15169689Skan do apply in other respects; for example, they cover modification of 16169689Skan the file, and distribution when not linked into a combine 17169689Skan executable.) 18169689Skan 19169689Skan This file is distributed in the hope that it will be useful, but 20169689Skan WITHOUT ANY WARRANTY; without even the implied warranty of 21169689Skan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22169689Skan General Public License for more details. 23169689Skan 24169689Skan You should have received a copy of the GNU General Public License 25169689Skan along with this program; see the file COPYING. If not, write to 26169689Skan the Free Software Foundation, 51 Franklin Street, Fifth Floor, 27169689Skan Boston, MA 02110-1301, USA. */ 28169689Skan#include "unwind.h" 29169689Skan 30169689Skan/* We add a prototype for abort here to avoid creating a dependency on 31169689Skan target headers. */ 32169689Skanextern void abort (void); 33169689Skan 34169689Skantypedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ 35169689Skan 36169689Skan/* Misc constants. */ 37169689Skan#define R_IP 12 38169689Skan#define R_SP 13 39169689Skan#define R_LR 14 40169689Skan#define R_PC 15 41169689Skan 42169689Skan#define uint32_highbit (((_uw) 1) << 31) 43169689Skan 44169689Skanvoid __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); 45169689Skan 46169689Skan/* Unwind descriptors. */ 47169689Skan 48169689Skantypedef struct 49169689Skan{ 50169689Skan _uw16 length; 51169689Skan _uw16 offset; 52169689Skan} EHT16; 53169689Skan 54169689Skantypedef struct 55169689Skan{ 56169689Skan _uw length; 57169689Skan _uw offset; 58169689Skan} EHT32; 59169689Skan 60169689Skan/* Calculate the address encoded by a 31-bit self-relative offset at address 61169689Skan P. Copy of routine in unwind-arm.c. */ 62169689Skan 63169689Skanstatic inline _uw 64169689Skanselfrel_offset31 (const _uw *p) 65169689Skan{ 66169689Skan _uw offset; 67169689Skan 68169689Skan offset = *p; 69169689Skan /* Sign extend to 32 bits. */ 70169689Skan if (offset & (1 << 30)) 71169689Skan offset |= 1u << 31; 72169689Skan 73169689Skan return offset + (_uw) p; 74169689Skan} 75169689Skan 76169689Skan 77169689Skan/* Personality routine helper functions. */ 78169689Skan 79169689Skan#define CODE_FINISH (0xb0) 80169689Skan 81169689Skan/* Return the next byte of unwinding information, or CODE_FINISH if there is 82169689Skan no data remaining. */ 83169689Skanstatic inline _uw8 84169689Skannext_unwind_byte (__gnu_unwind_state * uws) 85169689Skan{ 86169689Skan _uw8 b; 87169689Skan 88169689Skan if (uws->bytes_left == 0) 89169689Skan { 90169689Skan /* Load another word */ 91169689Skan if (uws->words_left == 0) 92169689Skan return CODE_FINISH; /* Nothing left. */ 93169689Skan uws->words_left--; 94169689Skan uws->data = *(uws->next++); 95169689Skan uws->bytes_left = 3; 96169689Skan } 97169689Skan else 98169689Skan uws->bytes_left--; 99169689Skan 100169689Skan /* Extract the most significant byte. */ 101169689Skan b = (uws->data >> 24) & 0xff; 102169689Skan uws->data <<= 8; 103169689Skan return b; 104169689Skan} 105169689Skan 106169689Skan/* Execute the unwinding instructions described by UWS. */ 107169689Skan_Unwind_Reason_Code 108169689Skan__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) 109169689Skan{ 110169689Skan _uw op; 111169689Skan int set_pc; 112169689Skan _uw reg; 113169689Skan 114169689Skan set_pc = 0; 115169689Skan for (;;) 116169689Skan { 117169689Skan op = next_unwind_byte (uws); 118169689Skan if (op == CODE_FINISH) 119169689Skan { 120169689Skan /* If we haven't already set pc then copy it from lr. */ 121169689Skan if (!set_pc) 122169689Skan { 123169689Skan _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, 124169689Skan ®); 125169689Skan _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, 126169689Skan ®); 127169689Skan set_pc = 1; 128169689Skan } 129169689Skan /* Drop out of the loop. */ 130169689Skan break; 131169689Skan } 132169689Skan if ((op & 0x80) == 0) 133169689Skan { 134169689Skan /* vsp = vsp +- (imm6 << 2 + 4). */ 135169689Skan _uw offset; 136169689Skan 137169689Skan offset = ((op & 0x3f) << 2) + 4; 138169689Skan _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 139169689Skan if (op & 0x40) 140169689Skan reg -= offset; 141169689Skan else 142169689Skan reg += offset; 143169689Skan _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 144169689Skan continue; 145169689Skan } 146169689Skan 147169689Skan if ((op & 0xf0) == 0x80) 148169689Skan { 149169689Skan op = (op << 8) | next_unwind_byte (uws); 150169689Skan if (op == 0x8000) 151169689Skan { 152169689Skan /* Refuse to unwind. */ 153169689Skan return _URC_FAILURE; 154169689Skan } 155169689Skan /* Pop r4-r15 under mask. */ 156169689Skan op = (op << 4) & 0xfff0; 157169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) 158169689Skan != _UVRSR_OK) 159169689Skan return _URC_FAILURE; 160169689Skan if (op & (1 << R_PC)) 161169689Skan set_pc = 1; 162169689Skan continue; 163169689Skan } 164169689Skan if ((op & 0xf0) == 0x90) 165169689Skan { 166169689Skan op &= 0xf; 167169689Skan if (op == 13 || op == 15) 168169689Skan /* Reserved. */ 169169689Skan return _URC_FAILURE; 170169689Skan /* vsp = r[nnnn]. */ 171169689Skan _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®); 172169689Skan _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); 173169689Skan continue; 174169689Skan } 175169689Skan if ((op & 0xf0) == 0xa0) 176169689Skan { 177169689Skan /* Pop r4-r[4+nnn], [lr]. */ 178169689Skan _uw mask; 179169689Skan 180169689Skan mask = (0xff0 >> (7 - (op & 7))) & 0xff0; 181169689Skan if (op & 8) 182169689Skan mask |= (1 << R_LR); 183169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32) 184169689Skan != _UVRSR_OK) 185169689Skan return _URC_FAILURE; 186169689Skan continue; 187169689Skan } 188169689Skan if ((op & 0xf0) == 0xb0) 189169689Skan { 190169689Skan /* op == 0xb0 already handled. */ 191169689Skan if (op == 0xb1) 192169689Skan { 193169689Skan op = next_unwind_byte (uws); 194169689Skan if (op == 0 || ((op & 0xf0) != 0)) 195169689Skan /* Spare. */ 196169689Skan return _URC_FAILURE; 197169689Skan /* Pop r0-r4 under mask. */ 198169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) 199169689Skan != _UVRSR_OK) 200169689Skan return _URC_FAILURE; 201169689Skan continue; 202169689Skan } 203169689Skan if (op == 0xb2) 204169689Skan { 205169689Skan /* vsp = vsp + 0x204 + (uleb128 << 2). */ 206169689Skan int shift; 207169689Skan 208169689Skan _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, 209169689Skan ®); 210169689Skan op = next_unwind_byte (uws); 211169689Skan shift = 2; 212169689Skan while (op & 0x80) 213169689Skan { 214169689Skan reg += ((op & 0x7f) << shift); 215169689Skan shift += 7; 216169689Skan op = next_unwind_byte (uws); 217169689Skan } 218169689Skan reg += ((op & 0x7f) << shift) + 0x204; 219169689Skan _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, 220169689Skan ®); 221169689Skan continue; 222169689Skan } 223169689Skan if (op == 0xb3) 224169689Skan { 225169689Skan /* Pop VFP registers with fldmx. */ 226169689Skan op = next_unwind_byte (uws); 227169689Skan op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 228169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) 229169689Skan != _UVRSR_OK) 230169689Skan return _URC_FAILURE; 231169689Skan continue; 232169689Skan } 233169689Skan if ((op & 0xfc) == 0xb4) 234169689Skan { 235169689Skan /* Pop FPA E[4]-E[4+nn]. */ 236169689Skan op = 0x40000 | ((op & 3) + 1); 237169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) 238169689Skan != _UVRSR_OK) 239169689Skan return _URC_FAILURE; 240169689Skan continue; 241169689Skan } 242169689Skan /* op & 0xf8 == 0xb8. */ 243169689Skan /* Pop VFP D[8]-D[8+nnn] with fldmx. */ 244169689Skan op = 0x80000 | ((op & 7) + 1); 245169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) 246169689Skan != _UVRSR_OK) 247169689Skan return _URC_FAILURE; 248169689Skan continue; 249169689Skan } 250169689Skan if ((op & 0xf0) == 0xc0) 251169689Skan { 252169689Skan if (op == 0xc6) 253169689Skan { 254169689Skan /* Pop iWMMXt D registers. */ 255169689Skan op = next_unwind_byte (uws); 256169689Skan op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 257169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) 258169689Skan != _UVRSR_OK) 259169689Skan return _URC_FAILURE; 260169689Skan continue; 261169689Skan } 262169689Skan if (op == 0xc7) 263169689Skan { 264169689Skan op = next_unwind_byte (uws); 265169689Skan if (op == 0 || (op & 0xf0) != 0) 266169689Skan /* Spare. */ 267169689Skan return _URC_FAILURE; 268169689Skan /* Pop iWMMXt wCGR{3,2,1,0} under mask. */ 269169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32) 270169689Skan != _UVRSR_OK) 271169689Skan return _URC_FAILURE; 272169689Skan continue; 273169689Skan } 274169689Skan if ((op & 0xf8) == 0xc0) 275169689Skan { 276169689Skan /* Pop iWMMXt wR[10]-wR[10+nnn]. */ 277169689Skan op = 0xa0000 | ((op & 0xf) + 1); 278169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) 279169689Skan != _UVRSR_OK) 280169689Skan return _URC_FAILURE; 281169689Skan continue; 282169689Skan } 283169689Skan if (op == 0xc8) 284169689Skan { 285169689Skan /* Pop FPA registers. */ 286169689Skan op = next_unwind_byte (uws); 287169689Skan op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 288169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) 289169689Skan != _UVRSR_OK) 290169689Skan return _URC_FAILURE; 291169689Skan continue; 292169689Skan } 293169689Skan if (op == 0xc9) 294169689Skan { 295169689Skan /* Pop VFP registers with fldmd. */ 296169689Skan op = next_unwind_byte (uws); 297169689Skan op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); 298169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) 299169689Skan != _UVRSR_OK) 300169689Skan return _URC_FAILURE; 301169689Skan continue; 302169689Skan } 303169689Skan /* Spare. */ 304169689Skan return _URC_FAILURE; 305169689Skan } 306169689Skan if ((op & 0xf8) == 0xd0) 307169689Skan { 308169689Skan /* Pop VFP D[8]-D[8+nnn] with fldmd. */ 309169689Skan op = 0x80000 | ((op & 7) + 1); 310169689Skan if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) 311169689Skan != _UVRSR_OK) 312169689Skan return _URC_FAILURE; 313169689Skan continue; 314169689Skan } 315169689Skan /* Spare. */ 316169689Skan return _URC_FAILURE; 317169689Skan } 318169689Skan return _URC_OK; 319169689Skan} 320169689Skan 321169689Skan 322169689Skan/* Execute the unwinding instructions associated with a frame. UCBP and 323169689Skan CONTEXT are the current exception object and virtual CPU state 324169689Skan respectively. */ 325169689Skan 326169689Skan_Unwind_Reason_Code 327169689Skan__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context) 328169689Skan{ 329169689Skan _uw *ptr; 330169689Skan __gnu_unwind_state uws; 331169689Skan 332169689Skan ptr = (_uw *) ucbp->pr_cache.ehtp; 333169689Skan /* Skip over the personality routine address. */ 334169689Skan ptr++; 335169689Skan /* Setup the unwinder state. */ 336169689Skan uws.data = (*ptr) << 8; 337169689Skan uws.next = ptr + 1; 338169689Skan uws.bytes_left = 3; 339169689Skan uws.words_left = ((*ptr) >> 24) & 0xff; 340169689Skan 341169689Skan return __gnu_unwind_execute (context, &uws); 342169689Skan} 343169689Skan 344169689Skan/* Get the _Unwind_Control_Block from an _Unwind_Context. */ 345169689Skan 346169689Skanstatic inline _Unwind_Control_Block * 347169689Skanunwind_UCB_from_context (_Unwind_Context * context) 348169689Skan{ 349169689Skan return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP); 350169689Skan} 351169689Skan 352169689Skan/* Get the start address of the function being unwound. */ 353169689Skan 354169689Skan_Unwind_Ptr 355169689Skan_Unwind_GetRegionStart (_Unwind_Context * context) 356169689Skan{ 357169689Skan _Unwind_Control_Block *ucbp; 358169689Skan 359169689Skan ucbp = unwind_UCB_from_context (context); 360169689Skan return (_Unwind_Ptr) ucbp->pr_cache.fnstart; 361169689Skan} 362169689Skan 363169689Skan/* Find the Language specific exception data. */ 364169689Skan 365169689Skanvoid * 366169689Skan_Unwind_GetLanguageSpecificData (_Unwind_Context * context) 367169689Skan{ 368169689Skan _Unwind_Control_Block *ucbp; 369169689Skan _uw *ptr; 370169689Skan 371169689Skan /* Get a pointer to the exception table entry. */ 372169689Skan ucbp = unwind_UCB_from_context (context); 373169689Skan ptr = (_uw *) ucbp->pr_cache.ehtp; 374169689Skan /* Skip the personality routine address. */ 375169689Skan ptr++; 376169689Skan /* Skip the unwind opcodes. */ 377169689Skan ptr += (((*ptr) >> 24) & 0xff) + 1; 378169689Skan 379169689Skan return ptr; 380169689Skan} 381169689Skan 382