|
1 // Copyright (c) 1996-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\system\t_exc.cpp |
|
15 // In WINS T_EXC should be run from the command line only. |
|
16 // T_EXC will not complete when run under the MSDEV debugger. |
|
17 // Overview: |
|
18 // Test and verify exception handling. |
|
19 // API Information: |
|
20 // User::SetExceptionHandler, User::RaiseException |
|
21 // Details: |
|
22 // - Create a global semaphore, verify success. |
|
23 // - Test exceptions with no handlers: verify that divide by zero and |
|
24 // User::RaiseException() panic as expected. |
|
25 // - Test exceptions with handlers: verify that divide by zero and |
|
26 // User::RaiseException() call their exception handlers as expected. |
|
27 // - Test exception raised in exception handler: verify divide by zero |
|
28 // causes exception and an exception in the exception handler causes |
|
29 // a panic. |
|
30 // - Verify the results are as expected when a thread causes a divide |
|
31 // by zero exception. |
|
32 // - Get context of interrupted thread, get context of thread waiting |
|
33 // for request, get context of suspended thread. Verify results are |
|
34 // as expected. |
|
35 // Platforms/Drives/Compatibility: |
|
36 // All. |
|
37 // Assumptions/Requirement/Pre-requisites: |
|
38 // Failures and causes: |
|
39 // Base Port information: |
|
40 // |
|
41 // |
|
42 |
|
43 #include <e32test.h> |
|
44 #include <e32svr.h> |
|
45 #include "u32std.h" |
|
46 |
|
47 #pragma warning( disable : 4723 ) // disable divide by zero warnings |
|
48 |
|
49 #ifdef __MARM__ |
|
50 void UndefinedInstruction(); |
|
51 #endif |
|
52 |
|
53 LOCAL_D RTest test(_L("T_EXC")); |
|
54 RDebug debug; |
|
55 |
|
56 TInt gCount=0; |
|
57 RSemaphore gSem; |
|
58 TBool outsideExcSupported=ETrue; |
|
59 |
|
60 void excHandler(TExcType /*aType*/) |
|
61 // |
|
62 // An exception handler that does nothing |
|
63 // |
|
64 { |
|
65 |
|
66 gCount++; |
|
67 } |
|
68 |
|
69 void excHandlerFault(TExcType aType) |
|
70 // |
|
71 // An exception handler that causes an exception |
|
72 // |
|
73 { |
|
74 debug.Print(_L("Handling exception %d and causing exception in handler"), aType); |
|
75 gCount++; |
|
76 |
|
77 #ifdef __MARM__ |
|
78 // There is no Divide By Zero exception on the Arm |
|
79 // Use undefined instruction instead |
|
80 UndefinedInstruction(); |
|
81 #else |
|
82 // Cause a div by zero exception |
|
83 volatile int i=0; |
|
84 volatile int j=10; |
|
85 int l=j/i; |
|
86 for (i=0; i<l; i++) |
|
87 ; |
|
88 #endif |
|
89 } |
|
90 |
|
91 TInt waitSemaphore(TAny *) |
|
92 // |
|
93 // Sleep |
|
94 // |
|
95 { |
|
96 RSemaphore s; |
|
97 TInt r=s.OpenGlobal(_L("A SEMAPHORE")); |
|
98 test(r==KErrNone); |
|
99 s.Wait(); |
|
100 return KErrNone; |
|
101 } |
|
102 |
|
103 TInt garfield(TAny *) |
|
104 // |
|
105 // Sleep for a long time |
|
106 // |
|
107 { |
|
108 |
|
109 User::After(10000000); |
|
110 return KErrNone; |
|
111 } |
|
112 |
|
113 TInt odie(TAny *) |
|
114 // |
|
115 // Run round in circles |
|
116 // |
|
117 { |
|
118 FOREVER |
|
119 ; |
|
120 } |
|
121 |
|
122 TInt divideByZero(TAny *) |
|
123 // |
|
124 // Divide by zero |
|
125 // |
|
126 { |
|
127 #ifdef __MARM__ |
|
128 // There is no Divide By Zero exception on the Arm |
|
129 // Use undefined instruction instead |
|
130 UndefinedInstruction(); |
|
131 return(KErrNone); |
|
132 #else |
|
133 #ifdef __WINS__ |
|
134 #pragma warning( disable : 4189 ) // local variable is initialized but not referenced |
|
135 #endif |
|
136 volatile int i=0, j=10; |
|
137 volatile int l=j/i; |
|
138 FOREVER |
|
139 ; |
|
140 #endif |
|
141 } |
|
142 #pragma warning( default : 4723 ) |
|
143 |
|
144 TInt raiseException(TAny *) |
|
145 // |
|
146 // Raise an exception |
|
147 // |
|
148 { |
|
149 |
|
150 User::RaiseException(EExcIntegerDivideByZero); |
|
151 User::After(500000); |
|
152 return KErrNone; |
|
153 } |
|
154 |
|
155 void test1() |
|
156 { |
|
157 |
|
158 test.Start(_L("Create a thread (divideByZero)")); |
|
159 User::SetJustInTime(EFalse); |
|
160 RThread t; |
|
161 TRequestStatus s; |
|
162 TInt r; |
|
163 r=t.Create(_L("divideByZero"),divideByZero,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
164 test(r==KErrNone); |
|
165 t.Logon(s); |
|
166 test.Next(_L("Resume and wait for div by zero exception")); |
|
167 t.Resume(); |
|
168 User::WaitForRequest(s); |
|
169 test.Printf(_L("Exit Type %d\r\n"),(TInt)t.ExitType()); |
|
170 test(t.ExitType()==EExitPanic); |
|
171 test(t.ExitReason()==ECausedException); |
|
172 CLOSE_AND_WAIT(t); |
|
173 // |
|
174 |
|
175 test.Next(_L("Create a thread (raiseException)")); |
|
176 r=t.Create(_L("raiseException"),raiseException,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
177 test(r==KErrNone); |
|
178 t.Logon(s); |
|
179 test.Next(_L("Resume, and wait for raise exception")); |
|
180 t.Resume(); |
|
181 User::WaitForRequest(s); |
|
182 test(t.ExitType()==EExitPanic); |
|
183 test(t.ExitReason()==ECausedException); |
|
184 CLOSE_AND_WAIT(t); |
|
185 |
|
186 test.End(); |
|
187 } |
|
188 |
|
189 TInt divideByZero2(TAny *) |
|
190 { |
|
191 #ifdef __MARM__ |
|
192 // There is no Div By Zero exception on the Arm so we use a data abort instead |
|
193 User::SetExceptionHandler(&excHandler, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt); |
|
194 #else |
|
195 User::SetExceptionHandler(&excHandler, KExceptionInteger); |
|
196 #endif |
|
197 return divideByZero(0); |
|
198 } |
|
199 |
|
200 TInt raiseException2(TAny *) |
|
201 { |
|
202 User::SetExceptionHandler(&excHandler, KExceptionInteger); |
|
203 return raiseException(0); |
|
204 } |
|
205 |
|
206 void test2() |
|
207 { |
|
208 |
|
209 test.Start(_L("Create a thread (odie)")); |
|
210 RThread t; |
|
211 TRequestStatus s; |
|
212 TInt r; |
|
213 |
|
214 test.Next(_L("Create a thread (divideByZero)")); |
|
215 r=t.Create(_L("divideByZero"),divideByZero2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
216 test(r==KErrNone); |
|
217 t.Logon(s); |
|
218 gCount=0; |
|
219 |
|
220 test.Next(_L("Resume, and wait for 10 divide by zero exceptions")); |
|
221 t.Resume(); |
|
222 while (gCount<10) |
|
223 User::After(500000); |
|
224 test(gCount>=10); |
|
225 test.Next(_L("Kill the thread")); |
|
226 t.Kill(666); |
|
227 User::WaitForRequest(s); |
|
228 test(t.ExitType()==EExitKill); |
|
229 test(t.ExitReason()==666); |
|
230 CLOSE_AND_WAIT(t); |
|
231 // |
|
232 test.Next(_L("Create a thread (raiseException2)")); |
|
233 r=t.Create(_L("raiseException2"),raiseException2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
234 test(r==KErrNone); |
|
235 t.Logon(s); |
|
236 gCount=0; |
|
237 test.Next(_L("Resume")); |
|
238 t.Resume(); |
|
239 test.Next(_L("Wait for thread to finish")); |
|
240 User::WaitForRequest(s); |
|
241 test.Next(_L("Test thread raised an exception on itself")); |
|
242 test(gCount==1); |
|
243 test(t.ExitType()==EExitKill); |
|
244 test(t.ExitReason()==KErrNone); |
|
245 CLOSE_AND_WAIT(t); |
|
246 |
|
247 test.End(); |
|
248 } |
|
249 |
|
250 TInt divideByZero3(TAny *) |
|
251 { |
|
252 #ifdef __MARM__ |
|
253 User::SetExceptionHandler(&excHandlerFault, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt); |
|
254 #else |
|
255 User::SetExceptionHandler(&excHandlerFault, KExceptionInteger); |
|
256 #endif |
|
257 return divideByZero(0); |
|
258 } |
|
259 |
|
260 void test3() |
|
261 { |
|
262 test.Start(_L("Create a thread (divideByZero3)")); |
|
263 RThread t; |
|
264 TRequestStatus s; |
|
265 TInt r; |
|
266 r=t.Create(_L("divideByZero3"),divideByZero3,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
267 test(r==KErrNone); |
|
268 t.Logon(s); |
|
269 gCount=0; |
|
270 test.Next(_L("Resume, and wait for thread to die")); |
|
271 t.Resume(); |
|
272 User::WaitForRequest(s); |
|
273 test.Next(_L("Test thread raised one exception")); |
|
274 test(gCount==1); |
|
275 test.Next(_L("Test thread paniced on double exception")); |
|
276 test(t.ExitType()==EExitPanic); |
|
277 test(t.ExitReason()==ECausedException); |
|
278 CLOSE_AND_WAIT(t); |
|
279 // |
|
280 test.End(); |
|
281 } |
|
282 |
|
283 extern TInt dividebyzeroFn(TInt x) |
|
284 { |
|
285 volatile int i=x, j=10; |
|
286 volatile int l=j/i; |
|
287 for (i=0; i<l; i++) |
|
288 ; |
|
289 return KErrNone; |
|
290 } |
|
291 |
|
292 TInt dividebyzeroThread(TAny *) |
|
293 { |
|
294 return dividebyzeroFn(0); |
|
295 } |
|
296 |
|
297 void testDivException() |
|
298 { |
|
299 RThread t; |
|
300 TRequestStatus s; |
|
301 test.Next(_L("Create divide by zero thread")); |
|
302 TInt r=t.Create(_L("drop dead"),dividebyzeroThread,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); |
|
303 test(r==KErrNone); |
|
304 t.Logon(s); |
|
305 test.Next(_L("Resume")); |
|
306 t.Resume(); |
|
307 User::WaitForRequest(s); |
|
308 test.Next(_L("Test thread died because of EExcDivideByZero")); |
|
309 test(t.ExitType()==EExitPanic); |
|
310 test(t.ExitReason()==ECausedException); |
|
311 CLOSE_AND_WAIT(t); |
|
312 } |
|
313 |
|
314 #ifndef __EPOC32__ |
|
315 TInt ContextThread0(TAny *) |
|
316 { |
|
317 FOREVER; |
|
318 } |
|
319 #else |
|
320 TInt ContextThread0(TAny *); |
|
321 #endif |
|
322 |
|
323 #ifndef __EPOC32__ |
|
324 TInt ContextThread1(TAny *) |
|
325 { |
|
326 FOREVER; |
|
327 } |
|
328 #else |
|
329 TInt ContextThread1(TAny *); |
|
330 #endif |
|
331 |
|
332 #ifndef __EPOC32__ |
|
333 TInt ContextThread2(TAny *) |
|
334 { |
|
335 FOREVER; |
|
336 } |
|
337 #else |
|
338 TInt ContextThread2(TAny *); |
|
339 #endif |
|
340 |
|
341 TUint32 RunContextThread(TThreadFunction aFunction, TUint32* aRegs) |
|
342 { |
|
343 #ifdef __EPOC32__ |
|
344 TUint32 pc = (TUint32)aFunction((TAny*)0x80000000); |
|
345 #else |
|
346 TUint32 pc = 0; |
|
347 #endif |
|
348 RThread t; |
|
349 TRequestStatus s; |
|
350 TInt r=t.Create(_L("Context"),aFunction,KDefaultStackSize,NULL,NULL); |
|
351 test(r==KErrNone); |
|
352 t.Logon(s); |
|
353 t.Resume(); |
|
354 User::After(100000); |
|
355 |
|
356 TPtr8 buf((TUint8*)aRegs, 32*4, 32*4); |
|
357 TInt i; |
|
358 for (i=0; i<32; i++) |
|
359 aRegs[i]=0xbad00bad; |
|
360 t.Context(buf); |
|
361 if (buf.Length()==0) |
|
362 pc = 0; // not supported |
|
363 t.Kill(KErrNone); |
|
364 User::WaitForRequest(s); |
|
365 CLOSE_AND_WAIT(t); |
|
366 return pc; |
|
367 } |
|
368 |
|
369 struct SRegValues |
|
370 { |
|
371 TUint32 iValidMask; |
|
372 TUint32 iValues[32]; |
|
373 }; |
|
374 |
|
375 const TInt KNumContextTests = 3; |
|
376 |
|
377 static const TThreadFunction ContextTestFn[KNumContextTests] = |
|
378 { |
|
379 &ContextThread0, |
|
380 &ContextThread1, |
|
381 &ContextThread2 |
|
382 }; |
|
383 |
|
384 #if defined(__CPU_ARM) |
|
385 const TInt KPCIndex = 15; |
|
386 static const SRegValues ExpectedRegs[KNumContextTests] = |
|
387 { |
|
388 {0x1ffff, |
|
389 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00, |
|
390 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
391 } |
|
392 }, |
|
393 {0x0eff0, |
|
394 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00, |
|
395 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
396 } |
|
397 }, |
|
398 {0x0eff0, |
|
399 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00, |
|
400 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
401 } |
|
402 } |
|
403 }; |
|
404 |
|
405 static const TUint32 KRegValidBitsMask[32] = |
|
406 { |
|
407 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
|
408 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
|
409 0xf00000ffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
|
410 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu |
|
411 }; |
|
412 |
|
413 #elif defined(__CPU_X86) |
|
414 const TInt KPCIndex = 15; |
|
415 static const SRegValues ExpectedRegs[KNumContextTests] = |
|
416 { |
|
417 {0xe7ff, |
|
418 { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed, |
|
419 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000, |
|
420 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
|
421 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
|
422 } |
|
423 }, |
|
424 {0xe7ff, |
|
425 { 0x00000000, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed, |
|
426 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000, |
|
427 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
|
428 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
|
429 } |
|
430 }, |
|
431 {0xe7fa, // EAX=exec number, ECX trashed by preprocess handler |
|
432 { 0xaaaaaaaa, 0xbbbbbbbb, 0xffff8001, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed, |
|
433 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000, |
|
434 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
|
435 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
|
436 } |
|
437 } |
|
438 }; |
|
439 |
|
440 static const TUint32 KRegValidBitsMask[32] = |
|
441 { |
|
442 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
|
443 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x00000cd5u, 0xffffffffu, |
|
444 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
|
445 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu |
|
446 }; |
|
447 |
|
448 #endif |
|
449 |
|
450 void CheckContextValues(TUint32* aRegs, const SRegValues& aExpected, TUint32 aPC) |
|
451 { |
|
452 test.Printf(_L("PC=%08x Context returned:\n"), aPC); |
|
453 TInt i; |
|
454 const TUint32* s = aRegs; |
|
455 for (i=0; i<8; ++i, s+=4) |
|
456 test.Printf(_L("%08x %08x %08x %08x\n"), s[0], s[1], s[2], s[3]); |
|
457 TUint32 v = aExpected.iValidMask; |
|
458 TBool ok = ETrue; |
|
459 for (i=0; i<32; ++i, v>>=1) |
|
460 { |
|
461 if (!(v&1)) |
|
462 continue; |
|
463 TUint32 mask = KRegValidBitsMask[i]; |
|
464 TUint32 actual = aRegs[i] & mask; |
|
465 TUint32 exp = (i == KPCIndex) ? aPC&mask : aExpected.iValues[i]; |
|
466 if (actual != exp) |
|
467 { |
|
468 test.Printf(_L("%d: Expected %08x but got %08x\n"), i, exp, actual); |
|
469 ok = EFalse; |
|
470 } |
|
471 } |
|
472 test(ok); |
|
473 } |
|
474 |
|
475 void testContext() |
|
476 { |
|
477 |
|
478 TUint32 regs[32]; |
|
479 |
|
480 test.Next(_L("Get context of interrupted thread")); |
|
481 TInt tn; |
|
482 for (tn=0; tn<KNumContextTests; ++tn) |
|
483 { |
|
484 test.Printf(_L("Context test %d\n"), tn); |
|
485 TUint32 pc = RunContextThread(ContextTestFn[tn], regs); |
|
486 if (pc) |
|
487 { |
|
488 CheckContextValues(regs, ExpectedRegs[tn], pc); |
|
489 } |
|
490 } |
|
491 } |
|
492 |
|
493 GLDEF_C TInt E32Main() |
|
494 // |
|
495 // __KHEAP_SETFAIL etc. not available in release mode, so don't test |
|
496 // |
|
497 { |
|
498 |
|
499 test.Title(); |
|
500 test.Start(_L("Create a semaphore")); |
|
501 TInt r=gSem.CreateGlobal(_L("A SEMAPHORE"),0); |
|
502 test(r==KErrNone); |
|
503 test.Next(_L("Test exceptions with no handlers")); |
|
504 test1(); |
|
505 test.Next(_L("Test exceptions with handlers")); |
|
506 test2(); |
|
507 test.Next(_L("Test exception raised in exception handler")); |
|
508 test3(); |
|
509 test.Next(_L("Divide by zero exception")); |
|
510 testDivException(); |
|
511 test.Next(_L("Test Context")); |
|
512 testContext(); |
|
513 test.End(); |
|
514 return(KErrNone); |
|
515 } |