Path: blob/main/contrib/llvm-project/libunwind/src/Unwind-EHABI.cpp
35148 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//7// Implements ARM zero-cost C++ exceptions8//9//===----------------------------------------------------------------------===//1011#include "Unwind-EHABI.h"1213#if defined(_LIBUNWIND_ARM_EHABI)1415#include <inttypes.h>16#include <stdbool.h>17#include <stdint.h>18#include <stdio.h>19#include <stdlib.h>20#include <string.h>2122#include "config.h"23#include "libunwind.h"24#include "libunwind_ext.h"25#include "unwind.h"2627namespace {2829// Strange order: take words in order, but inside word, take from most to least30// signinficant byte.31uint8_t getByte(const uint32_t* data, size_t offset) {32const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data);33#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__34return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))];35#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__36return byteData[offset];37#else38#error "Unable to determine endianess"39#endif40}4142const char* getNextWord(const char* data, uint32_t* out) {43*out = *reinterpret_cast<const uint32_t*>(data);44return data + 4;45}4647const char* getNextNibble(const char* data, uint32_t* out) {48*out = *reinterpret_cast<const uint16_t*>(data);49return data + 2;50}5152struct Descriptor {53// See # 9.254typedef enum {55SU16 = 0, // Short descriptor, 16-bit entries56LU16 = 1, // Long descriptor, 16-bit entries57LU32 = 3, // Long descriptor, 32-bit entries58RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7,59RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11,60RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 1561} Format;6263// See # 9.264typedef enum {65CLEANUP = 0x0,66FUNC = 0x1,67CATCH = 0x2,68INVALID = 0x469} Kind;70};7172_Unwind_Reason_Code ProcessDescriptors(73_Unwind_State state,74_Unwind_Control_Block* ucbp,75struct _Unwind_Context* context,76Descriptor::Format format,77const char* descriptorStart,78uint32_t flags) {7980// EHT is inlined in the index using compact form. No descriptors. #581if (flags & 0x1)82return _URC_CONTINUE_UNWIND;8384// TODO: We should check the state here, and determine whether we need to85// perform phase1 or phase2 unwinding.86(void)state;8788const char* descriptor = descriptorStart;89uint32_t descriptorWord;90getNextWord(descriptor, &descriptorWord);91while (descriptorWord) {92// Read descriptor based on # 9.2.93uint32_t length;94uint32_t offset;95switch (format) {96case Descriptor::LU32:97descriptor = getNextWord(descriptor, &length);98descriptor = getNextWord(descriptor, &offset);99break;100case Descriptor::LU16:101descriptor = getNextNibble(descriptor, &length);102descriptor = getNextNibble(descriptor, &offset);103break;104default:105assert(false);106return _URC_FAILURE;107}108109// See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value.110Descriptor::Kind kind =111static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1));112113// Clear off flag from last bit.114length &= ~1u;115offset &= ~1u;116uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset;117uintptr_t scopeEnd = scopeStart + length;118uintptr_t pc = _Unwind_GetIP(context);119bool isInScope = (scopeStart <= pc) && (pc < scopeEnd);120121switch (kind) {122case Descriptor::CLEANUP: {123// TODO(ajwong): Handle cleanup descriptors.124break;125}126case Descriptor::FUNC: {127// TODO(ajwong): Handle function descriptors.128break;129}130case Descriptor::CATCH: {131// Catch descriptors require gobbling one more word.132uint32_t landing_pad;133descriptor = getNextWord(descriptor, &landing_pad);134135if (isInScope) {136// TODO(ajwong): This is only phase1 compatible logic. Implement137// phase2.138landing_pad = signExtendPrel31(landing_pad & ~0x80000000);139if (landing_pad == 0xffffffff) {140return _URC_HANDLER_FOUND;141} else if (landing_pad == 0xfffffffe) {142return _URC_FAILURE;143} else {144/*145bool is_reference_type = landing_pad & 0x80000000;146void* matched_object;147if (__cxxabiv1::__cxa_type_match(148ucbp, reinterpret_cast<const std::type_info *>(landing_pad),149is_reference_type,150&matched_object) != __cxxabiv1::ctm_failed)151return _URC_HANDLER_FOUND;152*/153_LIBUNWIND_ABORT("Type matching not implemented");154}155}156break;157}158default:159_LIBUNWIND_ABORT("Invalid descriptor kind found.");160}161162getNextWord(descriptor, &descriptorWord);163}164165return _URC_CONTINUE_UNWIND;166}167168static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state,169_Unwind_Control_Block* ucbp,170struct _Unwind_Context* context) {171// Read the compact model EHT entry's header # 6.3172const uint32_t* unwindingData = ucbp->pr_cache.ehtp;173assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");174Descriptor::Format format =175static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24);176177const char *lsda =178reinterpret_cast<const char *>(_Unwind_GetLanguageSpecificData(context));179180// Handle descriptors before unwinding so they are processed in the context181// of the correct stack frame.182_Unwind_Reason_Code result =183ProcessDescriptors(state, ucbp, context, format, lsda,184ucbp->pr_cache.additional);185186if (result != _URC_CONTINUE_UNWIND)187return result;188189switch (__unw_step(reinterpret_cast<unw_cursor_t *>(context))) {190case UNW_STEP_SUCCESS:191return _URC_CONTINUE_UNWIND;192case UNW_STEP_END:193return _URC_END_OF_STACK;194default:195return _URC_FAILURE;196}197}198199// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /200// _UVRSD_UINT32.201uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) {202return ((1U << (count_minus_one + 1)) - 1) << start;203}204205// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP /206// _UVRSD_DOUBLE.207uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) {208return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1);209}210211} // end anonymous namespace212213/**214* Decodes an EHT entry.215*216* @param data Pointer to EHT.217* @param[out] off Offset from return value (in bytes) to begin interpretation.218* @param[out] len Number of bytes in unwind code.219* @return Pointer to beginning of unwind code.220*/221extern "C" const uint32_t*222decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {223if ((*data & 0x80000000) == 0) {224// 6.2: Generic Model225//226// EHT entry is a prel31 pointing to the PR, followed by data understood227// only by the personality routine. Fortunately, all existing assembler228// implementations, including GNU assembler, LLVM integrated assembler,229// and ARM assembler, assume that the unwind opcodes come after the230// personality rountine address.231*off = 1; // First byte is size data.232*len = (((data[1] >> 24) & 0xff) + 1) * 4;233data++; // Skip the first word, which is the prel31 offset.234} else {235// 6.3: ARM Compact Model236//237// EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeed238// by format:239Descriptor::Format format =240static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);241switch (format) {242case Descriptor::SU16:243*len = 4;244*off = 1;245break;246case Descriptor::LU16:247case Descriptor::LU32:248*len = 4 + 4 * ((*data & 0x00ff0000) >> 16);249*off = 2;250break;251default:252return nullptr;253}254}255return data;256}257258_LIBUNWIND_EXPORT _Unwind_Reason_Code259_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,260size_t offset, size_t len) {261bool wrotePC = false;262bool finish = false;263bool hasReturnAddrAuthCode = false;264while (offset < len && !finish) {265uint8_t byte = getByte(data, offset++);266if ((byte & 0x80) == 0) {267uint32_t sp;268_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);269if (byte & 0x40)270sp -= (((uint32_t)byte & 0x3f) << 2) + 4;271else272sp += ((uint32_t)byte << 2) + 4;273_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);274} else {275switch (byte & 0xf0) {276case 0x80: {277if (offset >= len)278return _URC_FAILURE;279uint32_t registers =280(((uint32_t)byte & 0x0f) << 12) |281(((uint32_t)getByte(data, offset++)) << 4);282if (!registers)283return _URC_FAILURE;284if (registers & (1 << 15))285wrotePC = true;286_Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);287break;288}289case 0x90: {290uint8_t reg = byte & 0x0f;291if (reg == 13 || reg == 15)292return _URC_FAILURE;293uint32_t sp;294_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg,295_UVRSD_UINT32, &sp);296_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,297&sp);298break;299}300case 0xa0: {301uint32_t registers = RegisterMask(4, byte & 0x07);302if (byte & 0x08)303registers |= 1 << 14;304_Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);305break;306}307case 0xb0: {308switch (byte) {309case 0xb0:310finish = true;311break;312case 0xb1: {313if (offset >= len)314return _URC_FAILURE;315uint8_t registers = getByte(data, offset++);316if (registers & 0xf0 || !registers)317return _URC_FAILURE;318_Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);319break;320}321case 0xb2: {322uint32_t addend = 0;323uint32_t shift = 0;324// This decodes a uleb128 value.325while (true) {326if (offset >= len)327return _URC_FAILURE;328uint32_t v = getByte(data, offset++);329addend |= (v & 0x7f) << shift;330if ((v & 0x80) == 0)331break;332shift += 7;333}334uint32_t sp;335_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,336&sp);337sp += 0x204 + (addend << 2);338_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,339&sp);340break;341}342case 0xb3: {343uint8_t v = getByte(data, offset++);344_Unwind_VRS_Pop(context, _UVRSC_VFP,345RegisterRange(static_cast<uint8_t>(v >> 4),346v & 0x0f), _UVRSD_VFPX);347break;348}349case 0xb4:350hasReturnAddrAuthCode = true;351_Unwind_VRS_Pop(context, _UVRSC_PSEUDO,3520 /* Return Address Auth Code */, _UVRSD_UINT32);353break;354case 0xb5:355case 0xb6:356case 0xb7:357return _URC_FAILURE;358default:359_Unwind_VRS_Pop(context, _UVRSC_VFP,360RegisterRange(8, byte & 0x07), _UVRSD_VFPX);361break;362}363break;364}365case 0xc0: {366switch (byte) {367#if defined(__ARM_WMMX)368case 0xc0:369case 0xc1:370case 0xc2:371case 0xc3:372case 0xc4:373case 0xc5:374_Unwind_VRS_Pop(context, _UVRSC_WMMXD,375RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE);376break;377case 0xc6: {378uint8_t v = getByte(data, offset++);379uint8_t start = static_cast<uint8_t>(v >> 4);380uint8_t count_minus_one = v & 0xf;381if (start + count_minus_one >= 16)382return _URC_FAILURE;383_Unwind_VRS_Pop(context, _UVRSC_WMMXD,384RegisterRange(start, count_minus_one),385_UVRSD_DOUBLE);386break;387}388case 0xc7: {389uint8_t v = getByte(data, offset++);390if (!v || v & 0xf0)391return _URC_FAILURE;392_Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);393break;394}395#endif396case 0xc8:397case 0xc9: {398uint8_t v = getByte(data, offset++);399uint8_t start =400static_cast<uint8_t>(((byte == 0xc8) ? 16 : 0) + (v >> 4));401uint8_t count_minus_one = v & 0xf;402if (start + count_minus_one >= 32)403return _URC_FAILURE;404_Unwind_VRS_Pop(context, _UVRSC_VFP,405RegisterRange(start, count_minus_one),406_UVRSD_DOUBLE);407break;408}409default:410return _URC_FAILURE;411}412break;413}414case 0xd0: {415if (byte & 0x08)416return _URC_FAILURE;417_Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7),418_UVRSD_DOUBLE);419break;420}421default:422return _URC_FAILURE;423}424}425}426if (!wrotePC) {427uint32_t lr;428_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr);429#ifdef __ARM_FEATURE_PAUTH430if (hasReturnAddrAuthCode) {431uint32_t sp;432uint32_t pac;433_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);434_Unwind_VRS_Get(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);435__asm__ __volatile__("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :);436}437#else438(void)hasReturnAddrAuthCode;439#endif440_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);441}442return _URC_CONTINUE_UNWIND;443}444445extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code446__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp,447_Unwind_Context *context) {448return unwindOneFrame(state, ucbp, context);449}450451extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code452__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp,453_Unwind_Context *context) {454return unwindOneFrame(state, ucbp, context);455}456457extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code458__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp,459_Unwind_Context *context) {460return unwindOneFrame(state, ucbp, context);461}462463static _Unwind_Reason_Code464unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {465// EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during466// phase 1 and then restoring it to the "primary VRS" for phase 2. The467// effect is phase 2 doesn't see any of the VRS manipulations from phase 1.468// In this implementation, the phases don't share the VRS backing store.469// Instead, they are passed the original |uc| and they create a new VRS470// from scratch thus achieving the same effect.471__unw_init_local(cursor, uc);472473// Walk each frame looking for a place to stop.474for (bool handlerNotFound = true; handlerNotFound;) {475476// See if frame has code to run (has personality routine).477unw_proc_info_t frameInfo;478if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {479_LIBUNWIND_TRACE_UNWINDING(480"unwind_phase1(ex_ojb=%p): __unw_get_proc_info "481"failed => _URC_FATAL_PHASE1_ERROR",482static_cast<void *>(exception_object));483return _URC_FATAL_PHASE1_ERROR;484}485486#ifndef NDEBUG487// When tracing, print state information.488if (_LIBUNWIND_TRACING_UNWINDING) {489char functionBuf[512];490const char *functionName = functionBuf;491unw_word_t offset;492if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),493&offset) != UNW_ESUCCESS) ||494(frameInfo.start_ip + offset > frameInfo.end_ip))495functionName = ".anonymous.";496unw_word_t pc;497__unw_get_reg(cursor, UNW_REG_IP, &pc);498_LIBUNWIND_TRACE_UNWINDING(499"unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, "500"lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,501static_cast<void *>(exception_object), pc,502frameInfo.start_ip, functionName,503frameInfo.lsda, frameInfo.handler);504}505#endif506507// If there is a personality routine, ask it if it will want to stop at508// this frame.509if (frameInfo.handler != 0) {510_Unwind_Personality_Fn p =511(_Unwind_Personality_Fn)(long)(frameInfo.handler);512_LIBUNWIND_TRACE_UNWINDING(513"unwind_phase1(ex_ojb=%p): calling personality function %p",514static_cast<void *>(exception_object),515reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p)));516struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);517exception_object->pr_cache.fnstart = frameInfo.start_ip;518exception_object->pr_cache.ehtp =519(_Unwind_EHT_Header *)frameInfo.unwind_info;520exception_object->pr_cache.additional = frameInfo.flags;521_Unwind_Reason_Code personalityResult =522(*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context);523_LIBUNWIND_TRACE_UNWINDING(524"unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p "525"additional %x",526static_cast<void *>(exception_object), personalityResult,527exception_object->pr_cache.fnstart,528static_cast<void *>(exception_object->pr_cache.ehtp),529exception_object->pr_cache.additional);530switch (personalityResult) {531case _URC_HANDLER_FOUND:532// found a catch clause or locals that need destructing in this frame533// stop search and remember stack pointer at the frame534handlerNotFound = false;535// p should have initialized barrier_cache. EHABI #7.3.5536_LIBUNWIND_TRACE_UNWINDING(537"unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",538static_cast<void *>(exception_object));539return _URC_NO_REASON;540541case _URC_CONTINUE_UNWIND:542_LIBUNWIND_TRACE_UNWINDING(543"unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",544static_cast<void *>(exception_object));545// continue unwinding546break;547548// EHABI #7.3.3549case _URC_FAILURE:550return _URC_FAILURE;551552default:553// something went wrong554_LIBUNWIND_TRACE_UNWINDING(555"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",556static_cast<void *>(exception_object));557return _URC_FATAL_PHASE1_ERROR;558}559}560}561return _URC_NO_REASON;562}563564static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,565_Unwind_Exception *exception_object,566bool resume) {567// See comment at the start of unwind_phase1 regarding VRS integrity.568__unw_init_local(cursor, uc);569570_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",571static_cast<void *>(exception_object));572int frame_count = 0;573574// Walk each frame until we reach where search phase said to stop.575while (true) {576// Ask libunwind to get next frame (skip over first which is577// _Unwind_RaiseException or _Unwind_Resume).578//579// Resume only ever makes sense for 1 frame.580_Unwind_State state =581resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING;582if (resume && frame_count == 1) {583// On a resume, first unwind the _Unwind_Resume() frame. The next frame584// is now the landing pad for the cleanup from a previous execution of585// phase2. To continue unwindingly correctly, replace VRS[15] with the586// IP of the frame that the previous run of phase2 installed the context587// for. After this, continue unwinding as if normal.588//589// See #7.4.6 for details.590__unw_set_reg(cursor, UNW_REG_IP,591exception_object->unwinder_cache.reserved2);592resume = false;593}594595// Get info about this frame.596unw_word_t sp;597unw_proc_info_t frameInfo;598__unw_get_reg(cursor, UNW_REG_SP, &sp);599if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {600_LIBUNWIND_TRACE_UNWINDING(601"unwind_phase2(ex_ojb=%p): __unw_get_proc_info "602"failed => _URC_FATAL_PHASE2_ERROR",603static_cast<void *>(exception_object));604return _URC_FATAL_PHASE2_ERROR;605}606607#ifndef NDEBUG608// When tracing, print state information.609if (_LIBUNWIND_TRACING_UNWINDING) {610char functionBuf[512];611const char *functionName = functionBuf;612unw_word_t offset;613if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),614&offset) != UNW_ESUCCESS) ||615(frameInfo.start_ip + offset > frameInfo.end_ip))616functionName = ".anonymous.";617_LIBUNWIND_TRACE_UNWINDING(618"unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", "619"lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",620static_cast<void *>(exception_object), frameInfo.start_ip,621functionName, sp, frameInfo.lsda,622frameInfo.handler);623}624#endif625626// If there is a personality routine, tell it we are unwinding.627if (frameInfo.handler != 0) {628_Unwind_Personality_Fn p =629(_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);630struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);631// EHABI #7.2632exception_object->pr_cache.fnstart = frameInfo.start_ip;633exception_object->pr_cache.ehtp =634(_Unwind_EHT_Header *)frameInfo.unwind_info;635exception_object->pr_cache.additional = frameInfo.flags;636_Unwind_Reason_Code personalityResult =637(*p)(state, exception_object, context);638switch (personalityResult) {639case _URC_CONTINUE_UNWIND:640// Continue unwinding641_LIBUNWIND_TRACE_UNWINDING(642"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",643static_cast<void *>(exception_object));644// EHABI #7.2645if (sp == exception_object->barrier_cache.sp) {646// Phase 1 said we would stop at this frame, but we did not...647_LIBUNWIND_ABORT("during phase1 personality function said it would "648"stop here, but now in phase2 it did not stop here");649}650break;651case _URC_INSTALL_CONTEXT:652_LIBUNWIND_TRACE_UNWINDING(653"unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",654static_cast<void *>(exception_object));655// Personality routine says to transfer control to landing pad.656// We may get control back if landing pad calls _Unwind_Resume().657if (_LIBUNWIND_TRACING_UNWINDING) {658unw_word_t pc;659__unw_get_reg(cursor, UNW_REG_IP, &pc);660__unw_get_reg(cursor, UNW_REG_SP, &sp);661_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "662"user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR,663static_cast<void *>(exception_object),664pc, sp);665}666667{668// EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume669// is called back, to find this same frame.670unw_word_t pc;671__unw_get_reg(cursor, UNW_REG_IP, &pc);672exception_object->unwinder_cache.reserved2 = (uint32_t)pc;673}674__unw_resume(cursor);675// __unw_resume() only returns if there was an error.676return _URC_FATAL_PHASE2_ERROR;677678// # EHABI #7.4.3679case _URC_FAILURE:680abort();681682default:683// Personality routine returned an unknown result code.684_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",685personalityResult);686return _URC_FATAL_PHASE2_ERROR;687}688}689frame_count++;690}691692// Clean up phase did not resume at the frame that the search phase693// said it would...694return _URC_FATAL_PHASE2_ERROR;695}696697static _Unwind_Reason_Code698unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,699_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop,700void *stop_parameter) {701bool endOfStack = false;702// See comment at the start of unwind_phase1 regarding VRS integrity.703__unw_init_local(cursor, uc);704_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_force(ex_ojb=%p)",705static_cast<void *>(exception_object));706// Walk each frame until we reach where search phase said to stop707while (!endOfStack) {708// Update info about this frame.709unw_proc_info_t frameInfo;710if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {711_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_get_proc_info "712"failed => _URC_END_OF_STACK",713(void *)exception_object);714return _URC_FATAL_PHASE2_ERROR;715}716717#ifndef NDEBUG718// When tracing, print state information.719if (_LIBUNWIND_TRACING_UNWINDING) {720char functionBuf[512];721const char *functionName = functionBuf;722unw_word_t offset;723if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),724&offset) != UNW_ESUCCESS) ||725(frameInfo.start_ip + offset > frameInfo.end_ip))726functionName = ".anonymous.";727_LIBUNWIND_TRACE_UNWINDING(728"unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR729", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,730(void *)exception_object, frameInfo.start_ip, functionName,731frameInfo.lsda, frameInfo.handler);732}733#endif734735// Call stop function at each frame.736_Unwind_Action action =737(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);738_Unwind_Reason_Code stopResult =739(*stop)(1, action, exception_object->exception_class, exception_object,740(_Unwind_Context *)(cursor), stop_parameter);741_LIBUNWIND_TRACE_UNWINDING(742"unwind_phase2_forced(ex_ojb=%p): stop function returned %d",743(void *)exception_object, stopResult);744if (stopResult != _URC_NO_REASON) {745_LIBUNWIND_TRACE_UNWINDING(746"unwind_phase2_forced(ex_ojb=%p): stopped by stop function",747(void *)exception_object);748return _URC_FATAL_PHASE2_ERROR;749}750751// If there is a personality routine, tell it we are unwinding.752if (frameInfo.handler != 0) {753_Unwind_Personality_Fn p =754(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);755struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);756// EHABI #7.2757exception_object->pr_cache.fnstart = frameInfo.start_ip;758exception_object->pr_cache.ehtp =759(_Unwind_EHT_Header *)frameInfo.unwind_info;760exception_object->pr_cache.additional = frameInfo.flags;761_Unwind_Reason_Code personalityResult =762(*p)(_US_FORCE_UNWIND | _US_UNWIND_FRAME_STARTING, exception_object,763context);764switch (personalityResult) {765case _URC_CONTINUE_UNWIND:766_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "767"personality returned "768"_URC_CONTINUE_UNWIND",769(void *)exception_object);770// Destructors called, continue unwinding771break;772case _URC_INSTALL_CONTEXT:773_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "774"personality returned "775"_URC_INSTALL_CONTEXT",776(void *)exception_object);777// We may get control back if landing pad calls _Unwind_Resume().778__unw_resume(cursor);779break;780case _URC_END_OF_STACK:781_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "782"personality returned "783"_URC_END_OF_STACK",784(void *)exception_object);785// Personalty routine did the step and it can't step forward.786endOfStack = true;787break;788default:789// Personality routine returned an unknown result code.790_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "791"personality returned %d, "792"_URC_FATAL_PHASE2_ERROR",793(void *)exception_object, personalityResult);794return _URC_FATAL_PHASE2_ERROR;795}796}797}798799// Call stop function one last time and tell it we've reached the end800// of the stack.801_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "802"function with _UA_END_OF_STACK",803(void *)exception_object);804_Unwind_Action lastAction =805(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);806(*stop)(1, lastAction, exception_object->exception_class, exception_object,807(struct _Unwind_Context *)(cursor), stop_parameter);808809// Clean up phase did not resume at the frame that the search phase said it810// would.811return _URC_FATAL_PHASE2_ERROR;812}813814/// Called by __cxa_throw. Only returns if there is a fatal error.815_LIBUNWIND_EXPORT _Unwind_Reason_Code816_Unwind_RaiseException(_Unwind_Exception *exception_object) {817_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",818static_cast<void *>(exception_object));819unw_context_t uc;820unw_cursor_t cursor;821__unw_getcontext(&uc);822823// This field for is for compatibility with GCC to say this isn't a forced824// unwind. EHABI #7.2825exception_object->unwinder_cache.reserved1 = 0;826827// phase 1: the search phase828_Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);829if (phase1 != _URC_NO_REASON)830return phase1;831832// phase 2: the clean up phase833return unwind_phase2(&uc, &cursor, exception_object, false);834}835836_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) {837// This is to be called when exception handling completes to give us a chance838// to perform any housekeeping. EHABI #7.2. But we have nothing to do here.839(void)exception_object;840}841842/// When _Unwind_RaiseException() is in phase2, it hands control843/// to the personality function at each frame. The personality844/// may force a jump to a landing pad in that function, the landing845/// pad code may then call _Unwind_Resume() to continue with the846/// unwinding. Note: the call to _Unwind_Resume() is from compiler847/// generated user code. All other _Unwind_* routines are called848/// by the C++ runtime __cxa_* routines.849///850/// Note: re-throwing an exception (as opposed to continuing the unwind)851/// is implemented by having the code call __cxa_rethrow() which852/// in turn calls _Unwind_Resume_or_Rethrow().853_LIBUNWIND_EXPORT void854_Unwind_Resume(_Unwind_Exception *exception_object) {855_LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)",856static_cast<void *>(exception_object));857unw_context_t uc;858unw_cursor_t cursor;859__unw_getcontext(&uc);860861if (exception_object->unwinder_cache.reserved1)862unwind_phase2_forced(863&uc, &cursor, exception_object,864(_Unwind_Stop_Fn)exception_object->unwinder_cache.reserved1,865(void *)exception_object->unwinder_cache.reserved3);866else867unwind_phase2(&uc, &cursor, exception_object, true);868869// Clients assume _Unwind_Resume() does not return, so all we can do is abort.870_LIBUNWIND_ABORT("_Unwind_Resume() can't return");871}872873/// Called by personality handler during phase 2 to get LSDA for current frame.874_LIBUNWIND_EXPORT uintptr_t875_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {876unw_cursor_t *cursor = (unw_cursor_t *)context;877unw_proc_info_t frameInfo;878uintptr_t result = 0;879if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)880result = (uintptr_t)frameInfo.lsda;881_LIBUNWIND_TRACE_API(882"_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx",883static_cast<void *>(context), (long long)result);884return result;885}886887// Only used in _LIBUNWIND_TRACE_API, which is a no-op when assertions are888// disabled.889[[gnu::unused]] static uint64_t890ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,891const void *valuep) {892uint64_t value = 0;893switch (representation) {894case _UVRSD_UINT32:895case _UVRSD_FLOAT:896memcpy(&value, valuep, sizeof(uint32_t));897break;898899case _UVRSD_VFPX:900case _UVRSD_UINT64:901case _UVRSD_DOUBLE:902memcpy(&value, valuep, sizeof(uint64_t));903break;904}905return value;906}907908_LIBUNWIND_EXPORT _Unwind_VRS_Result909_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,910uint32_t regno, _Unwind_VRS_DataRepresentation representation,911void *valuep) {912_LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, "913"rep=%d, value=0x%llX)",914static_cast<void *>(context), regclass, regno,915representation,916ValueAsBitPattern(representation, valuep));917unw_cursor_t *cursor = (unw_cursor_t *)context;918switch (regclass) {919case _UVRSC_CORE:920if (representation != _UVRSD_UINT32 || regno > 15)921return _UVRSR_FAILED;922return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),923*(unw_word_t *)valuep) == UNW_ESUCCESS924? _UVRSR_OK925: _UVRSR_FAILED;926case _UVRSC_VFP:927if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)928return _UVRSR_FAILED;929if (representation == _UVRSD_VFPX) {930// Can only touch d0-15 with FSTMFDX.931if (regno > 15)932return _UVRSR_FAILED;933__unw_save_vfp_as_X(cursor);934} else {935if (regno > 31)936return _UVRSR_FAILED;937}938return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),939*(unw_fpreg_t *)valuep) == UNW_ESUCCESS940? _UVRSR_OK941: _UVRSR_FAILED;942#if defined(__ARM_WMMX)943case _UVRSC_WMMXC:944if (representation != _UVRSD_UINT32 || regno > 3)945return _UVRSR_FAILED;946return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),947*(unw_word_t *)valuep) == UNW_ESUCCESS948? _UVRSR_OK949: _UVRSR_FAILED;950case _UVRSC_WMMXD:951if (representation != _UVRSD_DOUBLE || regno > 31)952return _UVRSR_FAILED;953return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),954*(unw_fpreg_t *)valuep) == UNW_ESUCCESS955? _UVRSR_OK956: _UVRSR_FAILED;957#else958case _UVRSC_WMMXC:959case _UVRSC_WMMXD:960break;961#endif962case _UVRSC_PSEUDO:963// There's only one pseudo-register, PAC, with regno == 0.964if (representation != _UVRSD_UINT32 || regno != 0)965return _UVRSR_FAILED;966return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_RA_AUTH_CODE),967*(unw_word_t *)valuep) == UNW_ESUCCESS968? _UVRSR_OK969: _UVRSR_FAILED;970break;971}972_LIBUNWIND_ABORT("unsupported register class");973}974975static _Unwind_VRS_Result976_Unwind_VRS_Get_Internal(_Unwind_Context *context,977_Unwind_VRS_RegClass regclass, uint32_t regno,978_Unwind_VRS_DataRepresentation representation,979void *valuep) {980unw_cursor_t *cursor = (unw_cursor_t *)context;981switch (regclass) {982case _UVRSC_CORE:983if (representation != _UVRSD_UINT32 || regno > 15)984return _UVRSR_FAILED;985return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),986(unw_word_t *)valuep) == UNW_ESUCCESS987? _UVRSR_OK988: _UVRSR_FAILED;989case _UVRSC_VFP:990if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)991return _UVRSR_FAILED;992if (representation == _UVRSD_VFPX) {993// Can only touch d0-15 with FSTMFDX.994if (regno > 15)995return _UVRSR_FAILED;996__unw_save_vfp_as_X(cursor);997} else {998if (regno > 31)999return _UVRSR_FAILED;1000}1001return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),1002(unw_fpreg_t *)valuep) == UNW_ESUCCESS1003? _UVRSR_OK1004: _UVRSR_FAILED;1005#if defined(__ARM_WMMX)1006case _UVRSC_WMMXC:1007if (representation != _UVRSD_UINT32 || regno > 3)1008return _UVRSR_FAILED;1009return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),1010(unw_word_t *)valuep) == UNW_ESUCCESS1011? _UVRSR_OK1012: _UVRSR_FAILED;1013case _UVRSC_WMMXD:1014if (representation != _UVRSD_DOUBLE || regno > 31)1015return _UVRSR_FAILED;1016return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),1017(unw_fpreg_t *)valuep) == UNW_ESUCCESS1018? _UVRSR_OK1019: _UVRSR_FAILED;1020#else1021case _UVRSC_WMMXC:1022case _UVRSC_WMMXD:1023break;1024#endif1025case _UVRSC_PSEUDO:1026// There's only one pseudo-register, PAC, with regno == 0.1027if (representation != _UVRSD_UINT32 || regno != 0)1028return _UVRSR_FAILED;1029return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_RA_AUTH_CODE),1030(unw_word_t *)valuep) == UNW_ESUCCESS1031? _UVRSR_OK1032: _UVRSR_FAILED;1033break;1034}1035_LIBUNWIND_ABORT("unsupported register class");1036}10371038_LIBUNWIND_EXPORT _Unwind_VRS_Result1039_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,1040uint32_t regno, _Unwind_VRS_DataRepresentation representation,1041void *valuep) {1042_Unwind_VRS_Result result =1043_Unwind_VRS_Get_Internal(context, regclass, regno, representation,1044valuep);1045_LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, "1046"rep=%d, value=0x%llX, result = %d)",1047static_cast<void *>(context), regclass, regno,1048representation,1049ValueAsBitPattern(representation, valuep), result);1050return result;1051}10521053_Unwind_VRS_Result1054_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,1055uint32_t discriminator,1056_Unwind_VRS_DataRepresentation representation) {1057_LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, "1058"discriminator=%d, representation=%d)",1059static_cast<void *>(context), regclass, discriminator,1060representation);1061switch (regclass) {1062case _UVRSC_WMMXC:1063#if !defined(__ARM_WMMX)1064break;1065#endif1066case _UVRSC_CORE: {1067if (representation != _UVRSD_UINT32)1068return _UVRSR_FAILED;1069// When popping SP from the stack, we don't want to override it from the1070// computed new stack location. See EHABI #7.5.4 table 3.1071bool poppedSP = false;1072uint32_t* sp;1073if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,1074_UVRSD_UINT32, &sp) != _UVRSR_OK) {1075return _UVRSR_FAILED;1076}1077for (uint32_t i = 0; i < 16; ++i) {1078if (!(discriminator & static_cast<uint32_t>(1 << i)))1079continue;1080uint32_t value = *sp++;1081if (regclass == _UVRSC_CORE && i == 13)1082poppedSP = true;1083if (_Unwind_VRS_Set(context, regclass, i,1084_UVRSD_UINT32, &value) != _UVRSR_OK) {1085return _UVRSR_FAILED;1086}1087}1088if (!poppedSP) {1089return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP,1090_UVRSD_UINT32, &sp);1091}1092return _UVRSR_OK;1093}1094case _UVRSC_WMMXD:1095#if !defined(__ARM_WMMX)1096break;1097#endif1098case _UVRSC_VFP: {1099if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)1100return _UVRSR_FAILED;1101uint32_t first = discriminator >> 16;1102uint32_t count = discriminator & 0xffff;1103uint32_t end = first+count;1104uint32_t* sp;1105if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,1106_UVRSD_UINT32, &sp) != _UVRSR_OK) {1107return _UVRSR_FAILED;1108}1109// For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard1110// format 1", which is equivalent to FSTMD + a padding word.1111for (uint32_t i = first; i < end; ++i) {1112// SP is only 32-bit aligned so don't copy 64-bit at a time.1113uint64_t w0 = *sp++;1114uint64_t w1 = *sp++;1115#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__1116uint64_t value = (w1 << 32) | w0;1117#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__1118uint64_t value = (w0 << 32) | w1;1119#else1120#error "Unable to determine endianess"1121#endif1122if (_Unwind_VRS_Set(context, regclass, i, representation, &value) !=1123_UVRSR_OK)1124return _UVRSR_FAILED;1125}1126if (representation == _UVRSD_VFPX)1127++sp;1128return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,1129&sp);1130}1131case _UVRSC_PSEUDO: {1132if (representation != _UVRSD_UINT32 || discriminator != 0)1133return _UVRSR_FAILED;1134// Return Address Authentication code (PAC) - discriminator 01135uint32_t *sp;1136if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,1137&sp) != _UVRSR_OK) {1138return _UVRSR_FAILED;1139}1140uint32_t pac = *sp++;1141_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);1142return _Unwind_VRS_Set(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);1143}1144}1145_LIBUNWIND_ABORT("unsupported register class");1146}11471148/// Not used by C++.1149/// Unwinds stack, calling "stop" function at each frame.1150/// Could be used to implement longjmp().1151_LIBUNWIND_EXPORT _Unwind_Reason_Code1152_Unwind_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop,1153void *stop_parameter) {1154_LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",1155(void *)exception_object, (void *)(uintptr_t)stop);1156unw_context_t uc;1157unw_cursor_t cursor;1158__unw_getcontext(&uc);11591160// Mark that this is a forced unwind, so _Unwind_Resume() can do1161// the right thing.1162exception_object->unwinder_cache.reserved1 = (uintptr_t)stop;1163exception_object->unwinder_cache.reserved3 = (uintptr_t)stop_parameter;11641165return unwind_phase2_forced(&uc, &cursor, exception_object, stop,1166stop_parameter);1167}11681169/// Called by personality handler during phase 2 to find the start of the1170/// function.1171_LIBUNWIND_EXPORT uintptr_t1172_Unwind_GetRegionStart(struct _Unwind_Context *context) {1173unw_cursor_t *cursor = (unw_cursor_t *)context;1174unw_proc_info_t frameInfo;1175uintptr_t result = 0;1176if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)1177result = (uintptr_t)frameInfo.start_ip;1178_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX",1179static_cast<void *>(context), (long long)result);1180return result;1181}118211831184/// Called by personality handler during phase 2 if a foreign exception1185// is caught.1186_LIBUNWIND_EXPORT void1187_Unwind_DeleteException(_Unwind_Exception *exception_object) {1188_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",1189static_cast<void *>(exception_object));1190if (exception_object->exception_cleanup != NULL)1191(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,1192exception_object);1193}11941195extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code1196__gnu_unwind_frame(_Unwind_Exception *exception_object,1197struct _Unwind_Context *context) {1198(void)exception_object;1199unw_cursor_t *cursor = (unw_cursor_t *)context;1200switch (__unw_step(cursor)) {1201case UNW_STEP_SUCCESS:1202return _URC_OK;1203case UNW_STEP_END:1204return _URC_END_OF_STACK;1205default:1206return _URC_FAILURE;1207}1208}12091210#endif // defined(_LIBUNWIND_ARM_EHABI)121112121213