COMPILER_RT_ABI _Unwind_Reason_Code
__gcc_personality_v0(int version, _Unwind_Action actions,
         uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
         struct _Unwind_Context *context)
#endif
{
    /* Since C does not have catch clauses, there is nothing to do during */
    /* phase 1 (the search phase). */
    if ( actions & _UA_SEARCH_PHASE ) 
        return _URC_CONTINUE_UNWIND;
        
    /* There is nothing to do if there is no LSDA for this frame. */
    const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
    if ( lsda == (uint8_t*) 0 )
        return _URC_CONTINUE_UNWIND;

    uintptr_t pc = _Unwind_GetIP(context)-1;
    uintptr_t funcStart = _Unwind_GetRegionStart(context);
    uintptr_t pcOffset = pc - funcStart;

    /* Parse LSDA header. */
    uint8_t lpStartEncoding = *lsda++;
    if (lpStartEncoding != DW_EH_PE_omit) {
        readEncodedPointer(&lsda, lpStartEncoding); 
    }
    uint8_t ttypeEncoding = *lsda++;
    if (ttypeEncoding != DW_EH_PE_omit) {
        readULEB128(&lsda);  
    }
    /* Walk call-site table looking for range that includes current PC. */
    uint8_t         callSiteEncoding = *lsda++;
    uint32_t        callSiteTableLength = readULEB128(&lsda);
    const uint8_t*  callSiteTableStart = lsda;
    const uint8_t*  callSiteTableEnd = callSiteTableStart + callSiteTableLength;
    const uint8_t* p=callSiteTableStart;
    while (p < callSiteTableEnd) {
        uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
        uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
        uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
        readULEB128(&p); /* action value not used for C code */
        if ( landingPad == 0 )
            continue; /* no landing pad for this entry */
        if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
            /* Found landing pad for the PC.
             * Set Instruction Pointer to so we re-enter function 
             * at landing pad. The landing pad is created by the compiler
             * to take two parameters in registers.
             */
            _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
                          (uintptr_t)exceptionObject);
            _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
            _Unwind_SetIP(context, (funcStart + landingPad));
            return _URC_INSTALL_CONTEXT;
        }
    }

    /* No landing pad found, continue unwinding. */
    return _URC_CONTINUE_UNWIND;
}
Example #2
0
static
const __shim_type_info*
get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
                   uint8_t ttypeEncoding, bool native_exception,
                   _Unwind_Exception* unwind_exception)
{
    if (classInfo == 0)
    {
        // this should not happen.  Indicates corrupted eh_table.
        call_terminate(native_exception, unwind_exception);
    }
    switch (ttypeEncoding & 0x0F)
    {
    case DW_EH_PE_absptr:
        ttypeIndex *= sizeof(void*);
        break;
    case DW_EH_PE_udata2:
    case DW_EH_PE_sdata2:
        ttypeIndex *= 2;
        break;
    case DW_EH_PE_udata4:
    case DW_EH_PE_sdata4:
        ttypeIndex *= 4;
        break;
    case DW_EH_PE_udata8:
    case DW_EH_PE_sdata8:
        ttypeIndex *= 8;
        break;
    default:
        // this should not happen.   Indicates corrupted eh_table.
        call_terminate(native_exception, unwind_exception);
    }
    classInfo -= ttypeIndex;
    return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);
}
Example #3
0
static int dlCallback(struct dl_phdr_info *info, size_t size, void *data)
{
	CBData* cbdata = static_cast<CBData*>(data);
	bool addrMatch = false;
	void* maxAddr = 0;
	const eh_frame_hdr* ehdr = 0;

	if (cbdata->info->dwarf_section) // we already have a match
		return 0;

	//std::cout << "Looking into " << info->dlpi_name << std::endl;

	if (size < offsetof(struct dl_phdr_info, dlpi_phnum))
		return 0;

	for (int i = 0; i < info->dlpi_phnum; i++)
	{
		const ElfW(Phdr)* phdr = &info->dlpi_phdr[i];
		/*
		if (strstr(info->dlpi_name, "cxxdarwin"))
		{
			std::cout << "type: " << phdr->p_type << "; vaddr: " << phdr->p_vaddr << std::endl;
		}
		*/
		
		if (phdr->p_type == PT_LOAD)
		{
			void* from = reinterpret_cast<void*>(uintptr_t(info->dlpi_addr) + uintptr_t(phdr->p_vaddr));
			void* to = reinterpret_cast<char*>(from) + phdr->p_memsz;

			if (cbdata->addr >= from && cbdata->addr < to)
				addrMatch = true;
			if (to > maxAddr)
				maxAddr = to; // TODO: could this be improved? libunwind does the same
		}
		else if (phdr->p_type == PT_GNU_EH_FRAME)
		{
			//std::cout << "Found .eh_frame_hdr in " << info->dlpi_name << std::endl;
			ehdr = reinterpret_cast<eh_frame_hdr*>(uintptr_t(info->dlpi_addr) + phdr->p_vaddr);
			// cbdata->info->dwarf_section_length = phdr->p_memsz;
		}
	}

	if (addrMatch && ehdr)
	{
		//std::cout << "*** Match found! " << info->dlpi_name << std::endl;
		
		// Now we find .eh_frame from .eh_frame_hdr
		if (ehdr->version != 1)
			return 0;
		cbdata->info->dwarf_section = reinterpret_cast<void*>(readEncodedPointer(ehdr));
		cbdata->info->dwarf_section_length = uintptr_t(maxAddr) - uintptr_t(cbdata->info->dwarf_section);
	}

	return 0;
}
Example #4
0
void
__cxa_call_unexpected(void* arg)
{
    _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
    if (unwind_exception == 0)
        call_terminate(false, unwind_exception);
    __cxa_begin_catch(unwind_exception);
    bool native_old_exception =
        (reinterpret_cast<uint64_t>(unwind_exception->exception_class) & get_vendor_and_language) ==
        (kOurExceptionClass                & get_vendor_and_language);
    std::unexpected_handler u_handler;
    std::terminate_handler t_handler;
    __cxa_exception* old_exception_header = 0;
    int64_t ttypeIndex;
    const uint8_t* lsda;
    if (native_old_exception)
    {
        old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
        t_handler = old_exception_header->terminateHandler;
        u_handler = old_exception_header->unexpectedHandler;
        // If std::__unexpected(u_handler) rethrows the same exception,
        //   these values get overwritten by the rethrow.  So save them now:
#ifndef __ARM_EABI_UNWINDER__
        ttypeIndex = old_exception_header->handlerSwitchValue;
        lsda = old_exception_header->languageSpecificData;
#endif
    }
    else
    {
        t_handler = std::get_terminate();
        u_handler = std::get_unexpected();
    }
    try
    {
        std::__unexpected(u_handler);
    }
    catch (...)
    {
        // If the old exception is foreign, then all we can do is terminate.
        //   We have no way to recover the needed old exception spec.  There's
        //   no way to pass that information here.  And the personality routine
        //   can't call us directly and do anything but terminate() if we throw
        //   from here.
        if (native_old_exception)
        {
            // Have:
            //   old_exception_header->languageSpecificData
            //   old_exception_header->actionRecord
            // Need
            //   const uint8_t* classInfo
            //   uint8_t ttypeEncoding
            uint8_t lpStartEncoding = *lsda++;
            const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
            (void)lpStart;  // purposefully unused.  Just needed to increment lsda.
            uint8_t ttypeEncoding = *lsda++;
            if (ttypeEncoding == DW_EH_PE_omit)
                std::__terminate(t_handler);
            uintptr_t classInfoOffset = readULEB128(&lsda);
            const uint8_t* classInfo = lsda + classInfoOffset;
            // Is this new exception catchable by the exception spec at ttypeIndex?
            // The answer is obviously yes if the new and old exceptions are the same exception
            // If no
            //    throw;
            __cxa_eh_globals* globals = __cxa_get_globals_fast();
            __cxa_exception* new_exception_header = globals->caughtExceptions;
            if (new_exception_header == 0)
                // This shouldn't be able to happen!
                std::__terminate(t_handler);
            bool native_new_exception =
                (reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) & get_vendor_and_language) ==
                                                (kOurExceptionClass & get_vendor_and_language);
            void* adjustedPtr;
            if (native_new_exception && (new_exception_header != old_exception_header))
            {
                const __shim_type_info* excpType =
                    static_cast<const __shim_type_info*>(new_exception_header->exceptionType);
                adjustedPtr =
                    reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) == kOurDependentExceptionClass ?
                        ((__cxa_dependent_exception*)new_exception_header)->primaryException :
                        new_exception_header + 1;
                if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
                                              excpType, adjustedPtr, unwind_exception))
                {
                    // We need to __cxa_end_catch, but for the old exception,
                    //   not the new one.  This is a little tricky ...
                    // Disguise new_exception_header as a rethrown exception, but
                    //   don't actually rethrow it.  This means you can temporarily
                    //   end the catch clause enclosing new_exception_header without
                    //   __cxa_end_catch destroying new_exception_header.
                    new_exception_header->handlerCount = -new_exception_header->handlerCount;
                    globals->uncaughtExceptions += 1;
                    // Call __cxa_end_catch for new_exception_header
                    __cxa_end_catch();
                    // Call __cxa_end_catch for old_exception_header
                    __cxa_end_catch();
                    // Renter this catch clause with new_exception_header
                    __cxa_begin_catch(&new_exception_header->unwindHeader);
                    // Rethrow new_exception_header
                    throw;
                }
            }
            // Will a std::bad_exception be catchable by the exception spec at
            //   ttypeIndex?
            // If no
            //    throw std::bad_exception();
            const __shim_type_info* excpType =
                static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
            std::bad_exception be;
            adjustedPtr = &be;
            if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
                                          excpType, adjustedPtr, unwind_exception))
            {
                // We need to __cxa_end_catch for both the old exception and the
                //   new exception.  Technically we should do it in that order.
                //   But it is expedient to do it in the opposite order:
                // Call __cxa_end_catch for new_exception_header
                __cxa_end_catch();
                // Throw std::bad_exception will __cxa_end_catch for
                //   old_exception_header
                throw be;
            }
        }
    }
    std::__terminate(t_handler);
}
Example #5
0
static
void
scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
            _Unwind_Exception* unwind_exception, _Unwind_Context* context)
{
    // Initialize results to found nothing but an error
    results.ttypeIndex = 0;
    results.actionRecord = 0;
    results.languageSpecificData = 0;
    results.landingPad = 0;
    results.adjustedPtr = 0;
    results.reason = _URC_FATAL_PHASE1_ERROR;
    // Check for consistent actions
    if (actions & _UA_SEARCH_PHASE)
    {
        // Do Phase 1
        if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND))
        {
            // None of these flags should be set during Phase 1
            //   Client error
            results.reason = _URC_FATAL_PHASE1_ERROR;
            return;
        }
    }
    else if (actions & _UA_CLEANUP_PHASE)
    {
        if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND))
        {
            // _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
            // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
            //    Client error
            results.reason = _URC_FATAL_PHASE2_ERROR;
            return;
        }
    }
    else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set
    {
        // One of these should be set.
        //   Client error
        results.reason = _URC_FATAL_PHASE1_ERROR;
        return;
    }
    // Start scan by getting exception table address
    const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
    if (lsda == 0)
    {
        // There is no exception table
        results.reason = _URC_CONTINUE_UNWIND;
        return;
    }
    results.languageSpecificData = lsda;
    // Get the current instruction pointer and offset it before next
    // instruction in the current frame which threw the exception.
    uintptr_t ip = _Unwind_GetIP(context) - 1;
    // Get beginning current frame's code (as defined by the 
    // emitted dwarf code)
    uintptr_t funcStart = _Unwind_GetRegionStart(context);
