|
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 "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\cppexceptions\t_romtable.cpp |
|
15 // Overview: |
|
16 // Check accessibility and integrity of ROM exception search table. |
|
17 // API Information: |
|
18 // TRomHeader, TRomExceptionSearchTable, TExceptionDescriptor |
|
19 // Details: |
|
20 // - Get the ROM exception search table, verify results are as expected. |
|
21 // - Check that the correct exception descriptor is returned by |
|
22 // GetExceptionDescriptor(). |
|
23 // - Check that the correct index table entry can be found. |
|
24 // - Initialize the unwinder cache of a UCB with an exception descriptor |
|
25 // and check we get the right result. |
|
26 // - Throw and catch a variety of exceptions and verify results are as expected. |
|
27 // Platforms/Drives/Compatibility: |
|
28 // Hardware (Automatic). |
|
29 // Assumptions/Requirement/Pre-requisites: |
|
30 // Failures and causes: |
|
31 // Base Port information: |
|
32 // |
|
33 // |
|
34 |
|
35 /* Environment: */ |
|
36 #include "unwind_env.h" |
|
37 /* Language-independent unwinder declarations: */ |
|
38 #include "unwinder.h" |
|
39 |
|
40 #include "symbian_support.h" |
|
41 |
|
42 #include <f32file.h> |
|
43 #include <e32test.h> |
|
44 #include <e32rom.h> |
|
45 #include <cpudefs.h> |
|
46 |
|
47 GLDEF_D RTest test(_L("T_ROMTABLE")); |
|
48 |
|
49 TRomHeader * pTheRomHeader; |
|
50 char * GetExceptionDescriptor(void); |
|
51 extern "C" { |
|
52 IMPORT_C TRomExceptionSearchTable * GetROMExceptionSearchTable(void); |
|
53 IMPORT_C TExceptionDescriptor * SearchEST(uint32_t addr, TRomExceptionSearchTable * aESTp); |
|
54 TExceptionDescriptor * GetRAMLoadedExceptionDescriptor(uint32_t addr); |
|
55 IMPORT_C const __EIT_entry *SearchEITV1(uint32_t return_address_offset, const __EIT_entry *base, unsigned int nelems); |
|
56 IMPORT_C __EIT_entry* SearchEITV2(uint32_t return_address, const __EIT_entry* base, unsigned int nelems); |
|
57 TExceptionDescriptor * ReLoadExceptionDescriptor(uint32_t addr, _Unwind_Control_Block * ucbp); |
|
58 IMPORT_C void InitialiseSymbianSpecificUnwinderCache(uint32_t addr, _Unwind_Control_Block * ucbp); |
|
59 |
|
60 void *__cxa_allocate_exception(size_t size); |
|
61 IMPORT_C __cxa_eh_globals * __cxa_get_globals(); |
|
62 |
|
63 #ifdef _DEBUG |
|
64 IMPORT_C void DebugPrintf(const char * aFmt, ...); |
|
65 #endif |
|
66 } |
|
67 |
|
68 int catcher(int x); |
|
69 int catcher2(int x); |
|
70 int catcher3(int x); |
|
71 int catcher4(int x); |
|
72 int catcher5(int x); |
|
73 void TestUncaught(void); |
|
74 const __EIT_entry * DumbGetEITV1(TUint32 offset, const __EIT_entry * base, TUint32 n); |
|
75 __EIT_entry * DumbGetEITV2(TUint32 addr, __EIT_entry * base, TUint32 n); |
|
76 |
|
77 GLDEF_C TInt E32Main() |
|
78 { |
|
79 test.Start(_L("Check accessibility and integrity of ROM exception search table")); |
|
80 |
|
81 TRomExceptionSearchTable * pEST = GetROMExceptionSearchTable(); |
|
82 test.Printf(_L("ROM EST @ %08x\n"), pEST); |
|
83 test(pEST != 0); |
|
84 |
|
85 test.Printf(_L("ROM EST contains %d entries\n"), pEST->iNumEntries); |
|
86 |
|
87 for (int i=0; i<pEST->iNumEntries; i++) |
|
88 { |
|
89 TRomImageHeader * pE = (TRomImageHeader *)pEST->iEntries[i]; |
|
90 TRomImageHeader * pH = pE -1; |
|
91 TUint xd = pH->iExceptionDescriptor; |
|
92 if ((xd&1)==0 || xd==0xffffffffu) |
|
93 continue; |
|
94 xd &= ~1; |
|
95 TExceptionDescriptor * pED = (TExceptionDescriptor *) ((char *)pE + xd); |
|
96 char * aExIdxBase = (char *)pED->iExIdxBase; |
|
97 char * aExIdxLimit = (char *)pED->iExIdxLimit; |
|
98 char * aROBase = (char *) pED->iROSegmentBase; |
|
99 char * aROLimit = (char *)pED->iROSegmentLimit; |
|
100 |
|
101 test.Printf(_L("%d\n"),i); |
|
102 |
|
103 test(aExIdxBase <= aExIdxLimit); |
|
104 |
|
105 test(aROBase <= aROLimit); |
|
106 |
|
107 test(aROBase <= aExIdxBase); |
|
108 test(aExIdxLimit <= aROLimit); |
|
109 } |
|
110 test.Printf(_L("\n")); |
|
111 |
|
112 #ifdef __SUPPORT_CPP_EXCEPTIONS__ |
|
113 // Check we get the right Exception Descriptor |
|
114 char * myExcpDesc = GetExceptionDescriptor(); |
|
115 uint32_t addr = (uint32_t)GetExceptionDescriptor; |
|
116 |
|
117 test.Printf(_L("Checking &GetExceptionDescriptor [%08x] in EST range: %08x - %08x\n"), |
|
118 addr, pEST->iEntries[0], GET_EST_FENCEPOST(pEST)); |
|
119 test(addr >= pEST->iEntries[0] && addr < GET_EST_FENCEPOST(pEST)); |
|
120 TExceptionDescriptor * aExcpDescP = SearchEST(addr, pEST); |
|
121 test.Printf(_L("Found entry %08x in EST\n"), aExcpDescP); |
|
122 test(aExcpDescP != NULL); |
|
123 test.Printf(_L("Check myExcpDesc[%08x] == aExcpDescP[%08x]\n"), myExcpDesc, aExcpDescP); |
|
124 test(myExcpDesc==(char*)aExcpDescP); |
|
125 |
|
126 // Now check we can find the right entry in the index table. |
|
127 __EIT_entry * aExIdxBase1 = (__EIT_entry *)aExcpDescP->iExIdxBase; |
|
128 __EIT_entry * aExIdxLimit1 = (__EIT_entry *)aExcpDescP->iExIdxLimit; |
|
129 unsigned int nelems = aExIdxLimit1 - aExIdxBase1; |
|
130 uint32_t aROBase1 = (uint32_t)aExcpDescP->iROSegmentBase; |
|
131 int ehabiv2 = aROBase1 & 1; |
|
132 aROBase1 = aROBase1 & EHABI_MASK; |
|
133 uint32_t aRetOffest = addr - aROBase1; |
|
134 test.Printf(_L("EHABI_V2= %d: Looking up %08x with base %08x in ExIdx @ %08x with %d entries\n"), |
|
135 ehabiv2, addr, aROBase1, aExIdxBase1, nelems); |
|
136 if (ehabiv2) { |
|
137 __EIT_entry * aResult = SearchEITV2(addr, aExIdxBase1, nelems); |
|
138 __EIT_entry * aResult1 = DumbGetEITV2(addr, aExIdxBase1, nelems); |
|
139 test.Printf(_L("Check result %08x == %08x\n"), aResult, aResult1); |
|
140 test(aResult == aResult1); |
|
141 } else { |
|
142 const __EIT_entry * aResult = SearchEITV1(aRetOffest, aExIdxBase1, nelems); |
|
143 const __EIT_entry * aResult1 = DumbGetEITV1(aRetOffest, aExIdxBase1, nelems); |
|
144 test.Printf(_L("Check result %08x == %08x\n"), aResult, aResult1); |
|
145 test(aResult == aResult1); |
|
146 } |
|
147 #ifdef _DEBUG |
|
148 DebugPrintf("Exception diagnostic print support is working if you can see this!!\n\r"); |
|
149 #else |
|
150 test.Printf(_L("Exception diagnostic print support only available in UDEB builds - not tested\n")); |
|
151 #endif |
|
152 |
|
153 //check we've got some eh_globals |
|
154 __cxa_eh_globals *g = __cxa_get_globals(); |
|
155 test.Printf(_L("Exception Handling globals for this thread allocated @ %08x\n"), g); |
|
156 test(g != NULL); |
|
157 test.Printf(_L("Emergency Buffer @ %08x\n"), g->emergency_buffer); |
|
158 |
|
159 // now initialize a the unwinder cache of a ucbp with an exception descriptor |
|
160 // and check we get the right result. |
|
161 test.Printf(_L("Allocate an empty exception object\n")); |
|
162 __cxa_exception *ep = ((__cxa_exception *)__cxa_allocate_exception(0)) - 1; |
|
163 test.Printf(_L("Empty Exception Object @ %08x UCB @ %08x\n"), ep, &ep->ucb); |
|
164 test.Printf(_L("Initialize the UCB with the EST and the current exception descriptor\n")); |
|
165 InitialiseSymbianSpecificUnwinderCache(addr, &ep->ucb); |
|
166 test.Printf(_L("Check the EST in the UCB [%08x] == %08x and the Exception Desc [%08x] == %08x\n"), |
|
167 GET_ROM_EST(&ep->ucb), pEST, GET_EXCEPTION_DESCRIPTOR(&ep->ucb), myExcpDesc); |
|
168 test(GET_ROM_EST(&ep->ucb)==pEST); |
|
169 test((char*)GET_EXCEPTION_DESCRIPTOR(&ep->ucb)== myExcpDesc); |
|
170 |
|
171 test.Printf(_L("Throwing first exception.\n")); |
|
172 int r = catcher(2); |
|
173 test.Printf(_L("Returned %d expected 2\n"), r); |
|
174 test(r==2); |
|
175 |
|
176 test.Printf(_L("Not throwing first exception.\n")); |
|
177 r = catcher(0); |
|
178 test.Printf(_L("Returned %d expected -1\n"), r); |
|
179 test(r==-1); |
|
180 |
|
181 test.Printf(_L("Throwing second exception.\n")); |
|
182 r = catcher2(3); |
|
183 test.Printf(_L("Returned %d expected 3\n"), r); |
|
184 test(r==3); |
|
185 |
|
186 test.Printf(_L("Not throwing second exception.\n")); |
|
187 r = catcher2(0); |
|
188 test.Printf(_L("Returned %d expected -1\n"), r); |
|
189 test(r==-1); |
|
190 |
|
191 test.Printf(_L("Throwing third exception.\n")); |
|
192 r = catcher3(4); |
|
193 test.Printf(_L("Returned %d expected 4\n"), r); |
|
194 test(r==4); |
|
195 |
|
196 test.Printf(_L("Not throwing third exception.\n")); |
|
197 r = catcher3(0); |
|
198 test.Printf(_L("Returned %d expected -1\n"), r); |
|
199 test(r==-1); |
|
200 |
|
201 test.Printf(_L("Throwing fourth exception.\n")); |
|
202 r = catcher4(5); |
|
203 test.Printf(_L("Returned %d expected 5\n"), r); |
|
204 test(r==5); |
|
205 |
|
206 test.Printf(_L("Not throwing fourth exception.\n")); |
|
207 r = catcher4(0); |
|
208 test.Printf(_L("Returned %d expected -1\n"), r); |
|
209 test(r==-1); |
|
210 |
|
211 test.Printf(_L("Throwing fifth exception.\n")); |
|
212 r = catcher5(6); |
|
213 test.Printf(_L("Returned %d expected 6\n"), r); |
|
214 test(r==6); |
|
215 |
|
216 test.Printf(_L("Not throwing fifth exception.\n")); |
|
217 r = catcher5(0); |
|
218 test.Printf(_L("Returned %d expected -1\n"), r); |
|
219 test(r==-1); |
|
220 |
|
221 test.Printf(_L("Testing std::uncaught_exception.\n")); |
|
222 TestUncaught(); |
|
223 #endif |
|
224 |
|
225 test.End(); |
|
226 test.Close(); |
|
227 return 0; |
|
228 } |
|
229 |
|
230 #ifdef __ARMCC__ |
|
231 // We rely on this immediately following E32main. DONT MOVE IT |
|
232 __asm char * GetExceptionDescriptor(void) { |
|
233 extern |Symbian$$CPP$$Exception$$Descriptor| |
|
234 ldr r0, theExceptionDesc |
|
235 |
|
236 #ifdef __SUPPORT_THUMB_INTERWORKING |
|
237 bx lr |
|
238 #else |
|
239 mov pc, lr |
|
240 #endif |
|
241 |
|
242 theExceptionDesc dcd |Symbian$$CPP$$Exception$$Descriptor| |
|
243 } |
|
244 #endif |
|
245 |
|
246 const __EIT_entry * DumbGetEITV1(TUint32 offset, const __EIT_entry * base, TUint32 n) { |
|
247 if (n && offset < base[0].fnoffset) return 0; |
|
248 for (int i=0; i<n; i++) { |
|
249 // check for last entry |
|
250 if (i == n-1 && base[i].fnoffset <= offset) return &base[i]; |
|
251 if (base[i].fnoffset <= offset && offset < base[i+1].fnoffset) return &base[i]; |
|
252 } |
|
253 return 0; |
|
254 } |
|
255 |
|
256 static uint32_t __ARM_resolve_prel31(void *p) |
|
257 { |
|
258 return (uint32_t)((((*(int32_t *)p) << 1) >> 1) + (int32_t)p); |
|
259 } |
|
260 |
|
261 __EIT_entry * DumbGetEITV2(TUint32 addr, __EIT_entry * base, TUint32 n) { |
|
262 if (n && (addr < __ARM_resolve_prel31(&base[0].fnoffset))) |
|
263 return 0; |
|
264 for (int i=0; i<n; i++) { |
|
265 // check for last entry |
|
266 if (i == n-1 && __ARM_resolve_prel31(&base[i].fnoffset) <= addr) |
|
267 return &base[i]; |
|
268 if ((__ARM_resolve_prel31(&base[i].fnoffset) <= addr) && |
|
269 (addr < __ARM_resolve_prel31(&base[i+1].fnoffset))) |
|
270 return &base[i]; |
|
271 } |
|
272 return 0; |
|
273 } |
|
274 |
|
275 #ifdef __SUPPORT_CPP_EXCEPTIONS__ |
|
276 |
|
277 class MyFirstException { |
|
278 public: |
|
279 MyFirstException(int x) { iVal = x; }; |
|
280 virtual ~MyFirstException(); |
|
281 int iVal; |
|
282 }; |
|
283 |
|
284 MyFirstException::~MyFirstException(){} |
|
285 |
|
286 int thrower (int x) { |
|
287 if (x != 0) throw MyFirstException(x); |
|
288 return -1; |
|
289 } |
|
290 |
|
291 int catcher(int x) { |
|
292 try { |
|
293 return thrower(x); |
|
294 } |
|
295 catch(MyFirstException& e) |
|
296 { |
|
297 return e.iVal; |
|
298 } |
|
299 } |
|
300 |
|
301 |
|
302 #include "second_excp.h" |
|
303 |
|
304 |
|
305 int catcher2(int x) { |
|
306 try { |
|
307 return thrower2(x); |
|
308 } |
|
309 catch(MySecondException& e) |
|
310 { |
|
311 return e.iVal; |
|
312 } |
|
313 } |
|
314 |
|
315 int catcher3(int x) { |
|
316 try { |
|
317 return thrower3(x); |
|
318 } |
|
319 catch(MyThirdException& e) |
|
320 { |
|
321 return e.iVal; |
|
322 } |
|
323 } |
|
324 |
|
325 int catcher4(int x) { |
|
326 try { |
|
327 return thrower4(x); |
|
328 } |
|
329 catch(MyFourthException& e) |
|
330 { |
|
331 return e.iVal; |
|
332 } |
|
333 } |
|
334 |
|
335 int catcher5(int x) { |
|
336 try { |
|
337 return thrower5(x); |
|
338 } |
|
339 catch(MyFifthException& e) |
|
340 { |
|
341 return e.iVal; |
|
342 } |
|
343 } |
|
344 |
|
345 void TestUncaught(void) { |
|
346 TInt x = 0; |
|
347 try { |
|
348 UncaughtTester aTester(x); |
|
349 test.Printf(_L("Check throw case\n")); |
|
350 thrower(0); |
|
351 } |
|
352 catch(MyFirstException& e) |
|
353 { |
|
354 test.Printf(_L("~Check x == 0\n")); |
|
355 test(x == 0); |
|
356 } |
|
357 try { |
|
358 UncaughtTester aTester(x); |
|
359 test.Printf(_L("Check no throw case\n")); |
|
360 } |
|
361 catch(MyFirstException& e) |
|
362 { |
|
363 test.Printf(_L("Whoops!!!\n")); |
|
364 } |
|
365 test(x==1); |
|
366 } |
|
367 |
|
368 |
|
369 #endif |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |