sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of the License "ARM EABI LICENCE.txt"
sl@0: // which accompanies this distribution, and is available
sl@0: // in kernel/eka/compsupp.
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // e32/compsupp/symaehabi/symbian_support.h
sl@0: // 
sl@0: //
sl@0: 
sl@0: 
sl@0: #ifndef SYMBIAN_SUPPORT_H
sl@0: #define SYMBIAN_SUPPORT_H
sl@0: 
sl@0: #include <e32def_private.h>
sl@0: 
sl@0: #ifdef __cplusplus
sl@0: typedef _Unwind_Control_Block UCB;
sl@0: 
sl@0: using std::terminate_handler;
sl@0: using std::unexpected_handler;
sl@0: using std::terminate;
sl@0: using std::unexpected;
sl@0: using std::type_info;
sl@0: 
sl@0: /* --------- Exception control object: --------- */
sl@0: 
sl@0: // Type __cxa_exception is the combined C++ housekeeping (LEO) and UCB.
sl@0: // It will be followed by the user exception object, hence must ensure
sl@0: // the latter is aligned on an 8 byte boundary.
sl@0: 
sl@0: struct __cxa_exception {
sl@0:   const type_info *exceptionType;       // RTTI object describing the type of the exception
sl@0:   void *(*exceptionDestructor)(void *); // Destructor for the exception object (may be NULL)
sl@0:   unexpected_handler unexpectedHandler; // Handler in force after evaluating throw expr
sl@0:   terminate_handler terminateHandler;   // Handler in force after evaluating throw expr
sl@0:   __cxa_exception *nextCaughtException; // Chain of "currently caught" c++ exception objects
sl@0:   uint32_t handlerCount;                // Count of how many handlers this EO is "caught" in
sl@0:   __cxa_exception *nextPropagatingException; // Chain of objects saved over cleanup
sl@0:   uint32_t propagationCount;            // Count of live propagations (throws) of this EO
sl@0:   UCB ucb;                              // Forces alignment of next item to 8-byte boundary
sl@0: };
sl@0: 
sl@0: 
sl@0: // Exceptions global support
sl@0: typedef void (*handler)(void);
sl@0: 
sl@0: struct __cxa_eh_globals {
sl@0:   uint32_t uncaughtExceptions;               // counter
sl@0:   unexpected_handler unexpectedHandler;      // per-thread handler
sl@0:   terminate_handler terminateHandler;        // per-thread handler
sl@0:   bool implementation_ever_called_terminate; // true if it ever did
sl@0:   handler call_hook;     // transient field to tell terminate/unexpected which hook to call
sl@0:   __cxa_exception *caughtExceptions;         // chain of "caught" exceptions
sl@0:   __cxa_exception *propagatingExceptions;    // chain of "propagating" (in cleanup) exceptions
sl@0:   void *emergency_buffer;                    // emergency buffer for when rest of heap full
sl@0: };
sl@0: 
sl@0: // emergency storage reserve primarily for throwing OOM exceptions
sl@0: struct emergency_eco {
sl@0:   __cxa_exception ep;
sl@0:     XLeaveException aUserLeaveException;
sl@0: };
sl@0: 
sl@0: struct emergency_buffer {
sl@0:   bool inuse;
sl@0:   struct emergency_eco eco;
sl@0: };
sl@0: 
sl@0: 
sl@0: class TCppRTExceptionsGlobals
sl@0: 	{
sl@0: public:
sl@0: 	IMPORT_C TCppRTExceptionsGlobals();
sl@0: private:
sl@0: 	__cxa_eh_globals thread_globals;
sl@0: 	emergency_buffer buffer;
sl@0: 	};
sl@0: 
sl@0: #endif
sl@0: 
sl@0: // Support for finding ROM resident ExIdx tables
sl@0: #define GET_ROM_EST(u) ((TRomExceptionSearchTable *)((u)->unwinder_cache.reserved4))
sl@0: #define SET_ROM_EST(u,e) ((TRomExceptionSearchTable *)((u)->unwinder_cache.reserved4=(uint32_t)e))
sl@0: #define GET_EXCEPTION_DESCRIPTOR(u) ((TExceptionDescriptor *)((u)->unwinder_cache.reserved5))
sl@0: #define SET_EXCEPTION_DESCRIPTOR(u,e) ((TExceptionDescriptor *)((u)->unwinder_cache.reserved5=(uint32_t)e))
sl@0: 
sl@0: // Support for checking which version of EHABI is in play
sl@0: #define EHABI_MASK 0xfffffffc
sl@0: // Checks if image implements V2 of EHABI
sl@0: #define EHABI_V2(u) ((GET_EXCEPTION_DESCRIPTOR(u)->iROSegmentBase) & 1)
sl@0: #define GET_RO_BASE(u) (((u)->iROSegmentBase) & EHABI_MASK)
sl@0: #define ADDRESS_IN_EXCEPTION_DESCRIPTOR_RANGE(addr, aEDp) (((addr) >= GET_RO_BASE(aEDp)) && ((addr) < (aEDp)->iROSegmentLimit))
sl@0: #define GET_EST_FENCEPOST(aESTp) ((aESTp)->iEntries[(aESTp)->iNumEntries])
sl@0: #define ADDRESS_IN_ROM_EST(addr, aESTp) (((addr) >= (aESTp)->iEntries[0]) && ((addr) < GET_EST_FENCEPOST((aESTp))))
sl@0: 
sl@0: 
sl@0: // Non __EPOC32__ versions defined in unwinder.c
sl@0: #define EIT_base(u) \
sl@0:     ((const __EIT_entry *)((GET_EXCEPTION_DESCRIPTOR(u))->iExIdxBase))
sl@0: #define EIT_limit(u) \
sl@0:     ((const __EIT_entry *)((GET_EXCEPTION_DESCRIPTOR(u))->iExIdxLimit))
sl@0: 
sl@0: 
sl@0: #ifdef __cplusplus
sl@0: extern "C" {
sl@0: #endif
sl@0: 
sl@0: typedef unsigned int size_t;
sl@0: IMPORT_C void abort(void);
sl@0: int typenameeq(const char * n1, const char * n2);
sl@0: 
sl@0: #define malloc User::Alloc
sl@0: #define free User::Free
sl@0: 
sl@0: 
sl@0: #ifdef _DEBUG
sl@0: // uncomment this for diagnostic output in UDEB build
sl@0: //#define _DEBUG_SYMBIAN_EH_SUPPORT
sl@0: #endif
sl@0: 
sl@0: #ifdef _DEBUG_SYMBIAN_EH_SUPPORT
sl@0: #define VRS_DIAGNOSTICS
sl@0: #define UNWIND_ACTIVITY_DIAGNOSTICS
sl@0: #define PR_DIAGNOSTICS
sl@0: #define PRINTED_DIAGNOSTICS
sl@0: #define CPP_DIAGNOSTICS
sl@0: #endif
sl@0: #define printf DebugPrintf
sl@0: extern void DebugPrintf(const char *, ...);
sl@0: 
sl@0: #ifdef _DEBUG_SYMBIAN_EH_SUPPORT
sl@0: #define SYMBIAN_EH_SUPPORT_PRINTF DebugPrintf
sl@0: #else
sl@0: #define SYMBIAN_EH_SUPPORT_PRINTF (void)
sl@0: #pragma diag_suppress 174
sl@0: #endif
sl@0: 
sl@0: void InitialiseSymbianSpecificUnwinderCache(uint32_t addr, _Unwind_Control_Block * ucbp);
sl@0: TExceptionDescriptor * ReLoadExceptionDescriptor(uint32_t addr,_Unwind_Control_Block * ucbp);
sl@0: 
sl@0: /* Functions used to convert between segment-relative offsets
sl@0:  * and absolute addresses. These are only used in unwinder.c and must be
sl@0:  * compilable by a C compiler.
sl@0:  */
sl@0: 
sl@0: static __inline void ValidateExceptionDescriptor(uint32_t addr, _Unwind_Control_Block * ucbp)
sl@0: {
sl@0:   // On entry assume ROM exception search table and exception descriptor for current frame cached in ucbp
sl@0:   
sl@0:   // see if addr is in current exception descriptor range
sl@0:   TExceptionDescriptor * aEDp = GET_EXCEPTION_DESCRIPTOR(ucbp);
sl@0:   if (!ADDRESS_IN_EXCEPTION_DESCRIPTOR_RANGE(addr, aEDp)) {
sl@0:     aEDp = ReLoadExceptionDescriptor(addr, ucbp);
sl@0:     // If there's no valid exception descriptor abort.
sl@0:     if (!aEDp) {
sl@0: #ifdef _DEBUG
sl@0:       DebugPrintf("EH ERROR: no exception descriptor for address 0x%08x\n", addr);
sl@0:       DEBUGGER_BOTTLENECK(ucbp, _UASUBSYS_UNWINDER, _UAACT_ENDING, _UAARG_ENDING_UNWINDER_LOOKUPFAILED);
sl@0: #endif
sl@0:       abort();
sl@0:     }
sl@0:   }
sl@0: }
sl@0: 
sl@0: static __inline uint32_t addr_to_ER_RO_offset(uint32_t addr, _Unwind_Control_Block * ucbp)
sl@0: {
sl@0:   TExceptionDescriptor * aEDp = GET_EXCEPTION_DESCRIPTOR(ucbp);
sl@0:   // assume ucbp has the correct exception descriptor for this offset
sl@0:   return addr - GET_RO_BASE(aEDp);
sl@0: }
sl@0: 
sl@0: static __inline uint32_t ER_RO_offset_to_addr(uint32_t offset, _Unwind_Control_Block * ucbp)
sl@0: {
sl@0:   TExceptionDescriptor * aEDp = GET_EXCEPTION_DESCRIPTOR(ucbp);
sl@0:   // assume ucbp has the correct exception descriptor for this offset
sl@0:   return offset + GET_RO_BASE(aEDp);
sl@0: }
sl@0: 
sl@0: // This must be the same as the version in unwinder.c. However its structure is 
sl@0: // governed by the EHABI and so it shouldn't change anytime soon.
sl@0: typedef struct __EIT_entry {
sl@0:   uint32_t fnoffset; /* Place-relative */
sl@0:   uint32_t content;
sl@0: } __EIT_entry;
sl@0: 
sl@0: // The Symbian unwinder uses these specific search functions rather than the generic bsearch
sl@0: // to find entries in the exception index table
sl@0: const __EIT_entry *SearchEITV1(uint32_t return_address_offset, const __EIT_entry *base, unsigned int nelems);
sl@0: __EIT_entry *SearchEITV2(uint32_t return_address, const __EIT_entry *base, unsigned int nelems);
sl@0: 
sl@0: 
sl@0: #ifdef __cplusplus
sl@0: }
sl@0: #endif
sl@0: 
sl@0: #endif // SYMBIAN_SUPPORT_H
sl@0: