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.cpp sl@0: // sl@0: // sl@0: sl@0: /* Environment: */ sl@0: #include "unwind_env.h" sl@0: /* Language-independent unwinder declarations: */ sl@0: #include "unwinder.h" sl@0: sl@0: /* Symbian specific support */ sl@0: #include "symbian_support.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: static void __default_terminate_handler(void) sl@0: { sl@0: abort(); sl@0: } sl@0: sl@0: #define NAMES __ARM sl@0: namespace NAMES { void default_unexpected_handler(void); } sl@0: sl@0: EXPORT_C TCppRTExceptionsGlobals::TCppRTExceptionsGlobals() sl@0: { sl@0: buffer.inuse = false; sl@0: thread_globals.uncaughtExceptions = 0; sl@0: thread_globals.unexpectedHandler = NAMES::default_unexpected_handler; sl@0: thread_globals.terminateHandler = __default_terminate_handler; sl@0: thread_globals.implementation_ever_called_terminate = false; sl@0: thread_globals.call_hook = NULL; sl@0: thread_globals.caughtExceptions = NULL; sl@0: thread_globals.propagatingExceptions = NULL; sl@0: thread_globals.emergency_buffer = &buffer; sl@0: Dll::SetTls(this); sl@0: } sl@0: #if __ARMCC_VERSION < 220000 sl@0: extern "C" sl@0: { sl@0: /* sl@0: we have to dummy up the following for 2.1. The names changed in the def file sl@0: since in 2.2 catch handlers should be able to deal with imported RTTI sl@0: sl@0: _ZTI15XLeaveException @ 206 NONAME ; Typeinfo for XLeaveException sl@0: _ZTV15XLeaveException @ 207 NONAME ; vtable for XLeaveException sl@0: _ZN15XLeaveException16ForceKeyFunctionEv @ 208 NONAME ; the key function for XLeaveException sl@0: */ sl@0: sl@0: EXPORT_C void _ZTI15XLeaveException() sl@0: { sl@0: // reserve a DEF file slot for key function sl@0: } sl@0: sl@0: EXPORT_C void _ZTV15XLeaveException() sl@0: { sl@0: // reserve a DEF file slot for vtable sl@0: } sl@0: sl@0: EXPORT_C void _ZN15XLeaveException16ForceKeyFunctionEv() sl@0: { sl@0: // reserve a DEF file slot for RTTI sl@0: } sl@0: } sl@0: sl@0: #else sl@0: // This is the key function that forces the class impedimenta to be get exported in RVCT 2.2 and later. sl@0: EXPORT_C void XLeaveException::ForceKeyFunction(){} sl@0: #endif sl@0: sl@0: #if 0 sl@0: #pragma push sl@0: #pragma arm sl@0: // If the strings were word aligned we could do something like this. sl@0: // We could even do this if we checked the alignment of the strings. sl@0: // Unfortunately the chances of them both being word aligned are sl@0: // sufficiently slim (1/16) that the test for alignment will be carried out sl@0: // most of time for no good purpose. sl@0: static inline int typenameeq(const char* n1, const char* n2) sl@0: { sl@0: if (n1 == n2) sl@0: return 1; sl@0: int* i1 = (int*)n1; sl@0: int* i2 = (int*)n2; sl@0: int w1=0; sl@0: int w2=0; sl@0: int x1, x2; sl@0: for (int i = 0, w1=i1[i], w2=i2[i]; w1 == w2; i++, w1=i1[i], w2=i2[i]) sl@0: { sl@0: // they're the same but they might contain the terminator sl@0: if (!(w1 & 0xffffff00)) sl@0: return 1; sl@0: if (!(w1 & 0xffff00ff)) sl@0: return 1; sl@0: if (!(w1 & 0xff00ffff)) sl@0: return 1; sl@0: if (!(w1 & 0x00ffffff)) sl@0: return 1; sl@0: } sl@0: // they're not the same but they might contain the terminator in the same place sl@0: x1 = w1 & 0x000000ff; sl@0: x2 = w2 & 0x000000ff; sl@0: if (!x1 && !x2) sl@0: return 1; sl@0: if (x1 != x2) sl@0: return 0; sl@0: sl@0: x1 = w1 & 0x0000ff00; sl@0: x2 = w2 & 0x0000ff00; sl@0: if (!x1 && !x2) sl@0: return 1; sl@0: if (x1 != x2) sl@0: return 0; sl@0: sl@0: x1 = w1 & 0x00ff0000; sl@0: x2 = w2 & 0x00ff0000; sl@0: if (!x1 && !x2) sl@0: return 1; sl@0: if (x1 != x2) sl@0: return 0; sl@0: sl@0: x1 = w1 & 0xff000000; sl@0: x2 = w2 & 0xff000000; sl@0: if (!x1 && !x2) sl@0: return 1; sl@0: if (x1 != x2) sl@0: return 0; sl@0: sl@0: // just to keep the compiler quiet sl@0: return 0; sl@0: } sl@0: #pragma pop sl@0: #endif sl@0: sl@0: extern "C" { sl@0: sl@0: IMPORT_C void abort(); sl@0: sl@0: TRomExceptionSearchTable * GetROMExceptionSearchTable(void) sl@0: { sl@0: return (TRomExceptionSearchTable *)((TRomHeader *)UserSvr::RomHeaderAddress())->iRomExceptionSearchTable; sl@0: } sl@0: sl@0: TExceptionDescriptor* SearchEST(uint32_t addr, TRomExceptionSearchTable* aESTp) sl@0: { sl@0: uint32_t l = 0; sl@0: uint32_t nelems = aESTp->iNumEntries; sl@0: uint32_t r = nelems; sl@0: uint32_t m = 0; sl@0: uint32_t val; sl@0: uint32_t* base = (uint32_t*)&aESTp->iEntries[0]; sl@0: while (r > l) sl@0: { sl@0: m = (l + r) >> 1; sl@0: val = base[m]; sl@0: if (val > addr) sl@0: r = m; sl@0: else sl@0: l = m + 1; sl@0: } sl@0: val = base[l-1]; sl@0: if (addr >= val && addr < base[l]) /* relies on presence of fencepost at the end */ sl@0: { sl@0: const TRomImageHeader* rih = (const TRomImageHeader*)val; sl@0: return (TExceptionDescriptor*)rih[-1].iExceptionDescriptor; sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: TExceptionDescriptor * GetRAMLoadedExceptionDescriptor(uint32_t addr) sl@0: { sl@0: TLinAddr aEDp = UserSvr::ExceptionDescriptor(addr); sl@0: sl@0: SYMBIAN_EH_SUPPORT_PRINTF("UserSvr::ExceptionDescriptor for %08x returned %08x\n", addr, aEDp); sl@0: sl@0: return (TExceptionDescriptor *)(aEDp & 0xfffffffe); sl@0: } sl@0: sl@0: void InitialiseSymbianSpecificUnwinderCache(uint32_t addr, _Unwind_Control_Block * ucbp) sl@0: { sl@0: SET_ROM_EST(ucbp, GetROMExceptionSearchTable()); sl@0: if (!ReLoadExceptionDescriptor(addr, ucbp)) sl@0: { sl@0: SYMBIAN_EH_SUPPORT_PRINTF("EH ERROR: no exception descriptor for address 0x%08x\n", addr); sl@0: abort(); sl@0: } sl@0: } sl@0: sl@0: TExceptionDescriptor * ReLoadExceptionDescriptor(uint32_t addr, _Unwind_Control_Block * ucbp) sl@0: { sl@0: /* Check to see if address is in range covered by ROM EST. If sl@0: it is find the exception descriptor for the address, sl@0: checking that the address is in the range covered by the sl@0: descriptor. Otherwise it comes from a RAM loaded sl@0: executable so get the kernel to find the exception sl@0: descriptor for us. sl@0: */ sl@0: TRomExceptionSearchTable * aESTp = GET_ROM_EST(ucbp); sl@0: TExceptionDescriptor * aEDp = NULL; sl@0: if (aESTp && addr >= aESTp->iEntries[0] && addr < GET_EST_FENCEPOST(aESTp)) sl@0: { sl@0: aEDp = SearchEST(addr, aESTp); sl@0: goto jobdone; sl@0: } sl@0: aEDp = GetRAMLoadedExceptionDescriptor(addr); sl@0: if (!aEDp) sl@0: { sl@0: // look in extension ROM if there is one sl@0: TUint main_start = UserSvr::RomHeaderAddress(); sl@0: TUint main_end = main_start + ((TRomHeader*)main_start)->iUncompressedSize; sl@0: sl@0: TUint rda = UserSvr::RomRootDirectoryAddress(); sl@0: sl@0: // Assume rom starts on multiple of 4k sl@0: if (rda > main_end) sl@0: { sl@0: // ASSUMPTIONS HERE sl@0: // 1. root directory is past the end of the main ROM so there must be an extension ROM sl@0: // 2. the ROM file system in the extension ROM is at the beginning of the ROM (similar to the sl@0: // main ROM) sl@0: // 3. the extension ROM is mapped starting at a megabyte boundary sl@0: // Thus the address of the extension ROM header may be obtained by rounding the root directory sl@0: // address down to the next megabyte boundary. sl@0: sl@0: TUint ext_start = rda &~ 0x000fffffu; sl@0: TRomExceptionSearchTable* extrom_exctab = (TRomExceptionSearchTable*)(((TExtensionRomHeader*)ext_start)->iRomExceptionSearchTable); sl@0: if (extrom_exctab && addr >= extrom_exctab->iEntries[0] && addr < GET_EST_FENCEPOST(extrom_exctab)) sl@0: aEDp = SearchEST(addr, extrom_exctab); sl@0: } sl@0: } sl@0: sl@0: jobdone: sl@0: SYMBIAN_EH_SUPPORT_PRINTF("ReLoadExceptionDescriptor: Exception descriptor for address 0x%08x = 0x%08x\n\r", addr, aEDp); sl@0: sl@0: if (aEDp && ADDRESS_IN_EXCEPTION_DESCRIPTOR_RANGE(addr, aEDp)) sl@0: return SET_EXCEPTION_DESCRIPTOR(ucbp, aEDp); sl@0: else sl@0: return NULL; sl@0: } sl@0: sl@0: sl@0: const __EIT_entry* SearchEITV1(uint32_t return_address_offset, const __EIT_entry* base, unsigned int nelems) sl@0: { sl@0: uint32_t l = 0; sl@0: uint32_t r = nelems; sl@0: uint32_t m=0; sl@0: uint32_t val; sl@0: while (r>l) sl@0: { sl@0: m = (l + r) >> 1; sl@0: val = base[m].fnoffset; sl@0: if (val > return_address_offset) sl@0: r = m; sl@0: else sl@0: l = m + 1; sl@0: } sl@0: #ifdef _DEBUG sl@0: val = base[l-1].fnoffset; sl@0: SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV1: Located IDX with fnoffset = %08x\n\r", val); sl@0: #endif sl@0: return base + l - 1; sl@0: } sl@0: sl@0: /* R_ARM_PREL31 is a place-relative 31-bit signed relocation. The sl@0: * routine takes the address of a location that was relocated by sl@0: * R_ARM_PREL31, and returns an absolute address. sl@0: */ sl@0: static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p) sl@0: { sl@0: return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p); sl@0: } sl@0: sl@0: __EIT_entry* SearchEITV2(uint32_t return_address, const __EIT_entry* base, unsigned int nelems) sl@0: { sl@0: uint32_t l = 0; sl@0: uint32_t r = nelems; sl@0: uint32_t m=0; sl@0: uint32_t val; sl@0: while (r>l) sl@0: { sl@0: m = (l + r) >> 1; sl@0: val = __ARM_resolve_prel31((void *)&base[m].fnoffset); sl@0: if (val > return_address) sl@0: r = m; sl@0: else sl@0: l = m + 1; sl@0: } sl@0: #ifdef _DEBUG sl@0: val = __ARM_resolve_prel31((void *)&base[l-1].fnoffset); sl@0: SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV2: Located IDX with fn address = %08x\n\r", val); sl@0: #endif sl@0: return ((__EIT_entry *)base) + l - 1; sl@0: } sl@0: sl@0: sl@0: #ifdef _DEBUG sl@0: class TestOverflowTruncate8 : public TDes8Overflow sl@0: { sl@0: public: sl@0: virtual void Overflow(TDes8& /*aDes*/) {} sl@0: }; sl@0: sl@0: #endif sl@0: sl@0: void DebugPrintf(const char * aFmt, ...) sl@0: { sl@0: #ifdef _DEBUG sl@0: TestOverflowTruncate8 overflow; sl@0: VA_LIST list; sl@0: VA_START(list,aFmt); sl@0: TPtrC8 fmt((const TUint8 *)aFmt); sl@0: TBuf8<0x100> buf; sl@0: buf.AppendFormatList(fmt,list,&overflow); sl@0: TBuf<0x100> buf2; sl@0: buf2.Copy(buf); sl@0: if (buf2[buf2.Length()-1]=='\n') buf2.Append('\r'); sl@0: RDebug::RawPrint(buf2); sl@0: #else sl@0: (void)aFmt; sl@0: #endif sl@0: } sl@0: sl@0: } // extern "C"