os/kernelhwsrv/kernel/eka/compsupp/symaehabi/symbian_support.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kernel/eka/compsupp/symaehabi/symbian_support.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,339 @@
     1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "ARM EABI LICENCE.txt"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// in kernel/eka/compsupp.
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// e32/compsupp/symaehabi/symbian_support.cpp
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +/* Environment: */
    1.22 +#include "unwind_env.h"
    1.23 +/* Language-independent unwinder declarations: */
    1.24 +#include "unwinder.h"
    1.25 +
    1.26 +/* Symbian specific support */
    1.27 +#include "symbian_support.h"
    1.28 +
    1.29 +#include <e32def.h>
    1.30 +#include <e32def_private.h>
    1.31 +#include <e32rom.h>
    1.32 +#include <e32svr.h>
    1.33 +#include <e32debug.h>
    1.34 +
    1.35 +static void __default_terminate_handler(void)
    1.36 +	{
    1.37 +	abort();
    1.38 +	}
    1.39 +
    1.40 +#define NAMES __ARM
    1.41 +namespace NAMES { void default_unexpected_handler(void); }
    1.42 +
    1.43 +EXPORT_C TCppRTExceptionsGlobals::TCppRTExceptionsGlobals()
    1.44 +	{
    1.45 +	buffer.inuse = false;
    1.46 +	thread_globals.uncaughtExceptions = 0;
    1.47 +	thread_globals.unexpectedHandler = NAMES::default_unexpected_handler;
    1.48 +	thread_globals.terminateHandler = __default_terminate_handler;
    1.49 +	thread_globals.implementation_ever_called_terminate = false;
    1.50 +	thread_globals.call_hook = NULL;
    1.51 +	thread_globals.caughtExceptions = NULL;
    1.52 +	thread_globals.propagatingExceptions = NULL;
    1.53 +	thread_globals.emergency_buffer = &buffer;
    1.54 +	Dll::SetTls(this);
    1.55 +	}
    1.56 +#if __ARMCC_VERSION < 220000
    1.57 +extern "C" 
    1.58 +{
    1.59 +  /*
    1.60 +    we have to dummy up the following for 2.1. The names changed in the def file
    1.61 +    since in 2.2 catch handlers should be able to deal with imported RTTI
    1.62 +
    1.63 +	_ZTI15XLeaveException @ 206 NONAME ; Typeinfo for XLeaveException
    1.64 +	_ZTV15XLeaveException @ 207 NONAME ; vtable for XLeaveException
    1.65 +	_ZN15XLeaveException16ForceKeyFunctionEv @ 208 NONAME ; the key function for XLeaveException
    1.66 +  */
    1.67 +
    1.68 +EXPORT_C void _ZTI15XLeaveException()
    1.69 +	{
    1.70 +	// reserve a DEF file slot for key function
    1.71 +	}
    1.72 +
    1.73 +EXPORT_C void _ZTV15XLeaveException()
    1.74 +	{
    1.75 +	// reserve a DEF file slot for vtable
    1.76 +	}
    1.77 +
    1.78 +EXPORT_C void _ZN15XLeaveException16ForceKeyFunctionEv()
    1.79 +	{
    1.80 +	// reserve a DEF file slot for RTTI
    1.81 +	}
    1.82 +}
    1.83 +
    1.84 +#else 
    1.85 +// This is the key function that forces the class impedimenta to be get exported in RVCT 2.2 and later.
    1.86 +EXPORT_C void XLeaveException::ForceKeyFunction(){}
    1.87 +#endif
    1.88 +
    1.89 +#if 0
    1.90 +#pragma push
    1.91 +#pragma arm
    1.92 +// If the strings were word aligned we could do something like this.
    1.93 +// We could even do this if we checked the alignment of the strings.
    1.94 +// Unfortunately the chances of them both being word aligned are
    1.95 +// sufficiently slim (1/16) that the test for alignment will be carried out
    1.96 +// most of time for no good purpose.
    1.97 +static inline int typenameeq(const char* n1, const char* n2)
    1.98 +	{
    1.99 +	if (n1 == n2)
   1.100 +		return 1;
   1.101 +	int* i1 = (int*)n1;
   1.102 +	int* i2 = (int*)n2;
   1.103 +	int w1=0;
   1.104 +	int w2=0;
   1.105 +	int x1, x2;
   1.106 +	for (int i = 0, w1=i1[i], w2=i2[i]; w1 == w2; i++, w1=i1[i], w2=i2[i])
   1.107 +		{
   1.108 +		// they're the same but they might contain the terminator
   1.109 +		if (!(w1 & 0xffffff00))
   1.110 +			return 1;
   1.111 +		if (!(w1 & 0xffff00ff))
   1.112 +			return 1;
   1.113 +		if (!(w1 & 0xff00ffff))
   1.114 +			return 1;
   1.115 +		if (!(w1 & 0x00ffffff))
   1.116 +			return 1;
   1.117 +		}
   1.118 +	// they're not the same but they might contain the terminator in the same place
   1.119 +	x1 = w1 & 0x000000ff;
   1.120 +	x2 = w2 & 0x000000ff;
   1.121 +	if (!x1 && !x2)
   1.122 +		return 1;
   1.123 +	if (x1 != x2)
   1.124 +		return 0;
   1.125 +
   1.126 +	x1 = w1 & 0x0000ff00;
   1.127 +	x2 = w2 & 0x0000ff00;
   1.128 +	if (!x1 && !x2)
   1.129 +		return 1;
   1.130 +	if (x1 != x2)
   1.131 +		return 0;
   1.132 +
   1.133 +	x1 = w1 & 0x00ff0000;
   1.134 +	x2 = w2 & 0x00ff0000;
   1.135 +	if (!x1 && !x2)
   1.136 +		return 1;
   1.137 +	if (x1 != x2)
   1.138 +		return 0;
   1.139 +
   1.140 +	x1 = w1 & 0xff000000;
   1.141 +	x2 = w2 & 0xff000000;
   1.142 +	if (!x1 && !x2)
   1.143 +		return 1;
   1.144 +	if (x1 != x2)
   1.145 +		return 0;
   1.146 +
   1.147 +	// just to keep the compiler quiet
   1.148 +	return 0;
   1.149 +	}
   1.150 +#pragma pop
   1.151 +#endif
   1.152 +
   1.153 +extern "C" {
   1.154 +
   1.155 +IMPORT_C void abort();
   1.156 +
   1.157 +TRomExceptionSearchTable * GetROMExceptionSearchTable(void)
   1.158 +	{
   1.159 +	return (TRomExceptionSearchTable *)((TRomHeader *)UserSvr::RomHeaderAddress())->iRomExceptionSearchTable;
   1.160 +	}
   1.161 +
   1.162 +TExceptionDescriptor* SearchEST(uint32_t addr, TRomExceptionSearchTable* aESTp)
   1.163 +	{
   1.164 +	uint32_t l = 0;
   1.165 +	uint32_t nelems = aESTp->iNumEntries;
   1.166 +	uint32_t r = nelems;
   1.167 +	uint32_t m = 0;
   1.168 +	uint32_t val;
   1.169 +	uint32_t* base = (uint32_t*)&aESTp->iEntries[0];
   1.170 +	while (r > l)
   1.171 +		{
   1.172 +		m = (l + r) >> 1;
   1.173 +		val = base[m];
   1.174 +		if (val > addr)
   1.175 +			r = m;
   1.176 +		else
   1.177 +			l = m + 1;
   1.178 +		}
   1.179 +	val = base[l-1];
   1.180 +	if (addr >= val && addr < base[l])	/* relies on presence of fencepost at the end */
   1.181 +		{
   1.182 +		const TRomImageHeader* rih = (const TRomImageHeader*)val;
   1.183 +		return (TExceptionDescriptor*)rih[-1].iExceptionDescriptor;
   1.184 +		}
   1.185 +	return 0;
   1.186 +	}
   1.187 +
   1.188 +
   1.189 +TExceptionDescriptor * GetRAMLoadedExceptionDescriptor(uint32_t addr)
   1.190 +	{
   1.191 +	TLinAddr aEDp = UserSvr::ExceptionDescriptor(addr);
   1.192 +
   1.193 +	SYMBIAN_EH_SUPPORT_PRINTF("UserSvr::ExceptionDescriptor for %08x returned %08x\n", addr, aEDp);
   1.194 +
   1.195 +	return (TExceptionDescriptor *)(aEDp & 0xfffffffe);
   1.196 +	}
   1.197 +
   1.198 +void InitialiseSymbianSpecificUnwinderCache(uint32_t addr, _Unwind_Control_Block * ucbp)
   1.199 +	{
   1.200 +	SET_ROM_EST(ucbp, GetROMExceptionSearchTable());
   1.201 +	if (!ReLoadExceptionDescriptor(addr, ucbp))
   1.202 +		{
   1.203 +		SYMBIAN_EH_SUPPORT_PRINTF("EH ERROR: no exception descriptor for address 0x%08x\n", addr);
   1.204 +		abort();
   1.205 +		}
   1.206 +	}
   1.207 +
   1.208 +TExceptionDescriptor * ReLoadExceptionDescriptor(uint32_t addr, _Unwind_Control_Block * ucbp)
   1.209 +	{
   1.210 +	/* Check to see if address is in range covered by ROM EST. If
   1.211 +	   it is find the exception descriptor for the address,
   1.212 +	   checking that the address is in the range covered by the
   1.213 +	   descriptor.  Otherwise it comes from a RAM loaded
   1.214 +	   executable so get the kernel to find the exception
   1.215 +	   descriptor for us.
   1.216 +	*/
   1.217 +	TRomExceptionSearchTable * aESTp = GET_ROM_EST(ucbp);
   1.218 +	TExceptionDescriptor * aEDp = NULL;
   1.219 +	if (aESTp && addr >= aESTp->iEntries[0] && addr < GET_EST_FENCEPOST(aESTp))
   1.220 +		{
   1.221 +		aEDp = SearchEST(addr, aESTp);
   1.222 +		goto jobdone;
   1.223 +		}
   1.224 +	aEDp = GetRAMLoadedExceptionDescriptor(addr);
   1.225 +	if (!aEDp)
   1.226 +		{
   1.227 +		// look in extension ROM if there is one
   1.228 +		TUint main_start = UserSvr::RomHeaderAddress();
   1.229 +		TUint main_end = main_start + ((TRomHeader*)main_start)->iUncompressedSize;
   1.230 +		
   1.231 +		TUint rda = UserSvr::RomRootDirectoryAddress();
   1.232 +		
   1.233 +		// Assume rom starts on multiple of 4k
   1.234 +		if (rda > main_end)
   1.235 +			{
   1.236 +			// ASSUMPTIONS HERE
   1.237 +			// 1. root directory is past the end of the main ROM so there must be an extension ROM
   1.238 +			// 2. the ROM file system in the extension ROM is at the beginning of the ROM (similar to the
   1.239 +			//    main ROM)
   1.240 +			// 3. the extension ROM is mapped starting at a megabyte boundary
   1.241 +			// Thus the address of the extension ROM header may be obtained by rounding the root directory
   1.242 +			// address down to the next megabyte boundary.
   1.243 +         
   1.244 + 			TUint ext_start = rda &~ 0x000fffffu;
   1.245 +			TRomExceptionSearchTable* extrom_exctab = (TRomExceptionSearchTable*)(((TExtensionRomHeader*)ext_start)->iRomExceptionSearchTable);
   1.246 +			if (extrom_exctab && addr >= extrom_exctab->iEntries[0] && addr < GET_EST_FENCEPOST(extrom_exctab))
   1.247 +				aEDp = SearchEST(addr, extrom_exctab);
   1.248 +			}
   1.249 +		}
   1.250 +
   1.251 +jobdone:
   1.252 +	SYMBIAN_EH_SUPPORT_PRINTF("ReLoadExceptionDescriptor: Exception descriptor for address 0x%08x = 0x%08x\n\r", addr, aEDp);
   1.253 +
   1.254 +	if (aEDp && ADDRESS_IN_EXCEPTION_DESCRIPTOR_RANGE(addr, aEDp))
   1.255 +		return SET_EXCEPTION_DESCRIPTOR(ucbp, aEDp);
   1.256 +	else
   1.257 +	  	return NULL;
   1.258 +	}
   1.259 +
   1.260 +
   1.261 +const __EIT_entry* SearchEITV1(uint32_t return_address_offset, const __EIT_entry* base, unsigned int nelems)
   1.262 +	{
   1.263 +	uint32_t l = 0;
   1.264 +	uint32_t r = nelems;
   1.265 +	uint32_t m=0;
   1.266 +	uint32_t val;
   1.267 +	while (r>l)
   1.268 +		{
   1.269 +		m = (l + r) >> 1;
   1.270 +		val = base[m].fnoffset;
   1.271 +		if (val > return_address_offset)
   1.272 +			r = m;
   1.273 +		else
   1.274 +			l = m + 1;
   1.275 +		}
   1.276 +#ifdef _DEBUG
   1.277 +	val = base[l-1].fnoffset;
   1.278 +	SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV1: Located IDX with fnoffset = %08x\n\r", val);
   1.279 +#endif
   1.280 +	return base + l - 1;
   1.281 +	}
   1.282 +
   1.283 +/* R_ARM_PREL31 is a place-relative 31-bit signed relocation.  The
   1.284 + * routine takes the address of a location that was relocated by
   1.285 + * R_ARM_PREL31, and returns an absolute address.
   1.286 + */
   1.287 +static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p)
   1.288 +{
   1.289 +  return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p);
   1.290 +}
   1.291 +
   1.292 +__EIT_entry* SearchEITV2(uint32_t return_address, const __EIT_entry* base, unsigned int nelems)
   1.293 +	{
   1.294 +	uint32_t l = 0;
   1.295 +	uint32_t r = nelems;
   1.296 +	uint32_t m=0;
   1.297 +	uint32_t val;
   1.298 +	while (r>l)
   1.299 +		{
   1.300 +		m = (l + r) >> 1;
   1.301 +		val = __ARM_resolve_prel31((void *)&base[m].fnoffset);
   1.302 +		if (val > return_address)
   1.303 +			r = m;
   1.304 +		else
   1.305 +			l = m + 1;
   1.306 +		}
   1.307 +#ifdef _DEBUG
   1.308 +	val = __ARM_resolve_prel31((void *)&base[l-1].fnoffset);
   1.309 +	SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV2: Located IDX with fn address = %08x\n\r", val);
   1.310 +#endif
   1.311 +	return ((__EIT_entry *)base) + l - 1;
   1.312 +	}
   1.313 +
   1.314 +
   1.315 +#ifdef _DEBUG
   1.316 +class TestOverflowTruncate8 : public TDes8Overflow
   1.317 +	{
   1.318 +public:
   1.319 +	virtual void Overflow(TDes8& /*aDes*/) {}
   1.320 +	};
   1.321 +	
   1.322 +#endif
   1.323 +
   1.324 +void DebugPrintf(const char * aFmt, ...)
   1.325 +	{
   1.326 +#ifdef _DEBUG
   1.327 +	TestOverflowTruncate8 overflow;
   1.328 +	VA_LIST list;
   1.329 +	VA_START(list,aFmt);
   1.330 +	TPtrC8 fmt((const TUint8 *)aFmt);
   1.331 +	TBuf8<0x100> buf;
   1.332 +	buf.AppendFormatList(fmt,list,&overflow);
   1.333 +	TBuf<0x100> buf2;
   1.334 +	buf2.Copy(buf);
   1.335 +	if (buf2[buf2.Length()-1]=='\n') buf2.Append('\r');
   1.336 +	RDebug::RawPrint(buf2);
   1.337 +#else
   1.338 +	(void)aFmt;
   1.339 +#endif		
   1.340 +	}
   1.341 +
   1.342 +} // extern "C"