1*0b57cec5SDimitry Andric //===--------------------------- Unwind-EHABI.cpp -------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric // 8*0b57cec5SDimitry Andric // Implements ARM zero-cost C++ exceptions 9*0b57cec5SDimitry Andric // 10*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric #include "Unwind-EHABI.h" 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #if defined(_LIBUNWIND_ARM_EHABI) 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include <inttypes.h> 17*0b57cec5SDimitry Andric #include <stdbool.h> 18*0b57cec5SDimitry Andric #include <stdint.h> 19*0b57cec5SDimitry Andric #include <stdio.h> 20*0b57cec5SDimitry Andric #include <stdlib.h> 21*0b57cec5SDimitry Andric #include <string.h> 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric #include "config.h" 24*0b57cec5SDimitry Andric #include "libunwind.h" 25*0b57cec5SDimitry Andric #include "libunwind_ext.h" 26*0b57cec5SDimitry Andric #include "unwind.h" 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric namespace { 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric // Strange order: take words in order, but inside word, take from most to least 31*0b57cec5SDimitry Andric // signinficant byte. 32*0b57cec5SDimitry Andric uint8_t getByte(const uint32_t* data, size_t offset) { 33*0b57cec5SDimitry Andric const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data); 34*0b57cec5SDimitry Andric #ifdef __LITTLE_ENDIAN__ 35*0b57cec5SDimitry Andric return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; 36*0b57cec5SDimitry Andric #else 37*0b57cec5SDimitry Andric return byteData[offset]; 38*0b57cec5SDimitry Andric #endif 39*0b57cec5SDimitry Andric } 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric const char* getNextWord(const char* data, uint32_t* out) { 42*0b57cec5SDimitry Andric *out = *reinterpret_cast<const uint32_t*>(data); 43*0b57cec5SDimitry Andric return data + 4; 44*0b57cec5SDimitry Andric } 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric const char* getNextNibble(const char* data, uint32_t* out) { 47*0b57cec5SDimitry Andric *out = *reinterpret_cast<const uint16_t*>(data); 48*0b57cec5SDimitry Andric return data + 2; 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric struct Descriptor { 52*0b57cec5SDimitry Andric // See # 9.2 53*0b57cec5SDimitry Andric typedef enum { 54*0b57cec5SDimitry Andric SU16 = 0, // Short descriptor, 16-bit entries 55*0b57cec5SDimitry Andric LU16 = 1, // Long descriptor, 16-bit entries 56*0b57cec5SDimitry Andric LU32 = 3, // Long descriptor, 32-bit entries 57*0b57cec5SDimitry Andric RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7, 58*0b57cec5SDimitry Andric RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11, 59*0b57cec5SDimitry Andric RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15 60*0b57cec5SDimitry Andric } Format; 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric // See # 9.2 63*0b57cec5SDimitry Andric typedef enum { 64*0b57cec5SDimitry Andric CLEANUP = 0x0, 65*0b57cec5SDimitry Andric FUNC = 0x1, 66*0b57cec5SDimitry Andric CATCH = 0x2, 67*0b57cec5SDimitry Andric INVALID = 0x4 68*0b57cec5SDimitry Andric } Kind; 69*0b57cec5SDimitry Andric }; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric _Unwind_Reason_Code ProcessDescriptors( 72*0b57cec5SDimitry Andric _Unwind_State state, 73*0b57cec5SDimitry Andric _Unwind_Control_Block* ucbp, 74*0b57cec5SDimitry Andric struct _Unwind_Context* context, 75*0b57cec5SDimitry Andric Descriptor::Format format, 76*0b57cec5SDimitry Andric const char* descriptorStart, 77*0b57cec5SDimitry Andric uint32_t flags) { 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric // EHT is inlined in the index using compact form. No descriptors. #5 80*0b57cec5SDimitry Andric if (flags & 0x1) 81*0b57cec5SDimitry Andric return _URC_CONTINUE_UNWIND; 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric // TODO: We should check the state here, and determine whether we need to 84*0b57cec5SDimitry Andric // perform phase1 or phase2 unwinding. 85*0b57cec5SDimitry Andric (void)state; 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric const char* descriptor = descriptorStart; 88*0b57cec5SDimitry Andric uint32_t descriptorWord; 89*0b57cec5SDimitry Andric getNextWord(descriptor, &descriptorWord); 90*0b57cec5SDimitry Andric while (descriptorWord) { 91*0b57cec5SDimitry Andric // Read descriptor based on # 9.2. 92*0b57cec5SDimitry Andric uint32_t length; 93*0b57cec5SDimitry Andric uint32_t offset; 94*0b57cec5SDimitry Andric switch (format) { 95*0b57cec5SDimitry Andric case Descriptor::LU32: 96*0b57cec5SDimitry Andric descriptor = getNextWord(descriptor, &length); 97*0b57cec5SDimitry Andric descriptor = getNextWord(descriptor, &offset); 98*0b57cec5SDimitry Andric case Descriptor::LU16: 99*0b57cec5SDimitry Andric descriptor = getNextNibble(descriptor, &length); 100*0b57cec5SDimitry Andric descriptor = getNextNibble(descriptor, &offset); 101*0b57cec5SDimitry Andric default: 102*0b57cec5SDimitry Andric assert(false); 103*0b57cec5SDimitry Andric return _URC_FAILURE; 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value. 107*0b57cec5SDimitry Andric Descriptor::Kind kind = 108*0b57cec5SDimitry Andric static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1)); 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric // Clear off flag from last bit. 111*0b57cec5SDimitry Andric length &= ~1u; 112*0b57cec5SDimitry Andric offset &= ~1u; 113*0b57cec5SDimitry Andric uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset; 114*0b57cec5SDimitry Andric uintptr_t scopeEnd = scopeStart + length; 115*0b57cec5SDimitry Andric uintptr_t pc = _Unwind_GetIP(context); 116*0b57cec5SDimitry Andric bool isInScope = (scopeStart <= pc) && (pc < scopeEnd); 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric switch (kind) { 119*0b57cec5SDimitry Andric case Descriptor::CLEANUP: { 120*0b57cec5SDimitry Andric // TODO(ajwong): Handle cleanup descriptors. 121*0b57cec5SDimitry Andric break; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric case Descriptor::FUNC: { 124*0b57cec5SDimitry Andric // TODO(ajwong): Handle function descriptors. 125*0b57cec5SDimitry Andric break; 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric case Descriptor::CATCH: { 128*0b57cec5SDimitry Andric // Catch descriptors require gobbling one more word. 129*0b57cec5SDimitry Andric uint32_t landing_pad; 130*0b57cec5SDimitry Andric descriptor = getNextWord(descriptor, &landing_pad); 131*0b57cec5SDimitry Andric 132*0b57cec5SDimitry Andric if (isInScope) { 133*0b57cec5SDimitry Andric // TODO(ajwong): This is only phase1 compatible logic. Implement 134*0b57cec5SDimitry Andric // phase2. 135*0b57cec5SDimitry Andric landing_pad = signExtendPrel31(landing_pad & ~0x80000000); 136*0b57cec5SDimitry Andric if (landing_pad == 0xffffffff) { 137*0b57cec5SDimitry Andric return _URC_HANDLER_FOUND; 138*0b57cec5SDimitry Andric } else if (landing_pad == 0xfffffffe) { 139*0b57cec5SDimitry Andric return _URC_FAILURE; 140*0b57cec5SDimitry Andric } else { 141*0b57cec5SDimitry Andric /* 142*0b57cec5SDimitry Andric bool is_reference_type = landing_pad & 0x80000000; 143*0b57cec5SDimitry Andric void* matched_object; 144*0b57cec5SDimitry Andric if (__cxxabiv1::__cxa_type_match( 145*0b57cec5SDimitry Andric ucbp, reinterpret_cast<const std::type_info *>(landing_pad), 146*0b57cec5SDimitry Andric is_reference_type, 147*0b57cec5SDimitry Andric &matched_object) != __cxxabiv1::ctm_failed) 148*0b57cec5SDimitry Andric return _URC_HANDLER_FOUND; 149*0b57cec5SDimitry Andric */ 150*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("Type matching not implemented"); 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric break; 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric default: 156*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("Invalid descriptor kind found."); 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric getNextWord(descriptor, &descriptorWord); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric return _URC_CONTINUE_UNWIND; 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, 166*0b57cec5SDimitry Andric _Unwind_Control_Block* ucbp, 167*0b57cec5SDimitry Andric struct _Unwind_Context* context) { 168*0b57cec5SDimitry Andric // Read the compact model EHT entry's header # 6.3 169*0b57cec5SDimitry Andric const uint32_t* unwindingData = ucbp->pr_cache.ehtp; 170*0b57cec5SDimitry Andric assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); 171*0b57cec5SDimitry Andric Descriptor::Format format = 172*0b57cec5SDimitry Andric static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24); 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric const char *lsda = 175*0b57cec5SDimitry Andric reinterpret_cast<const char *>(_Unwind_GetLanguageSpecificData(context)); 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric // Handle descriptors before unwinding so they are processed in the context 178*0b57cec5SDimitry Andric // of the correct stack frame. 179*0b57cec5SDimitry Andric _Unwind_Reason_Code result = 180*0b57cec5SDimitry Andric ProcessDescriptors(state, ucbp, context, format, lsda, 181*0b57cec5SDimitry Andric ucbp->pr_cache.additional); 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric if (result != _URC_CONTINUE_UNWIND) 184*0b57cec5SDimitry Andric return result; 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric if (__unw_step(reinterpret_cast<unw_cursor_t *>(context)) != UNW_STEP_SUCCESS) 187*0b57cec5SDimitry Andric return _URC_FAILURE; 188*0b57cec5SDimitry Andric return _URC_CONTINUE_UNWIND; 189*0b57cec5SDimitry Andric } 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / 192*0b57cec5SDimitry Andric // _UVRSD_UINT32. 193*0b57cec5SDimitry Andric uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) { 194*0b57cec5SDimitry Andric return ((1U << (count_minus_one + 1)) - 1) << start; 195*0b57cec5SDimitry Andric } 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP / 198*0b57cec5SDimitry Andric // _UVRSD_DOUBLE. 199*0b57cec5SDimitry Andric uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) { 200*0b57cec5SDimitry Andric return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1); 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric } // end anonymous namespace 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric /** 206*0b57cec5SDimitry Andric * Decodes an EHT entry. 207*0b57cec5SDimitry Andric * 208*0b57cec5SDimitry Andric * @param data Pointer to EHT. 209*0b57cec5SDimitry Andric * @param[out] off Offset from return value (in bytes) to begin interpretation. 210*0b57cec5SDimitry Andric * @param[out] len Number of bytes in unwind code. 211*0b57cec5SDimitry Andric * @return Pointer to beginning of unwind code. 212*0b57cec5SDimitry Andric */ 213*0b57cec5SDimitry Andric extern "C" const uint32_t* 214*0b57cec5SDimitry Andric decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { 215*0b57cec5SDimitry Andric if ((*data & 0x80000000) == 0) { 216*0b57cec5SDimitry Andric // 6.2: Generic Model 217*0b57cec5SDimitry Andric // 218*0b57cec5SDimitry Andric // EHT entry is a prel31 pointing to the PR, followed by data understood 219*0b57cec5SDimitry Andric // only by the personality routine. Fortunately, all existing assembler 220*0b57cec5SDimitry Andric // implementations, including GNU assembler, LLVM integrated assembler, 221*0b57cec5SDimitry Andric // and ARM assembler, assume that the unwind opcodes come after the 222*0b57cec5SDimitry Andric // personality rountine address. 223*0b57cec5SDimitry Andric *off = 1; // First byte is size data. 224*0b57cec5SDimitry Andric *len = (((data[1] >> 24) & 0xff) + 1) * 4; 225*0b57cec5SDimitry Andric data++; // Skip the first word, which is the prel31 offset. 226*0b57cec5SDimitry Andric } else { 227*0b57cec5SDimitry Andric // 6.3: ARM Compact Model 228*0b57cec5SDimitry Andric // 229*0b57cec5SDimitry Andric // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded 230*0b57cec5SDimitry Andric // by format: 231*0b57cec5SDimitry Andric Descriptor::Format format = 232*0b57cec5SDimitry Andric static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24); 233*0b57cec5SDimitry Andric switch (format) { 234*0b57cec5SDimitry Andric case Descriptor::SU16: 235*0b57cec5SDimitry Andric *len = 4; 236*0b57cec5SDimitry Andric *off = 1; 237*0b57cec5SDimitry Andric break; 238*0b57cec5SDimitry Andric case Descriptor::LU16: 239*0b57cec5SDimitry Andric case Descriptor::LU32: 240*0b57cec5SDimitry Andric *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); 241*0b57cec5SDimitry Andric *off = 2; 242*0b57cec5SDimitry Andric break; 243*0b57cec5SDimitry Andric default: 244*0b57cec5SDimitry Andric return nullptr; 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric return data; 248*0b57cec5SDimitry Andric } 249*0b57cec5SDimitry Andric 250*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 251*0b57cec5SDimitry Andric _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data, 252*0b57cec5SDimitry Andric size_t offset, size_t len) { 253*0b57cec5SDimitry Andric bool wrotePC = false; 254*0b57cec5SDimitry Andric bool finish = false; 255*0b57cec5SDimitry Andric while (offset < len && !finish) { 256*0b57cec5SDimitry Andric uint8_t byte = getByte(data, offset++); 257*0b57cec5SDimitry Andric if ((byte & 0x80) == 0) { 258*0b57cec5SDimitry Andric uint32_t sp; 259*0b57cec5SDimitry Andric _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); 260*0b57cec5SDimitry Andric if (byte & 0x40) 261*0b57cec5SDimitry Andric sp -= (((uint32_t)byte & 0x3f) << 2) + 4; 262*0b57cec5SDimitry Andric else 263*0b57cec5SDimitry Andric sp += ((uint32_t)byte << 2) + 4; 264*0b57cec5SDimitry Andric _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); 265*0b57cec5SDimitry Andric } else { 266*0b57cec5SDimitry Andric switch (byte & 0xf0) { 267*0b57cec5SDimitry Andric case 0x80: { 268*0b57cec5SDimitry Andric if (offset >= len) 269*0b57cec5SDimitry Andric return _URC_FAILURE; 270*0b57cec5SDimitry Andric uint32_t registers = 271*0b57cec5SDimitry Andric (((uint32_t)byte & 0x0f) << 12) | 272*0b57cec5SDimitry Andric (((uint32_t)getByte(data, offset++)) << 4); 273*0b57cec5SDimitry Andric if (!registers) 274*0b57cec5SDimitry Andric return _URC_FAILURE; 275*0b57cec5SDimitry Andric if (registers & (1 << 15)) 276*0b57cec5SDimitry Andric wrotePC = true; 277*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); 278*0b57cec5SDimitry Andric break; 279*0b57cec5SDimitry Andric } 280*0b57cec5SDimitry Andric case 0x90: { 281*0b57cec5SDimitry Andric uint8_t reg = byte & 0x0f; 282*0b57cec5SDimitry Andric if (reg == 13 || reg == 15) 283*0b57cec5SDimitry Andric return _URC_FAILURE; 284*0b57cec5SDimitry Andric uint32_t sp; 285*0b57cec5SDimitry Andric _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg, 286*0b57cec5SDimitry Andric _UVRSD_UINT32, &sp); 287*0b57cec5SDimitry Andric _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, 288*0b57cec5SDimitry Andric &sp); 289*0b57cec5SDimitry Andric break; 290*0b57cec5SDimitry Andric } 291*0b57cec5SDimitry Andric case 0xa0: { 292*0b57cec5SDimitry Andric uint32_t registers = RegisterMask(4, byte & 0x07); 293*0b57cec5SDimitry Andric if (byte & 0x08) 294*0b57cec5SDimitry Andric registers |= 1 << 14; 295*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); 296*0b57cec5SDimitry Andric break; 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric case 0xb0: { 299*0b57cec5SDimitry Andric switch (byte) { 300*0b57cec5SDimitry Andric case 0xb0: 301*0b57cec5SDimitry Andric finish = true; 302*0b57cec5SDimitry Andric break; 303*0b57cec5SDimitry Andric case 0xb1: { 304*0b57cec5SDimitry Andric if (offset >= len) 305*0b57cec5SDimitry Andric return _URC_FAILURE; 306*0b57cec5SDimitry Andric uint8_t registers = getByte(data, offset++); 307*0b57cec5SDimitry Andric if (registers & 0xf0 || !registers) 308*0b57cec5SDimitry Andric return _URC_FAILURE; 309*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32); 310*0b57cec5SDimitry Andric break; 311*0b57cec5SDimitry Andric } 312*0b57cec5SDimitry Andric case 0xb2: { 313*0b57cec5SDimitry Andric uint32_t addend = 0; 314*0b57cec5SDimitry Andric uint32_t shift = 0; 315*0b57cec5SDimitry Andric // This decodes a uleb128 value. 316*0b57cec5SDimitry Andric while (true) { 317*0b57cec5SDimitry Andric if (offset >= len) 318*0b57cec5SDimitry Andric return _URC_FAILURE; 319*0b57cec5SDimitry Andric uint32_t v = getByte(data, offset++); 320*0b57cec5SDimitry Andric addend |= (v & 0x7f) << shift; 321*0b57cec5SDimitry Andric if ((v & 0x80) == 0) 322*0b57cec5SDimitry Andric break; 323*0b57cec5SDimitry Andric shift += 7; 324*0b57cec5SDimitry Andric } 325*0b57cec5SDimitry Andric uint32_t sp; 326*0b57cec5SDimitry Andric _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, 327*0b57cec5SDimitry Andric &sp); 328*0b57cec5SDimitry Andric sp += 0x204 + (addend << 2); 329*0b57cec5SDimitry Andric _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, 330*0b57cec5SDimitry Andric &sp); 331*0b57cec5SDimitry Andric break; 332*0b57cec5SDimitry Andric } 333*0b57cec5SDimitry Andric case 0xb3: { 334*0b57cec5SDimitry Andric uint8_t v = getByte(data, offset++); 335*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_VFP, 336*0b57cec5SDimitry Andric RegisterRange(static_cast<uint8_t>(v >> 4), 337*0b57cec5SDimitry Andric v & 0x0f), _UVRSD_VFPX); 338*0b57cec5SDimitry Andric break; 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric case 0xb4: 341*0b57cec5SDimitry Andric case 0xb5: 342*0b57cec5SDimitry Andric case 0xb6: 343*0b57cec5SDimitry Andric case 0xb7: 344*0b57cec5SDimitry Andric return _URC_FAILURE; 345*0b57cec5SDimitry Andric default: 346*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_VFP, 347*0b57cec5SDimitry Andric RegisterRange(8, byte & 0x07), _UVRSD_VFPX); 348*0b57cec5SDimitry Andric break; 349*0b57cec5SDimitry Andric } 350*0b57cec5SDimitry Andric break; 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric case 0xc0: { 353*0b57cec5SDimitry Andric switch (byte) { 354*0b57cec5SDimitry Andric #if defined(__ARM_WMMX) 355*0b57cec5SDimitry Andric case 0xc0: 356*0b57cec5SDimitry Andric case 0xc1: 357*0b57cec5SDimitry Andric case 0xc2: 358*0b57cec5SDimitry Andric case 0xc3: 359*0b57cec5SDimitry Andric case 0xc4: 360*0b57cec5SDimitry Andric case 0xc5: 361*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_WMMXD, 362*0b57cec5SDimitry Andric RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE); 363*0b57cec5SDimitry Andric break; 364*0b57cec5SDimitry Andric case 0xc6: { 365*0b57cec5SDimitry Andric uint8_t v = getByte(data, offset++); 366*0b57cec5SDimitry Andric uint8_t start = static_cast<uint8_t>(v >> 4); 367*0b57cec5SDimitry Andric uint8_t count_minus_one = v & 0xf; 368*0b57cec5SDimitry Andric if (start + count_minus_one >= 16) 369*0b57cec5SDimitry Andric return _URC_FAILURE; 370*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_WMMXD, 371*0b57cec5SDimitry Andric RegisterRange(start, count_minus_one), 372*0b57cec5SDimitry Andric _UVRSD_DOUBLE); 373*0b57cec5SDimitry Andric break; 374*0b57cec5SDimitry Andric } 375*0b57cec5SDimitry Andric case 0xc7: { 376*0b57cec5SDimitry Andric uint8_t v = getByte(data, offset++); 377*0b57cec5SDimitry Andric if (!v || v & 0xf0) 378*0b57cec5SDimitry Andric return _URC_FAILURE; 379*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE); 380*0b57cec5SDimitry Andric break; 381*0b57cec5SDimitry Andric } 382*0b57cec5SDimitry Andric #endif 383*0b57cec5SDimitry Andric case 0xc8: 384*0b57cec5SDimitry Andric case 0xc9: { 385*0b57cec5SDimitry Andric uint8_t v = getByte(data, offset++); 386*0b57cec5SDimitry Andric uint8_t start = 387*0b57cec5SDimitry Andric static_cast<uint8_t>(((byte == 0xc8) ? 16 : 0) + (v >> 4)); 388*0b57cec5SDimitry Andric uint8_t count_minus_one = v & 0xf; 389*0b57cec5SDimitry Andric if (start + count_minus_one >= 32) 390*0b57cec5SDimitry Andric return _URC_FAILURE; 391*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_VFP, 392*0b57cec5SDimitry Andric RegisterRange(start, count_minus_one), 393*0b57cec5SDimitry Andric _UVRSD_DOUBLE); 394*0b57cec5SDimitry Andric break; 395*0b57cec5SDimitry Andric } 396*0b57cec5SDimitry Andric default: 397*0b57cec5SDimitry Andric return _URC_FAILURE; 398*0b57cec5SDimitry Andric } 399*0b57cec5SDimitry Andric break; 400*0b57cec5SDimitry Andric } 401*0b57cec5SDimitry Andric case 0xd0: { 402*0b57cec5SDimitry Andric if (byte & 0x08) 403*0b57cec5SDimitry Andric return _URC_FAILURE; 404*0b57cec5SDimitry Andric _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7), 405*0b57cec5SDimitry Andric _UVRSD_DOUBLE); 406*0b57cec5SDimitry Andric break; 407*0b57cec5SDimitry Andric } 408*0b57cec5SDimitry Andric default: 409*0b57cec5SDimitry Andric return _URC_FAILURE; 410*0b57cec5SDimitry Andric } 411*0b57cec5SDimitry Andric } 412*0b57cec5SDimitry Andric } 413*0b57cec5SDimitry Andric if (!wrotePC) { 414*0b57cec5SDimitry Andric uint32_t lr; 415*0b57cec5SDimitry Andric _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); 416*0b57cec5SDimitry Andric _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); 417*0b57cec5SDimitry Andric } 418*0b57cec5SDimitry Andric return _URC_CONTINUE_UNWIND; 419*0b57cec5SDimitry Andric } 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code 422*0b57cec5SDimitry Andric __aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp, 423*0b57cec5SDimitry Andric _Unwind_Context *context) { 424*0b57cec5SDimitry Andric return unwindOneFrame(state, ucbp, context); 425*0b57cec5SDimitry Andric } 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code 428*0b57cec5SDimitry Andric __aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp, 429*0b57cec5SDimitry Andric _Unwind_Context *context) { 430*0b57cec5SDimitry Andric return unwindOneFrame(state, ucbp, context); 431*0b57cec5SDimitry Andric } 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code 434*0b57cec5SDimitry Andric __aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp, 435*0b57cec5SDimitry Andric _Unwind_Context *context) { 436*0b57cec5SDimitry Andric return unwindOneFrame(state, ucbp, context); 437*0b57cec5SDimitry Andric } 438*0b57cec5SDimitry Andric 439*0b57cec5SDimitry Andric static _Unwind_Reason_Code 440*0b57cec5SDimitry Andric unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) { 441*0b57cec5SDimitry Andric // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during 442*0b57cec5SDimitry Andric // phase 1 and then restoring it to the "primary VRS" for phase 2. The 443*0b57cec5SDimitry Andric // effect is phase 2 doesn't see any of the VRS manipulations from phase 1. 444*0b57cec5SDimitry Andric // In this implementation, the phases don't share the VRS backing store. 445*0b57cec5SDimitry Andric // Instead, they are passed the original |uc| and they create a new VRS 446*0b57cec5SDimitry Andric // from scratch thus achieving the same effect. 447*0b57cec5SDimitry Andric __unw_init_local(cursor, uc); 448*0b57cec5SDimitry Andric 449*0b57cec5SDimitry Andric // Walk each frame looking for a place to stop. 450*0b57cec5SDimitry Andric for (bool handlerNotFound = true; handlerNotFound;) { 451*0b57cec5SDimitry Andric 452*0b57cec5SDimitry Andric // See if frame has code to run (has personality routine). 453*0b57cec5SDimitry Andric unw_proc_info_t frameInfo; 454*0b57cec5SDimitry Andric if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { 455*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 456*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): __unw_get_proc_info " 457*0b57cec5SDimitry Andric "failed => _URC_FATAL_PHASE1_ERROR", 458*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 459*0b57cec5SDimitry Andric return _URC_FATAL_PHASE1_ERROR; 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric // When tracing, print state information. 463*0b57cec5SDimitry Andric if (_LIBUNWIND_TRACING_UNWINDING) { 464*0b57cec5SDimitry Andric char functionBuf[512]; 465*0b57cec5SDimitry Andric const char *functionName = functionBuf; 466*0b57cec5SDimitry Andric unw_word_t offset; 467*0b57cec5SDimitry Andric if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), 468*0b57cec5SDimitry Andric &offset) != UNW_ESUCCESS) || 469*0b57cec5SDimitry Andric (frameInfo.start_ip + offset > frameInfo.end_ip)) 470*0b57cec5SDimitry Andric functionName = ".anonymous."; 471*0b57cec5SDimitry Andric unw_word_t pc; 472*0b57cec5SDimitry Andric __unw_get_reg(cursor, UNW_REG_IP, &pc); 473*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 474*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, " 475*0b57cec5SDimitry Andric "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, 476*0b57cec5SDimitry Andric static_cast<void *>(exception_object), pc, 477*0b57cec5SDimitry Andric frameInfo.start_ip, functionName, 478*0b57cec5SDimitry Andric frameInfo.lsda, frameInfo.handler); 479*0b57cec5SDimitry Andric } 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric // If there is a personality routine, ask it if it will want to stop at 482*0b57cec5SDimitry Andric // this frame. 483*0b57cec5SDimitry Andric if (frameInfo.handler != 0) { 484*0b57cec5SDimitry Andric __personality_routine p = 485*0b57cec5SDimitry Andric (__personality_routine)(long)(frameInfo.handler); 486*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 487*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): calling personality function %p", 488*0b57cec5SDimitry Andric static_cast<void *>(exception_object), 489*0b57cec5SDimitry Andric reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p))); 490*0b57cec5SDimitry Andric struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); 491*0b57cec5SDimitry Andric exception_object->pr_cache.fnstart = frameInfo.start_ip; 492*0b57cec5SDimitry Andric exception_object->pr_cache.ehtp = 493*0b57cec5SDimitry Andric (_Unwind_EHT_Header *)frameInfo.unwind_info; 494*0b57cec5SDimitry Andric exception_object->pr_cache.additional = frameInfo.flags; 495*0b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = 496*0b57cec5SDimitry Andric (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context); 497*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 498*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p " 499*0b57cec5SDimitry Andric "additional %x", 500*0b57cec5SDimitry Andric static_cast<void *>(exception_object), personalityResult, 501*0b57cec5SDimitry Andric exception_object->pr_cache.fnstart, 502*0b57cec5SDimitry Andric static_cast<void *>(exception_object->pr_cache.ehtp), 503*0b57cec5SDimitry Andric exception_object->pr_cache.additional); 504*0b57cec5SDimitry Andric switch (personalityResult) { 505*0b57cec5SDimitry Andric case _URC_HANDLER_FOUND: 506*0b57cec5SDimitry Andric // found a catch clause or locals that need destructing in this frame 507*0b57cec5SDimitry Andric // stop search and remember stack pointer at the frame 508*0b57cec5SDimitry Andric handlerNotFound = false; 509*0b57cec5SDimitry Andric // p should have initialized barrier_cache. EHABI #7.3.5 510*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 511*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND", 512*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 513*0b57cec5SDimitry Andric return _URC_NO_REASON; 514*0b57cec5SDimitry Andric 515*0b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 516*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 517*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND", 518*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 519*0b57cec5SDimitry Andric // continue unwinding 520*0b57cec5SDimitry Andric break; 521*0b57cec5SDimitry Andric 522*0b57cec5SDimitry Andric // EHABI #7.3.3 523*0b57cec5SDimitry Andric case _URC_FAILURE: 524*0b57cec5SDimitry Andric return _URC_FAILURE; 525*0b57cec5SDimitry Andric 526*0b57cec5SDimitry Andric default: 527*0b57cec5SDimitry Andric // something went wrong 528*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 529*0b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", 530*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 531*0b57cec5SDimitry Andric return _URC_FATAL_PHASE1_ERROR; 532*0b57cec5SDimitry Andric } 533*0b57cec5SDimitry Andric } 534*0b57cec5SDimitry Andric } 535*0b57cec5SDimitry Andric return _URC_NO_REASON; 536*0b57cec5SDimitry Andric } 537*0b57cec5SDimitry Andric 538*0b57cec5SDimitry Andric static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, 539*0b57cec5SDimitry Andric _Unwind_Exception *exception_object, 540*0b57cec5SDimitry Andric bool resume) { 541*0b57cec5SDimitry Andric // See comment at the start of unwind_phase1 regarding VRS integrity. 542*0b57cec5SDimitry Andric __unw_init_local(cursor, uc); 543*0b57cec5SDimitry Andric 544*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", 545*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 546*0b57cec5SDimitry Andric int frame_count = 0; 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric // Walk each frame until we reach where search phase said to stop. 549*0b57cec5SDimitry Andric while (true) { 550*0b57cec5SDimitry Andric // Ask libunwind to get next frame (skip over first which is 551*0b57cec5SDimitry Andric // _Unwind_RaiseException or _Unwind_Resume). 552*0b57cec5SDimitry Andric // 553*0b57cec5SDimitry Andric // Resume only ever makes sense for 1 frame. 554*0b57cec5SDimitry Andric _Unwind_State state = 555*0b57cec5SDimitry Andric resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; 556*0b57cec5SDimitry Andric if (resume && frame_count == 1) { 557*0b57cec5SDimitry Andric // On a resume, first unwind the _Unwind_Resume() frame. The next frame 558*0b57cec5SDimitry Andric // is now the landing pad for the cleanup from a previous execution of 559*0b57cec5SDimitry Andric // phase2. To continue unwindingly correctly, replace VRS[15] with the 560*0b57cec5SDimitry Andric // IP of the frame that the previous run of phase2 installed the context 561*0b57cec5SDimitry Andric // for. After this, continue unwinding as if normal. 562*0b57cec5SDimitry Andric // 563*0b57cec5SDimitry Andric // See #7.4.6 for details. 564*0b57cec5SDimitry Andric __unw_set_reg(cursor, UNW_REG_IP, 565*0b57cec5SDimitry Andric exception_object->unwinder_cache.reserved2); 566*0b57cec5SDimitry Andric resume = false; 567*0b57cec5SDimitry Andric } 568*0b57cec5SDimitry Andric 569*0b57cec5SDimitry Andric // Get info about this frame. 570*0b57cec5SDimitry Andric unw_word_t sp; 571*0b57cec5SDimitry Andric unw_proc_info_t frameInfo; 572*0b57cec5SDimitry Andric __unw_get_reg(cursor, UNW_REG_SP, &sp); 573*0b57cec5SDimitry Andric if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) { 574*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 575*0b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): __unw_get_proc_info " 576*0b57cec5SDimitry Andric "failed => _URC_FATAL_PHASE2_ERROR", 577*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 578*0b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 579*0b57cec5SDimitry Andric } 580*0b57cec5SDimitry Andric 581*0b57cec5SDimitry Andric // When tracing, print state information. 582*0b57cec5SDimitry Andric if (_LIBUNWIND_TRACING_UNWINDING) { 583*0b57cec5SDimitry Andric char functionBuf[512]; 584*0b57cec5SDimitry Andric const char *functionName = functionBuf; 585*0b57cec5SDimitry Andric unw_word_t offset; 586*0b57cec5SDimitry Andric if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf), 587*0b57cec5SDimitry Andric &offset) != UNW_ESUCCESS) || 588*0b57cec5SDimitry Andric (frameInfo.start_ip + offset > frameInfo.end_ip)) 589*0b57cec5SDimitry Andric functionName = ".anonymous."; 590*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 591*0b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", " 592*0b57cec5SDimitry Andric "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "", 593*0b57cec5SDimitry Andric static_cast<void *>(exception_object), frameInfo.start_ip, 594*0b57cec5SDimitry Andric functionName, sp, frameInfo.lsda, 595*0b57cec5SDimitry Andric frameInfo.handler); 596*0b57cec5SDimitry Andric } 597*0b57cec5SDimitry Andric 598*0b57cec5SDimitry Andric // If there is a personality routine, tell it we are unwinding. 599*0b57cec5SDimitry Andric if (frameInfo.handler != 0) { 600*0b57cec5SDimitry Andric __personality_routine p = 601*0b57cec5SDimitry Andric (__personality_routine)(long)(frameInfo.handler); 602*0b57cec5SDimitry Andric struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor); 603*0b57cec5SDimitry Andric // EHABI #7.2 604*0b57cec5SDimitry Andric exception_object->pr_cache.fnstart = frameInfo.start_ip; 605*0b57cec5SDimitry Andric exception_object->pr_cache.ehtp = 606*0b57cec5SDimitry Andric (_Unwind_EHT_Header *)frameInfo.unwind_info; 607*0b57cec5SDimitry Andric exception_object->pr_cache.additional = frameInfo.flags; 608*0b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = 609*0b57cec5SDimitry Andric (*p)(state, exception_object, context); 610*0b57cec5SDimitry Andric switch (personalityResult) { 611*0b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 612*0b57cec5SDimitry Andric // Continue unwinding 613*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 614*0b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", 615*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 616*0b57cec5SDimitry Andric // EHABI #7.2 617*0b57cec5SDimitry Andric if (sp == exception_object->barrier_cache.sp) { 618*0b57cec5SDimitry Andric // Phase 1 said we would stop at this frame, but we did not... 619*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("during phase1 personality function said it would " 620*0b57cec5SDimitry Andric "stop here, but now in phase2 it did not stop here"); 621*0b57cec5SDimitry Andric } 622*0b57cec5SDimitry Andric break; 623*0b57cec5SDimitry Andric case _URC_INSTALL_CONTEXT: 624*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 625*0b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT", 626*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 627*0b57cec5SDimitry Andric // Personality routine says to transfer control to landing pad. 628*0b57cec5SDimitry Andric // We may get control back if landing pad calls _Unwind_Resume(). 629*0b57cec5SDimitry Andric if (_LIBUNWIND_TRACING_UNWINDING) { 630*0b57cec5SDimitry Andric unw_word_t pc; 631*0b57cec5SDimitry Andric __unw_get_reg(cursor, UNW_REG_IP, &pc); 632*0b57cec5SDimitry Andric __unw_get_reg(cursor, UNW_REG_SP, &sp); 633*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " 634*0b57cec5SDimitry Andric "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR, 635*0b57cec5SDimitry Andric static_cast<void *>(exception_object), 636*0b57cec5SDimitry Andric pc, sp); 637*0b57cec5SDimitry Andric } 638*0b57cec5SDimitry Andric 639*0b57cec5SDimitry Andric { 640*0b57cec5SDimitry Andric // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume 641*0b57cec5SDimitry Andric // is called back, to find this same frame. 642*0b57cec5SDimitry Andric unw_word_t pc; 643*0b57cec5SDimitry Andric __unw_get_reg(cursor, UNW_REG_IP, &pc); 644*0b57cec5SDimitry Andric exception_object->unwinder_cache.reserved2 = (uint32_t)pc; 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric __unw_resume(cursor); 647*0b57cec5SDimitry Andric // __unw_resume() only returns if there was an error. 648*0b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 649*0b57cec5SDimitry Andric 650*0b57cec5SDimitry Andric // # EHABI #7.4.3 651*0b57cec5SDimitry Andric case _URC_FAILURE: 652*0b57cec5SDimitry Andric abort(); 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric default: 655*0b57cec5SDimitry Andric // Personality routine returned an unknown result code. 656*0b57cec5SDimitry Andric _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", 657*0b57cec5SDimitry Andric personalityResult); 658*0b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 659*0b57cec5SDimitry Andric } 660*0b57cec5SDimitry Andric } 661*0b57cec5SDimitry Andric frame_count++; 662*0b57cec5SDimitry Andric } 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric // Clean up phase did not resume at the frame that the search phase 665*0b57cec5SDimitry Andric // said it would... 666*0b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 667*0b57cec5SDimitry Andric } 668*0b57cec5SDimitry Andric 669*0b57cec5SDimitry Andric /// Called by __cxa_throw. Only returns if there is a fatal error. 670*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 671*0b57cec5SDimitry Andric _Unwind_RaiseException(_Unwind_Exception *exception_object) { 672*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", 673*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 674*0b57cec5SDimitry Andric unw_context_t uc; 675*0b57cec5SDimitry Andric unw_cursor_t cursor; 676*0b57cec5SDimitry Andric __unw_getcontext(&uc); 677*0b57cec5SDimitry Andric 678*0b57cec5SDimitry Andric // This field for is for compatibility with GCC to say this isn't a forced 679*0b57cec5SDimitry Andric // unwind. EHABI #7.2 680*0b57cec5SDimitry Andric exception_object->unwinder_cache.reserved1 = 0; 681*0b57cec5SDimitry Andric 682*0b57cec5SDimitry Andric // phase 1: the search phase 683*0b57cec5SDimitry Andric _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object); 684*0b57cec5SDimitry Andric if (phase1 != _URC_NO_REASON) 685*0b57cec5SDimitry Andric return phase1; 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric // phase 2: the clean up phase 688*0b57cec5SDimitry Andric return unwind_phase2(&uc, &cursor, exception_object, false); 689*0b57cec5SDimitry Andric } 690*0b57cec5SDimitry Andric 691*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) { 692*0b57cec5SDimitry Andric // This is to be called when exception handling completes to give us a chance 693*0b57cec5SDimitry Andric // to perform any housekeeping. EHABI #7.2. But we have nothing to do here. 694*0b57cec5SDimitry Andric (void)exception_object; 695*0b57cec5SDimitry Andric } 696*0b57cec5SDimitry Andric 697*0b57cec5SDimitry Andric /// When _Unwind_RaiseException() is in phase2, it hands control 698*0b57cec5SDimitry Andric /// to the personality function at each frame. The personality 699*0b57cec5SDimitry Andric /// may force a jump to a landing pad in that function, the landing 700*0b57cec5SDimitry Andric /// pad code may then call _Unwind_Resume() to continue with the 701*0b57cec5SDimitry Andric /// unwinding. Note: the call to _Unwind_Resume() is from compiler 702*0b57cec5SDimitry Andric /// geneated user code. All other _Unwind_* routines are called 703*0b57cec5SDimitry Andric /// by the C++ runtime __cxa_* routines. 704*0b57cec5SDimitry Andric /// 705*0b57cec5SDimitry Andric /// Note: re-throwing an exception (as opposed to continuing the unwind) 706*0b57cec5SDimitry Andric /// is implemented by having the code call __cxa_rethrow() which 707*0b57cec5SDimitry Andric /// in turn calls _Unwind_Resume_or_Rethrow(). 708*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 709*0b57cec5SDimitry Andric _Unwind_Resume(_Unwind_Exception *exception_object) { 710*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", 711*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 712*0b57cec5SDimitry Andric unw_context_t uc; 713*0b57cec5SDimitry Andric unw_cursor_t cursor; 714*0b57cec5SDimitry Andric __unw_getcontext(&uc); 715*0b57cec5SDimitry Andric 716*0b57cec5SDimitry Andric // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, 717*0b57cec5SDimitry Andric // which is in the same position as private_1 below. 718*0b57cec5SDimitry Andric // TODO(ajwong): Who wronte the above? Why is it true? 719*0b57cec5SDimitry Andric unwind_phase2(&uc, &cursor, exception_object, true); 720*0b57cec5SDimitry Andric 721*0b57cec5SDimitry Andric // Clients assume _Unwind_Resume() does not return, so all we can do is abort. 722*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); 723*0b57cec5SDimitry Andric } 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get LSDA for current frame. 726*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 727*0b57cec5SDimitry Andric _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { 728*0b57cec5SDimitry Andric unw_cursor_t *cursor = (unw_cursor_t *)context; 729*0b57cec5SDimitry Andric unw_proc_info_t frameInfo; 730*0b57cec5SDimitry Andric uintptr_t result = 0; 731*0b57cec5SDimitry Andric if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) 732*0b57cec5SDimitry Andric result = (uintptr_t)frameInfo.lsda; 733*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API( 734*0b57cec5SDimitry Andric "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx", 735*0b57cec5SDimitry Andric static_cast<void *>(context), (long long)result); 736*0b57cec5SDimitry Andric return result; 737*0b57cec5SDimitry Andric } 738*0b57cec5SDimitry Andric 739*0b57cec5SDimitry Andric static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation, 740*0b57cec5SDimitry Andric void* valuep) { 741*0b57cec5SDimitry Andric uint64_t value = 0; 742*0b57cec5SDimitry Andric switch (representation) { 743*0b57cec5SDimitry Andric case _UVRSD_UINT32: 744*0b57cec5SDimitry Andric case _UVRSD_FLOAT: 745*0b57cec5SDimitry Andric memcpy(&value, valuep, sizeof(uint32_t)); 746*0b57cec5SDimitry Andric break; 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric case _UVRSD_VFPX: 749*0b57cec5SDimitry Andric case _UVRSD_UINT64: 750*0b57cec5SDimitry Andric case _UVRSD_DOUBLE: 751*0b57cec5SDimitry Andric memcpy(&value, valuep, sizeof(uint64_t)); 752*0b57cec5SDimitry Andric break; 753*0b57cec5SDimitry Andric } 754*0b57cec5SDimitry Andric return value; 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_VRS_Result 758*0b57cec5SDimitry Andric _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, 759*0b57cec5SDimitry Andric uint32_t regno, _Unwind_VRS_DataRepresentation representation, 760*0b57cec5SDimitry Andric void *valuep) { 761*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, " 762*0b57cec5SDimitry Andric "rep=%d, value=0x%llX)", 763*0b57cec5SDimitry Andric static_cast<void *>(context), regclass, regno, 764*0b57cec5SDimitry Andric representation, 765*0b57cec5SDimitry Andric ValueAsBitPattern(representation, valuep)); 766*0b57cec5SDimitry Andric unw_cursor_t *cursor = (unw_cursor_t *)context; 767*0b57cec5SDimitry Andric switch (regclass) { 768*0b57cec5SDimitry Andric case _UVRSC_CORE: 769*0b57cec5SDimitry Andric if (representation != _UVRSD_UINT32 || regno > 15) 770*0b57cec5SDimitry Andric return _UVRSR_FAILED; 771*0b57cec5SDimitry Andric return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), 772*0b57cec5SDimitry Andric *(unw_word_t *)valuep) == UNW_ESUCCESS 773*0b57cec5SDimitry Andric ? _UVRSR_OK 774*0b57cec5SDimitry Andric : _UVRSR_FAILED; 775*0b57cec5SDimitry Andric case _UVRSC_VFP: 776*0b57cec5SDimitry Andric if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) 777*0b57cec5SDimitry Andric return _UVRSR_FAILED; 778*0b57cec5SDimitry Andric if (representation == _UVRSD_VFPX) { 779*0b57cec5SDimitry Andric // Can only touch d0-15 with FSTMFDX. 780*0b57cec5SDimitry Andric if (regno > 15) 781*0b57cec5SDimitry Andric return _UVRSR_FAILED; 782*0b57cec5SDimitry Andric __unw_save_vfp_as_X(cursor); 783*0b57cec5SDimitry Andric } else { 784*0b57cec5SDimitry Andric if (regno > 31) 785*0b57cec5SDimitry Andric return _UVRSR_FAILED; 786*0b57cec5SDimitry Andric } 787*0b57cec5SDimitry Andric return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), 788*0b57cec5SDimitry Andric *(unw_fpreg_t *)valuep) == UNW_ESUCCESS 789*0b57cec5SDimitry Andric ? _UVRSR_OK 790*0b57cec5SDimitry Andric : _UVRSR_FAILED; 791*0b57cec5SDimitry Andric #if defined(__ARM_WMMX) 792*0b57cec5SDimitry Andric case _UVRSC_WMMXC: 793*0b57cec5SDimitry Andric if (representation != _UVRSD_UINT32 || regno > 3) 794*0b57cec5SDimitry Andric return _UVRSR_FAILED; 795*0b57cec5SDimitry Andric return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), 796*0b57cec5SDimitry Andric *(unw_word_t *)valuep) == UNW_ESUCCESS 797*0b57cec5SDimitry Andric ? _UVRSR_OK 798*0b57cec5SDimitry Andric : _UVRSR_FAILED; 799*0b57cec5SDimitry Andric case _UVRSC_WMMXD: 800*0b57cec5SDimitry Andric if (representation != _UVRSD_DOUBLE || regno > 31) 801*0b57cec5SDimitry Andric return _UVRSR_FAILED; 802*0b57cec5SDimitry Andric return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), 803*0b57cec5SDimitry Andric *(unw_fpreg_t *)valuep) == UNW_ESUCCESS 804*0b57cec5SDimitry Andric ? _UVRSR_OK 805*0b57cec5SDimitry Andric : _UVRSR_FAILED; 806*0b57cec5SDimitry Andric #else 807*0b57cec5SDimitry Andric case _UVRSC_WMMXC: 808*0b57cec5SDimitry Andric case _UVRSC_WMMXD: 809*0b57cec5SDimitry Andric break; 810*0b57cec5SDimitry Andric #endif 811*0b57cec5SDimitry Andric } 812*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("unsupported register class"); 813*0b57cec5SDimitry Andric } 814*0b57cec5SDimitry Andric 815*0b57cec5SDimitry Andric static _Unwind_VRS_Result 816*0b57cec5SDimitry Andric _Unwind_VRS_Get_Internal(_Unwind_Context *context, 817*0b57cec5SDimitry Andric _Unwind_VRS_RegClass regclass, uint32_t regno, 818*0b57cec5SDimitry Andric _Unwind_VRS_DataRepresentation representation, 819*0b57cec5SDimitry Andric void *valuep) { 820*0b57cec5SDimitry Andric unw_cursor_t *cursor = (unw_cursor_t *)context; 821*0b57cec5SDimitry Andric switch (regclass) { 822*0b57cec5SDimitry Andric case _UVRSC_CORE: 823*0b57cec5SDimitry Andric if (representation != _UVRSD_UINT32 || regno > 15) 824*0b57cec5SDimitry Andric return _UVRSR_FAILED; 825*0b57cec5SDimitry Andric return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno), 826*0b57cec5SDimitry Andric (unw_word_t *)valuep) == UNW_ESUCCESS 827*0b57cec5SDimitry Andric ? _UVRSR_OK 828*0b57cec5SDimitry Andric : _UVRSR_FAILED; 829*0b57cec5SDimitry Andric case _UVRSC_VFP: 830*0b57cec5SDimitry Andric if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) 831*0b57cec5SDimitry Andric return _UVRSR_FAILED; 832*0b57cec5SDimitry Andric if (representation == _UVRSD_VFPX) { 833*0b57cec5SDimitry Andric // Can only touch d0-15 with FSTMFDX. 834*0b57cec5SDimitry Andric if (regno > 15) 835*0b57cec5SDimitry Andric return _UVRSR_FAILED; 836*0b57cec5SDimitry Andric __unw_save_vfp_as_X(cursor); 837*0b57cec5SDimitry Andric } else { 838*0b57cec5SDimitry Andric if (regno > 31) 839*0b57cec5SDimitry Andric return _UVRSR_FAILED; 840*0b57cec5SDimitry Andric } 841*0b57cec5SDimitry Andric return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno), 842*0b57cec5SDimitry Andric (unw_fpreg_t *)valuep) == UNW_ESUCCESS 843*0b57cec5SDimitry Andric ? _UVRSR_OK 844*0b57cec5SDimitry Andric : _UVRSR_FAILED; 845*0b57cec5SDimitry Andric #if defined(__ARM_WMMX) 846*0b57cec5SDimitry Andric case _UVRSC_WMMXC: 847*0b57cec5SDimitry Andric if (representation != _UVRSD_UINT32 || regno > 3) 848*0b57cec5SDimitry Andric return _UVRSR_FAILED; 849*0b57cec5SDimitry Andric return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno), 850*0b57cec5SDimitry Andric (unw_word_t *)valuep) == UNW_ESUCCESS 851*0b57cec5SDimitry Andric ? _UVRSR_OK 852*0b57cec5SDimitry Andric : _UVRSR_FAILED; 853*0b57cec5SDimitry Andric case _UVRSC_WMMXD: 854*0b57cec5SDimitry Andric if (representation != _UVRSD_DOUBLE || regno > 31) 855*0b57cec5SDimitry Andric return _UVRSR_FAILED; 856*0b57cec5SDimitry Andric return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno), 857*0b57cec5SDimitry Andric (unw_fpreg_t *)valuep) == UNW_ESUCCESS 858*0b57cec5SDimitry Andric ? _UVRSR_OK 859*0b57cec5SDimitry Andric : _UVRSR_FAILED; 860*0b57cec5SDimitry Andric #else 861*0b57cec5SDimitry Andric case _UVRSC_WMMXC: 862*0b57cec5SDimitry Andric case _UVRSC_WMMXD: 863*0b57cec5SDimitry Andric break; 864*0b57cec5SDimitry Andric #endif 865*0b57cec5SDimitry Andric } 866*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("unsupported register class"); 867*0b57cec5SDimitry Andric } 868*0b57cec5SDimitry Andric 869*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_VRS_Result 870*0b57cec5SDimitry Andric _Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, 871*0b57cec5SDimitry Andric uint32_t regno, _Unwind_VRS_DataRepresentation representation, 872*0b57cec5SDimitry Andric void *valuep) { 873*0b57cec5SDimitry Andric _Unwind_VRS_Result result = 874*0b57cec5SDimitry Andric _Unwind_VRS_Get_Internal(context, regclass, regno, representation, 875*0b57cec5SDimitry Andric valuep); 876*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, " 877*0b57cec5SDimitry Andric "rep=%d, value=0x%llX, result = %d)", 878*0b57cec5SDimitry Andric static_cast<void *>(context), regclass, regno, 879*0b57cec5SDimitry Andric representation, 880*0b57cec5SDimitry Andric ValueAsBitPattern(representation, valuep), result); 881*0b57cec5SDimitry Andric return result; 882*0b57cec5SDimitry Andric } 883*0b57cec5SDimitry Andric 884*0b57cec5SDimitry Andric _Unwind_VRS_Result 885*0b57cec5SDimitry Andric _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, 886*0b57cec5SDimitry Andric uint32_t discriminator, 887*0b57cec5SDimitry Andric _Unwind_VRS_DataRepresentation representation) { 888*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, " 889*0b57cec5SDimitry Andric "discriminator=%d, representation=%d)", 890*0b57cec5SDimitry Andric static_cast<void *>(context), regclass, discriminator, 891*0b57cec5SDimitry Andric representation); 892*0b57cec5SDimitry Andric switch (regclass) { 893*0b57cec5SDimitry Andric case _UVRSC_WMMXC: 894*0b57cec5SDimitry Andric #if !defined(__ARM_WMMX) 895*0b57cec5SDimitry Andric break; 896*0b57cec5SDimitry Andric #endif 897*0b57cec5SDimitry Andric case _UVRSC_CORE: { 898*0b57cec5SDimitry Andric if (representation != _UVRSD_UINT32) 899*0b57cec5SDimitry Andric return _UVRSR_FAILED; 900*0b57cec5SDimitry Andric // When popping SP from the stack, we don't want to override it from the 901*0b57cec5SDimitry Andric // computed new stack location. See EHABI #7.5.4 table 3. 902*0b57cec5SDimitry Andric bool poppedSP = false; 903*0b57cec5SDimitry Andric uint32_t* sp; 904*0b57cec5SDimitry Andric if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, 905*0b57cec5SDimitry Andric _UVRSD_UINT32, &sp) != _UVRSR_OK) { 906*0b57cec5SDimitry Andric return _UVRSR_FAILED; 907*0b57cec5SDimitry Andric } 908*0b57cec5SDimitry Andric for (uint32_t i = 0; i < 16; ++i) { 909*0b57cec5SDimitry Andric if (!(discriminator & static_cast<uint32_t>(1 << i))) 910*0b57cec5SDimitry Andric continue; 911*0b57cec5SDimitry Andric uint32_t value = *sp++; 912*0b57cec5SDimitry Andric if (regclass == _UVRSC_CORE && i == 13) 913*0b57cec5SDimitry Andric poppedSP = true; 914*0b57cec5SDimitry Andric if (_Unwind_VRS_Set(context, regclass, i, 915*0b57cec5SDimitry Andric _UVRSD_UINT32, &value) != _UVRSR_OK) { 916*0b57cec5SDimitry Andric return _UVRSR_FAILED; 917*0b57cec5SDimitry Andric } 918*0b57cec5SDimitry Andric } 919*0b57cec5SDimitry Andric if (!poppedSP) { 920*0b57cec5SDimitry Andric return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, 921*0b57cec5SDimitry Andric _UVRSD_UINT32, &sp); 922*0b57cec5SDimitry Andric } 923*0b57cec5SDimitry Andric return _UVRSR_OK; 924*0b57cec5SDimitry Andric } 925*0b57cec5SDimitry Andric case _UVRSC_WMMXD: 926*0b57cec5SDimitry Andric #if !defined(__ARM_WMMX) 927*0b57cec5SDimitry Andric break; 928*0b57cec5SDimitry Andric #endif 929*0b57cec5SDimitry Andric case _UVRSC_VFP: { 930*0b57cec5SDimitry Andric if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) 931*0b57cec5SDimitry Andric return _UVRSR_FAILED; 932*0b57cec5SDimitry Andric uint32_t first = discriminator >> 16; 933*0b57cec5SDimitry Andric uint32_t count = discriminator & 0xffff; 934*0b57cec5SDimitry Andric uint32_t end = first+count; 935*0b57cec5SDimitry Andric uint32_t* sp; 936*0b57cec5SDimitry Andric if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, 937*0b57cec5SDimitry Andric _UVRSD_UINT32, &sp) != _UVRSR_OK) { 938*0b57cec5SDimitry Andric return _UVRSR_FAILED; 939*0b57cec5SDimitry Andric } 940*0b57cec5SDimitry Andric // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard 941*0b57cec5SDimitry Andric // format 1", which is equivalent to FSTMD + a padding word. 942*0b57cec5SDimitry Andric for (uint32_t i = first; i < end; ++i) { 943*0b57cec5SDimitry Andric // SP is only 32-bit aligned so don't copy 64-bit at a time. 944*0b57cec5SDimitry Andric uint64_t value = *sp++; 945*0b57cec5SDimitry Andric value |= ((uint64_t)(*sp++)) << 32; 946*0b57cec5SDimitry Andric if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != 947*0b57cec5SDimitry Andric _UVRSR_OK) 948*0b57cec5SDimitry Andric return _UVRSR_FAILED; 949*0b57cec5SDimitry Andric } 950*0b57cec5SDimitry Andric if (representation == _UVRSD_VFPX) 951*0b57cec5SDimitry Andric ++sp; 952*0b57cec5SDimitry Andric return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, 953*0b57cec5SDimitry Andric &sp); 954*0b57cec5SDimitry Andric } 955*0b57cec5SDimitry Andric } 956*0b57cec5SDimitry Andric _LIBUNWIND_ABORT("unsupported register class"); 957*0b57cec5SDimitry Andric } 958*0b57cec5SDimitry Andric 959*0b57cec5SDimitry Andric /// Called by personality handler during phase 2 to find the start of the 960*0b57cec5SDimitry Andric /// function. 961*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 962*0b57cec5SDimitry Andric _Unwind_GetRegionStart(struct _Unwind_Context *context) { 963*0b57cec5SDimitry Andric unw_cursor_t *cursor = (unw_cursor_t *)context; 964*0b57cec5SDimitry Andric unw_proc_info_t frameInfo; 965*0b57cec5SDimitry Andric uintptr_t result = 0; 966*0b57cec5SDimitry Andric if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) 967*0b57cec5SDimitry Andric result = (uintptr_t)frameInfo.start_ip; 968*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX", 969*0b57cec5SDimitry Andric static_cast<void *>(context), (long long)result); 970*0b57cec5SDimitry Andric return result; 971*0b57cec5SDimitry Andric } 972*0b57cec5SDimitry Andric 973*0b57cec5SDimitry Andric 974*0b57cec5SDimitry Andric /// Called by personality handler during phase 2 if a foreign exception 975*0b57cec5SDimitry Andric // is caught. 976*0b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 977*0b57cec5SDimitry Andric _Unwind_DeleteException(_Unwind_Exception *exception_object) { 978*0b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", 979*0b57cec5SDimitry Andric static_cast<void *>(exception_object)); 980*0b57cec5SDimitry Andric if (exception_object->exception_cleanup != NULL) 981*0b57cec5SDimitry Andric (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, 982*0b57cec5SDimitry Andric exception_object); 983*0b57cec5SDimitry Andric } 984*0b57cec5SDimitry Andric 985*0b57cec5SDimitry Andric extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code 986*0b57cec5SDimitry Andric __gnu_unwind_frame(_Unwind_Exception *exception_object, 987*0b57cec5SDimitry Andric struct _Unwind_Context *context) { 988*0b57cec5SDimitry Andric unw_cursor_t *cursor = (unw_cursor_t *)context; 989*0b57cec5SDimitry Andric if (__unw_step(cursor) != UNW_STEP_SUCCESS) 990*0b57cec5SDimitry Andric return _URC_FAILURE; 991*0b57cec5SDimitry Andric return _URC_OK; 992*0b57cec5SDimitry Andric } 993*0b57cec5SDimitry Andric 994*0b57cec5SDimitry Andric #endif // defined(_LIBUNWIND_ARM_EHABI) 995