Path: blob/master/libs/unwind/src/UnwindLevel1-gcc-ext.c
12346 views
//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===//1//2// The LLVM Compiler Infrastructure3//4// This file is dual licensed under the MIT and the University of Illinois Open5// Source Licenses. See LICENSE.TXT for details.6//7//8// Implements gcc extensions to the C++ ABI Exception Handling Level 1.9//10//===----------------------------------------------------------------------===//1112#include <inttypes.h>13#include <stdbool.h>14#include <stdint.h>15#include <stdio.h>16#include <stdlib.h>17#include <string.h>1819#include "config.h"20#include "libunwind_ext.h"21#include "libunwind.h"22#include "Unwind-EHABI.h"23#include "unwind.h"2425#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)2627#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)28#define private_1 private_[0]29#endif3031/// Called by __cxa_rethrow().32_LIBUNWIND_EXPORT _Unwind_Reason_Code33_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {34#if defined(_LIBUNWIND_ARM_EHABI)35_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",36(void *)exception_object,37(long)exception_object->unwinder_cache.reserved1);38#else39_LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,40(void *)exception_object,41(intptr_t)exception_object->private_1);42#endif4344#if defined(_LIBUNWIND_ARM_EHABI)45// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,46// which is in the same position as private_1 below.47return _Unwind_RaiseException(exception_object);48#else49// If this is non-forced and a stopping place was found, then this is a50// re-throw.51// Call _Unwind_RaiseException() as if this was a new exception52if (exception_object->private_1 == 0) {53return _Unwind_RaiseException(exception_object);54// Will return if there is no catch clause, so that __cxa_rethrow can call55// std::terminate().56}5758// Call through to _Unwind_Resume() which distiguishes between forced and59// regular exceptions.60_Unwind_Resume(exception_object);61_LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"62" which unexpectedly returned");63#endif64}656667/// Called by personality handler during phase 2 to get base address for data68/// relative encodings.69_LIBUNWIND_EXPORT uintptr_t70_Unwind_GetDataRelBase(struct _Unwind_Context *context) {71(void)context;72_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);73_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");74}757677/// Called by personality handler during phase 2 to get base address for text78/// relative encodings.79_LIBUNWIND_EXPORT uintptr_t80_Unwind_GetTextRelBase(struct _Unwind_Context *context) {81(void)context;82_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);83_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");84}858687/// Scans unwind information to find the function that contains the88/// specified code address "pc".89_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {90_LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);91// This is slow, but works.92// We create an unwind cursor then alter the IP to be pc93unw_cursor_t cursor;94unw_context_t uc;95unw_proc_info_t info;96unw_getcontext(&uc);97unw_init_local(&cursor, &uc);98unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);99if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)100return (void *)(intptr_t) info.start_ip;101else102return NULL;103}104105/// Walk every frame and call trace function at each one. If trace function106/// returns anything other than _URC_NO_REASON, then walk is terminated.107_LIBUNWIND_EXPORT _Unwind_Reason_Code108_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {109unw_cursor_t cursor;110unw_context_t uc;111unw_getcontext(&uc);112unw_init_local(&cursor, &uc);113114_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",115(void *)(uintptr_t)callback);116117#if defined(_LIBUNWIND_ARM_EHABI)118// Create a mock exception object for force unwinding.119_Unwind_Exception ex;120memset(&ex, '\0', sizeof(ex));121ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0122#endif123124// walk each frame125while (true) {126_Unwind_Reason_Code result;127128#if !defined(_LIBUNWIND_ARM_EHABI)129// ask libunwind to get next frame (skip over first frame which is130// _Unwind_Backtrace())131if (unw_step(&cursor) <= 0) {132_LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "133"bottom of stack, returning %d",134_URC_END_OF_STACK);135return _URC_END_OF_STACK;136}137#else138// Get the information for this frame.139unw_proc_info_t frameInfo;140if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {141return _URC_END_OF_STACK;142}143144// Update the pr_cache in the mock exception object.145const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;146ex.pr_cache.fnstart = frameInfo.start_ip;147ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;148ex.pr_cache.additional= frameInfo.flags;149150struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;151// Get and call the personality function to unwind the frame.152__personality_routine handler = (__personality_routine) frameInfo.handler;153if (handler == NULL) {154return _URC_END_OF_STACK;155}156if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=157_URC_CONTINUE_UNWIND) {158return _URC_END_OF_STACK;159}160#endif // defined(_LIBUNWIND_ARM_EHABI)161162// debugging163if (_LIBUNWIND_TRACING_UNWINDING) {164char functionName[512];165unw_proc_info_t frame;166unw_word_t offset;167unw_get_proc_name(&cursor, functionName, 512, &offset);168unw_get_proc_info(&cursor, &frame);169_LIBUNWIND_TRACE_UNWINDING(170" _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",171frame.start_ip, functionName, frame.lsda,172(void *)&cursor);173}174175// call trace function with this frame176result = (*callback)((struct _Unwind_Context *)(&cursor), ref);177if (result != _URC_NO_REASON) {178_LIBUNWIND_TRACE_UNWINDING(179" _backtrace: ended because callback returned %d", result);180return result;181}182}183}184185186/// Find DWARF unwind info for an address 'pc' in some function.187_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,188struct dwarf_eh_bases *bases) {189// This is slow, but works.190// We create an unwind cursor then alter the IP to be pc191unw_cursor_t cursor;192unw_context_t uc;193unw_proc_info_t info;194unw_getcontext(&uc);195unw_init_local(&cursor, &uc);196unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);197unw_get_proc_info(&cursor, &info);198bases->tbase = (uintptr_t)info.extra;199bases->dbase = 0; // dbase not used on Mac OS X200bases->func = (uintptr_t)info.start_ip;201_LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,202(void *)(intptr_t) info.unwind_info);203return (void *)(intptr_t) info.unwind_info;204}205206/// Returns the CFA (call frame area, or stack pointer at start of function)207/// for the current context.208_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {209unw_cursor_t *cursor = (unw_cursor_t *)context;210unw_word_t result;211unw_get_reg(cursor, UNW_REG_SP, &result);212_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,213(void *)context, result);214return (uintptr_t)result;215}216217218/// Called by personality handler during phase 2 to get instruction pointer.219/// ipBefore is a boolean that says if IP is already adjusted to be the call220/// site address. Normally IP is the return address.221_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,222int *ipBefore) {223_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);224*ipBefore = 0;225return _Unwind_GetIP(context);226}227228#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)229230/// Called by programs with dynamic code generators that want231/// to register a dynamically generated FDE.232/// This function has existed on Mac OS X since 10.4, but233/// was broken until 10.6.234_LIBUNWIND_EXPORT void __register_frame(const void *fde) {235_LIBUNWIND_TRACE_API("__register_frame(%p)", fde);236_unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde);237}238239240/// Called by programs with dynamic code generators that want241/// to unregister a dynamically generated FDE.242/// This function has existed on Mac OS X since 10.4, but243/// was broken until 10.6.244_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {245_LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);246_unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde);247}248249250// The following register/deregister functions are gcc extensions.251// They have existed on Mac OS X, but have never worked because Mac OS X252// before 10.6 used keymgr to track known FDEs, but these functions253// never got updated to use keymgr.254// For now, we implement these as do-nothing functions to keep any existing255// applications working. We also add the not in 10.6 symbol so that nwe256// application won't be able to use them.257258#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)259_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,260void *tb, void *db) {261(void)fde;262(void)ob;263(void)tb;264(void)db;265_LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",266fde, ob, tb, db);267// do nothing, this function never worked in Mac OS X268}269270_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {271(void)fde;272(void)ob;273_LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);274// do nothing, this function never worked in Mac OS X275}276277_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,278void *ob, void *tb,279void *db) {280(void)fde;281(void)ob;282(void)tb;283(void)db;284_LIBUNWIND_TRACE_API("__register_frame_info_table_bases"285"(%p,%p, %p, %p)", fde, ob, tb, db);286// do nothing, this function never worked in Mac OS X287}288289_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {290(void)fde;291(void)ob;292_LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);293// do nothing, this function never worked in Mac OS X294}295296_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {297(void)fde;298_LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);299// do nothing, this function never worked in Mac OS X300}301302_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {303(void)fde;304_LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);305// do nothing, this function never worked in Mac OS X306return NULL;307}308309_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {310(void)fde;311_LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);312// do nothing, this function never worked in Mac OS X313return NULL;314}315#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)316317#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)318319#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)320321322