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