kernel/eka/compsupp/symaehabi/symbian_support.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "ARM EABI LICENCE.txt"
       
     5 // which accompanies this distribution, and is available
       
     6 // in kernel/eka/compsupp.
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32/compsupp/symaehabi/symbian_support.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 /* Environment: */
       
    19 #include "unwind_env.h"
       
    20 /* Language-independent unwinder declarations: */
       
    21 #include "unwinder.h"
       
    22 
       
    23 /* Symbian specific support */
       
    24 #include "symbian_support.h"
       
    25 
       
    26 #include <e32def.h>
       
    27 #include <e32def_private.h>
       
    28 #include <e32rom.h>
       
    29 #include <e32svr.h>
       
    30 #include <e32debug.h>
       
    31 
       
    32 static void __default_terminate_handler(void)
       
    33 	{
       
    34 	abort();
       
    35 	}
       
    36 
       
    37 #define NAMES __ARM
       
    38 namespace NAMES { void default_unexpected_handler(void); }
       
    39 
       
    40 EXPORT_C TCppRTExceptionsGlobals::TCppRTExceptionsGlobals()
       
    41 	{
       
    42 	buffer.inuse = false;
       
    43 	thread_globals.uncaughtExceptions = 0;
       
    44 	thread_globals.unexpectedHandler = NAMES::default_unexpected_handler;
       
    45 	thread_globals.terminateHandler = __default_terminate_handler;
       
    46 	thread_globals.implementation_ever_called_terminate = false;
       
    47 	thread_globals.call_hook = NULL;
       
    48 	thread_globals.caughtExceptions = NULL;
       
    49 	thread_globals.propagatingExceptions = NULL;
       
    50 	thread_globals.emergency_buffer = &buffer;
       
    51 	Dll::SetTls(this);
       
    52 	}
       
    53 #if __ARMCC_VERSION < 220000
       
    54 extern "C" 
       
    55 {
       
    56   /*
       
    57     we have to dummy up the following for 2.1. The names changed in the def file
       
    58     since in 2.2 catch handlers should be able to deal with imported RTTI
       
    59 
       
    60 	_ZTI15XLeaveException @ 206 NONAME ; Typeinfo for XLeaveException
       
    61 	_ZTV15XLeaveException @ 207 NONAME ; vtable for XLeaveException
       
    62 	_ZN15XLeaveException16ForceKeyFunctionEv @ 208 NONAME ; the key function for XLeaveException
       
    63   */
       
    64 
       
    65 EXPORT_C void _ZTI15XLeaveException()
       
    66 	{
       
    67 	// reserve a DEF file slot for key function
       
    68 	}
       
    69 
       
    70 EXPORT_C void _ZTV15XLeaveException()
       
    71 	{
       
    72 	// reserve a DEF file slot for vtable
       
    73 	}
       
    74 
       
    75 EXPORT_C void _ZN15XLeaveException16ForceKeyFunctionEv()
       
    76 	{
       
    77 	// reserve a DEF file slot for RTTI
       
    78 	}
       
    79 }
       
    80 
       
    81 #else 
       
    82 // This is the key function that forces the class impedimenta to be get exported in RVCT 2.2 and later.
       
    83 EXPORT_C void XLeaveException::ForceKeyFunction(){}
       
    84 #endif
       
    85 
       
    86 #if 0
       
    87 #pragma push
       
    88 #pragma arm
       
    89 // If the strings were word aligned we could do something like this.
       
    90 // We could even do this if we checked the alignment of the strings.
       
    91 // Unfortunately the chances of them both being word aligned are
       
    92 // sufficiently slim (1/16) that the test for alignment will be carried out
       
    93 // most of time for no good purpose.
       
    94 static inline int typenameeq(const char* n1, const char* n2)
       
    95 	{
       
    96 	if (n1 == n2)
       
    97 		return 1;
       
    98 	int* i1 = (int*)n1;
       
    99 	int* i2 = (int*)n2;
       
   100 	int w1=0;
       
   101 	int w2=0;
       
   102 	int x1, x2;
       
   103 	for (int i = 0, w1=i1[i], w2=i2[i]; w1 == w2; i++, w1=i1[i], w2=i2[i])
       
   104 		{
       
   105 		// they're the same but they might contain the terminator
       
   106 		if (!(w1 & 0xffffff00))
       
   107 			return 1;
       
   108 		if (!(w1 & 0xffff00ff))
       
   109 			return 1;
       
   110 		if (!(w1 & 0xff00ffff))
       
   111 			return 1;
       
   112 		if (!(w1 & 0x00ffffff))
       
   113 			return 1;
       
   114 		}
       
   115 	// they're not the same but they might contain the terminator in the same place
       
   116 	x1 = w1 & 0x000000ff;
       
   117 	x2 = w2 & 0x000000ff;
       
   118 	if (!x1 && !x2)
       
   119 		return 1;
       
   120 	if (x1 != x2)
       
   121 		return 0;
       
   122 
       
   123 	x1 = w1 & 0x0000ff00;
       
   124 	x2 = w2 & 0x0000ff00;
       
   125 	if (!x1 && !x2)
       
   126 		return 1;
       
   127 	if (x1 != x2)
       
   128 		return 0;
       
   129 
       
   130 	x1 = w1 & 0x00ff0000;
       
   131 	x2 = w2 & 0x00ff0000;
       
   132 	if (!x1 && !x2)
       
   133 		return 1;
       
   134 	if (x1 != x2)
       
   135 		return 0;
       
   136 
       
   137 	x1 = w1 & 0xff000000;
       
   138 	x2 = w2 & 0xff000000;
       
   139 	if (!x1 && !x2)
       
   140 		return 1;
       
   141 	if (x1 != x2)
       
   142 		return 0;
       
   143 
       
   144 	// just to keep the compiler quiet
       
   145 	return 0;
       
   146 	}
       
   147 #pragma pop
       
   148 #endif
       
   149 
       
   150 extern "C" {
       
   151 
       
   152 IMPORT_C void abort();
       
   153 
       
   154 TRomExceptionSearchTable * GetROMExceptionSearchTable(void)
       
   155 	{
       
   156 	return (TRomExceptionSearchTable *)((TRomHeader *)UserSvr::RomHeaderAddress())->iRomExceptionSearchTable;
       
   157 	}
       
   158 
       
   159 TExceptionDescriptor* SearchEST(uint32_t addr, TRomExceptionSearchTable* aESTp)
       
   160 	{
       
   161 	uint32_t l = 0;
       
   162 	uint32_t nelems = aESTp->iNumEntries;
       
   163 	uint32_t r = nelems;
       
   164 	uint32_t m = 0;
       
   165 	uint32_t val;
       
   166 	uint32_t* base = (uint32_t*)&aESTp->iEntries[0];
       
   167 	while (r > l)
       
   168 		{
       
   169 		m = (l + r) >> 1;
       
   170 		val = base[m];
       
   171 		if (val > addr)
       
   172 			r = m;
       
   173 		else
       
   174 			l = m + 1;
       
   175 		}
       
   176 	val = base[l-1];
       
   177 	if (addr >= val && addr < base[l])	/* relies on presence of fencepost at the end */
       
   178 		{
       
   179 		const TRomImageHeader* rih = (const TRomImageHeader*)val;
       
   180 		return (TExceptionDescriptor*)rih[-1].iExceptionDescriptor;
       
   181 		}
       
   182 	return 0;
       
   183 	}
       
   184 
       
   185 
       
   186 TExceptionDescriptor * GetRAMLoadedExceptionDescriptor(uint32_t addr)
       
   187 	{
       
   188 	TLinAddr aEDp = UserSvr::ExceptionDescriptor(addr);
       
   189 
       
   190 	SYMBIAN_EH_SUPPORT_PRINTF("UserSvr::ExceptionDescriptor for %08x returned %08x\n", addr, aEDp);
       
   191 
       
   192 	return (TExceptionDescriptor *)(aEDp & 0xfffffffe);
       
   193 	}
       
   194 
       
   195 void InitialiseSymbianSpecificUnwinderCache(uint32_t addr, _Unwind_Control_Block * ucbp)
       
   196 	{
       
   197 	SET_ROM_EST(ucbp, GetROMExceptionSearchTable());
       
   198 	if (!ReLoadExceptionDescriptor(addr, ucbp))
       
   199 		{
       
   200 		SYMBIAN_EH_SUPPORT_PRINTF("EH ERROR: no exception descriptor for address 0x%08x\n", addr);
       
   201 		abort();
       
   202 		}
       
   203 	}
       
   204 
       
   205 TExceptionDescriptor * ReLoadExceptionDescriptor(uint32_t addr, _Unwind_Control_Block * ucbp)
       
   206 	{
       
   207 	/* Check to see if address is in range covered by ROM EST. If
       
   208 	   it is find the exception descriptor for the address,
       
   209 	   checking that the address is in the range covered by the
       
   210 	   descriptor.  Otherwise it comes from a RAM loaded
       
   211 	   executable so get the kernel to find the exception
       
   212 	   descriptor for us.
       
   213 	*/
       
   214 	TRomExceptionSearchTable * aESTp = GET_ROM_EST(ucbp);
       
   215 	TExceptionDescriptor * aEDp = NULL;
       
   216 	if (aESTp && addr >= aESTp->iEntries[0] && addr < GET_EST_FENCEPOST(aESTp))
       
   217 		{
       
   218 		aEDp = SearchEST(addr, aESTp);
       
   219 		goto jobdone;
       
   220 		}
       
   221 	aEDp = GetRAMLoadedExceptionDescriptor(addr);
       
   222 	if (!aEDp)
       
   223 		{
       
   224 		// look in extension ROM if there is one
       
   225 		TUint main_start = UserSvr::RomHeaderAddress();
       
   226 		TUint main_end = main_start + ((TRomHeader*)main_start)->iUncompressedSize;
       
   227 		
       
   228 		TUint rda = UserSvr::RomRootDirectoryAddress();
       
   229 		
       
   230 		// Assume rom starts on multiple of 4k
       
   231 		if (rda > main_end)
       
   232 			{
       
   233 			// ASSUMPTIONS HERE
       
   234 			// 1. root directory is past the end of the main ROM so there must be an extension ROM
       
   235 			// 2. the ROM file system in the extension ROM is at the beginning of the ROM (similar to the
       
   236 			//    main ROM)
       
   237 			// 3. the extension ROM is mapped starting at a megabyte boundary
       
   238 			// Thus the address of the extension ROM header may be obtained by rounding the root directory
       
   239 			// address down to the next megabyte boundary.
       
   240          
       
   241  			TUint ext_start = rda &~ 0x000fffffu;
       
   242 			TRomExceptionSearchTable* extrom_exctab = (TRomExceptionSearchTable*)(((TExtensionRomHeader*)ext_start)->iRomExceptionSearchTable);
       
   243 			if (extrom_exctab && addr >= extrom_exctab->iEntries[0] && addr < GET_EST_FENCEPOST(extrom_exctab))
       
   244 				aEDp = SearchEST(addr, extrom_exctab);
       
   245 			}
       
   246 		}
       
   247 
       
   248 jobdone:
       
   249 	SYMBIAN_EH_SUPPORT_PRINTF("ReLoadExceptionDescriptor: Exception descriptor for address 0x%08x = 0x%08x\n\r", addr, aEDp);
       
   250 
       
   251 	if (aEDp && ADDRESS_IN_EXCEPTION_DESCRIPTOR_RANGE(addr, aEDp))
       
   252 		return SET_EXCEPTION_DESCRIPTOR(ucbp, aEDp);
       
   253 	else
       
   254 	  	return NULL;
       
   255 	}
       
   256 
       
   257 
       
   258 const __EIT_entry* SearchEITV1(uint32_t return_address_offset, const __EIT_entry* base, unsigned int nelems)
       
   259 	{
       
   260 	uint32_t l = 0;
       
   261 	uint32_t r = nelems;
       
   262 	uint32_t m=0;
       
   263 	uint32_t val;
       
   264 	while (r>l)
       
   265 		{
       
   266 		m = (l + r) >> 1;
       
   267 		val = base[m].fnoffset;
       
   268 		if (val > return_address_offset)
       
   269 			r = m;
       
   270 		else
       
   271 			l = m + 1;
       
   272 		}
       
   273 #ifdef _DEBUG
       
   274 	val = base[l-1].fnoffset;
       
   275 	SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV1: Located IDX with fnoffset = %08x\n\r", val);
       
   276 #endif
       
   277 	return base + l - 1;
       
   278 	}
       
   279 
       
   280 /* R_ARM_PREL31 is a place-relative 31-bit signed relocation.  The
       
   281  * routine takes the address of a location that was relocated by
       
   282  * R_ARM_PREL31, and returns an absolute address.
       
   283  */
       
   284 static FORCEINLINE uint32_t __ARM_resolve_prel31(void *p)
       
   285 {
       
   286   return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p);
       
   287 }
       
   288 
       
   289 __EIT_entry* SearchEITV2(uint32_t return_address, const __EIT_entry* base, unsigned int nelems)
       
   290 	{
       
   291 	uint32_t l = 0;
       
   292 	uint32_t r = nelems;
       
   293 	uint32_t m=0;
       
   294 	uint32_t val;
       
   295 	while (r>l)
       
   296 		{
       
   297 		m = (l + r) >> 1;
       
   298 		val = __ARM_resolve_prel31((void *)&base[m].fnoffset);
       
   299 		if (val > return_address)
       
   300 			r = m;
       
   301 		else
       
   302 			l = m + 1;
       
   303 		}
       
   304 #ifdef _DEBUG
       
   305 	val = __ARM_resolve_prel31((void *)&base[l-1].fnoffset);
       
   306 	SYMBIAN_EH_SUPPORT_PRINTF("SearchEITV2: Located IDX with fn address = %08x\n\r", val);
       
   307 #endif
       
   308 	return ((__EIT_entry *)base) + l - 1;
       
   309 	}
       
   310 
       
   311 
       
   312 #ifdef _DEBUG
       
   313 class TestOverflowTruncate8 : public TDes8Overflow
       
   314 	{
       
   315 public:
       
   316 	virtual void Overflow(TDes8& /*aDes*/) {}
       
   317 	};
       
   318 	
       
   319 #endif
       
   320 
       
   321 void DebugPrintf(const char * aFmt, ...)
       
   322 	{
       
   323 #ifdef _DEBUG
       
   324 	TestOverflowTruncate8 overflow;
       
   325 	VA_LIST list;
       
   326 	VA_START(list,aFmt);
       
   327 	TPtrC8 fmt((const TUint8 *)aFmt);
       
   328 	TBuf8<0x100> buf;
       
   329 	buf.AppendFormatList(fmt,list,&overflow);
       
   330 	TBuf<0x100> buf2;
       
   331 	buf2.Copy(buf);
       
   332 	if (buf2[buf2.Length()-1]=='\n') buf2.Append('\r');
       
   333 	RDebug::RawPrint(buf2);
       
   334 #else
       
   335 	(void)aFmt;
       
   336 #endif		
       
   337 	}
       
   338 
       
   339 } // extern "C"