#if __arm__
    if (ip == uintptr_t(-1))
    {
        // no action
        results.reason = _URC_CONTINUE_UNWIND;
        return;
    }
    else if (ip == 0)
        call_terminate(native_exception, unwind_exception);
    // ip is 1-based index into call site table
#else  // __arm__
    uintptr_t ipOffset = ip - funcStart;
#endif  // __arm__
    const uint8_t* classInfo = NULL;
    // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
    //       dwarf emission
    // Parse LSDA header.
    uint8_t lpStartEncoding = *lsda++;
    const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
    if (lpStart == 0)
        lpStart = (const uint8_t*)funcStart;
    uint8_t ttypeEncoding = *lsda++;
    if (ttypeEncoding != DW_EH_PE_omit)
    {
        // Calculate type info locations in emitted dwarf code which
        // were flagged by type info arguments to llvm.eh.selector
        // intrinsic
        uintptr_t classInfoOffset = readULEB128(&lsda);
        classInfo = lsda + classInfoOffset;
    }
    // Walk call-site table looking for range that 
    // includes current PC. 
    uint8_t callSiteEncoding = *lsda++;
#if __arm__
    (void)callSiteEncoding;  // On arm callSiteEncoding is never used
#endif
    uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
    const uint8_t* callSiteTableStart = lsda;
    const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
    const uint8_t* actionTableStart = callSiteTableEnd;
    const uint8_t* callSitePtr = callSiteTableStart;
    while (callSitePtr < callSiteTableEnd)
    {
        // There is one entry per call site.
#if !__arm__
        // The call sites are non-overlapping in [start, start+length)
        // The call sites are ordered in increasing value of start
        uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
        uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
        uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
        uintptr_t actionEntry = readULEB128(&callSitePtr);
        if ((start <= ipOffset) && (ipOffset < (start + length)))
#else  // __arm__
        // ip is 1-based index into this table
        uintptr_t landingPad = readULEB128(&callSitePtr);
        uintptr_t actionEntry = readULEB128(&callSitePtr);
        if (--ip == 0)
#endif  // __arm__
        {
            // Found the call site containing ip.
#if !__arm__
            if (landingPad == 0)
            {
                // No handler here
                results.reason = _URC_CONTINUE_UNWIND;
                return;
            }
            landingPad = (uintptr_t)lpStart + landingPad;
#else  // __arm__
            ++landingPad;
#endif  // __arm__
            if (actionEntry == 0)
            {
                // Found a cleanup
                // If this is a type 1 or type 2 search, there are no handlers
                // If this is a type 3 search, you want to install the cleanup.
                if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
                {
                    results.ttypeIndex = 0;  // Redundant but clarifying
                    results.landingPad = landingPad;
                    results.reason = _URC_HANDLER_FOUND;
                    return;
                }
                // No handler here
                results.reason = _URC_CONTINUE_UNWIND;
                return;
            }
            // Convert 1-based byte offset into
            const uint8_t* action = actionTableStart + (actionEntry - 1);
            // Scan action entries until you find a matching handler, cleanup, or the end of action list
            while (true)
            {
                const uint8_t* actionRecord = action;
                int64_t ttypeIndex = readSLEB128(&action);
                if (ttypeIndex > 0)
                {
                    // Found a catch, does it actually catch?
                    // First check for catch (...)
                    const __shim_type_info* catchType =
                        get_shim_type_info(static_cast<uint64_t>(ttypeIndex),
                                           classInfo, ttypeEncoding,
                                           native_exception, unwind_exception);
                    if (catchType == 0)
                    {
                        // Found catch (...) catches everything, including foreign exceptions
                        // If this is a type 1 search save state and return _URC_HANDLER_FOUND
                        // If this is a type 2 search save state and return _URC_HANDLER_FOUND
                        // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                        // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
                        if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
                        {
                            // Save state and return _URC_HANDLER_FOUND
                            results.ttypeIndex = ttypeIndex;
                            results.actionRecord = actionRecord;
                            results.landingPad = landingPad;
                            results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
                            results.reason = _URC_HANDLER_FOUND;
                            return;
                        }
                        else if (!(actions & _UA_FORCE_UNWIND))
                        {
                            // It looks like the exception table has changed
                            //    on us.  Likely stack corruption!
                            call_terminate(native_exception, unwind_exception);
                        }
                    }
                    // Else this is a catch (T) clause and will never
                    //    catch a foreign exception
                    else if (native_exception)
                    {
                        __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
                        void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
                        const __shim_type_info* excpType =
                            static_cast<const __shim_type_info*>(exception_header->exceptionType);
                        if (adjustedPtr == 0 || excpType == 0)
                        {
                            // Something very bad happened
                            call_terminate(native_exception, unwind_exception);
                        }
                        if (catchType->can_catch(excpType, adjustedPtr))
                        {
                            // Found a matching handler
                            // If this is a type 1 search save state and return _URC_HANDLER_FOUND
                            // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
                            // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
                            if (actions & _UA_SEARCH_PHASE)
                            {
                                // Save state and return _URC_HANDLER_FOUND
                                results.ttypeIndex = ttypeIndex;
                                results.actionRecord = actionRecord;
                                results.landingPad = landingPad;
                                results.adjustedPtr = adjustedPtr;
                                results.reason = _URC_HANDLER_FOUND;
                                return;
                            }
                            else if (!(actions & _UA_FORCE_UNWIND))
                            {
                                // It looks like the exception table has changed
                                //    on us.  Likely stack corruption!
                                call_terminate(native_exception, unwind_exception);
                            }
                        }
                    }
                    // Scan next action ...
                }
                else if (ttypeIndex < 0)
                {
                    // Found an exception spec.  If this is a foreign exception,
                    //   it is always caught.
                    if (native_exception)
                    {
                        // Does the exception spec catch this native exception?
                        __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
                        void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
                        const __shim_type_info* excpType =
                            static_cast<const __shim_type_info*>(exception_header->exceptionType);
                        if (adjustedPtr == 0 || excpType == 0)
                        {
                            // Something very bad happened
                            call_terminate(native_exception, unwind_exception);
                        }
                        if (exception_spec_can_catch(ttypeIndex, classInfo,
                                                     ttypeEncoding, excpType,
                                                     adjustedPtr, unwind_exception))
                        {
                            // native exception caught by exception spec
                            // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
                            // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                            // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
                            if (actions & _UA_SEARCH_PHASE)
                            {
                                // Save state and return _URC_HANDLER_FOUND
                                results.ttypeIndex = ttypeIndex;
                                results.actionRecord = actionRecord;
                                results.landingPad = landingPad;
                                results.adjustedPtr = adjustedPtr;
                                results.reason = _URC_HANDLER_FOUND;
                                return;
                            }
                            else if (!(actions & _UA_FORCE_UNWIND))
                            {
                                // It looks like the exception table has changed
                                //    on us.  Likely stack corruption!
                                call_terminate(native_exception, unwind_exception);
                            }
                        }
                    }
                    else
                    {
                        // foreign exception caught by exception spec
                        // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
                        // If this is a type 2 search, save state and return _URC_HANDLER_FOUND
                        // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                        // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
                        if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
                        {
                            // Save state and return _URC_HANDLER_FOUND
                            results.ttypeIndex = ttypeIndex;
                            results.actionRecord = actionRecord;
                            results.landingPad = landingPad;
                            results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
                            results.reason = _URC_HANDLER_FOUND;
                            return;
                        }
                        else if (!(actions & _UA_FORCE_UNWIND))
                        {
                            // It looks like the exception table has changed
                            //    on us.  Likely stack corruption!
                            call_terminate(native_exception, unwind_exception);
                        }
                    }
                    // Scan next action ...
                }
                else  // ttypeIndex == 0
                {
                    // Found a cleanup
                    // If this is a type 1 search, ignore it and continue scan
                    // If this is a type 2 search, ignore it and continue scan
                    // If this is a type 3 search, save state and return _URC_HANDLER_FOUND
                    if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
                    {
                        // Save state and return _URC_HANDLER_FOUND
                        results.ttypeIndex = ttypeIndex;
                        results.actionRecord = actionRecord;
                        results.landingPad = landingPad;
                        results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
                        results.reason = _URC_HANDLER_FOUND;
                        return;
                    }
                }
                const uint8_t* temp = action;
                int64_t actionOffset = readSLEB128(&temp);
                if (actionOffset == 0)
                {
                    // End of action list, no matching handler or cleanup found
                    results.reason = _URC_CONTINUE_UNWIND;
                    return;
                }
                // Go to next action
                action += actionOffset;
            }  // there is no break out of this loop, only return
        }
#if !__arm__
        else if (ipOffset < start)
        {
            // There is no call site for this ip
            // Something bad has happened.  We should never get here.
            // Possible stack corruption.
            call_terminate(native_exception, unwind_exception);
        }
#endif  // !__arm__
    }  // there might be some tricky cases which break out of this loop

    // It is possible that no eh table entry specify how to handle
    // this exception. By spec, terminate it immediately.
    call_terminate(native_exception, unwind_exception);
}