|
1 // Copyright (c) 2003-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\debug\d_eventtracker.cpp |
|
15 // LDD-based debug agent used to track kernel events. See |
|
16 // t_eventtracker.cpp |
|
17 // |
|
18 // |
|
19 |
|
20 #include <kernel/kern_priv.h> |
|
21 #include "reventtracker.h" |
|
22 #include "d_eventtracker.h" |
|
23 #include "nk_trace.h" |
|
24 |
|
25 #ifdef __MARM__ |
|
26 #include <kernel/kdebug.h> |
|
27 #endif //__MARM__ |
|
28 |
|
29 #ifdef _DEBUG |
|
30 static const char KPanicCat[] = "D_EVENTTRACKER"; |
|
31 #endif // _DEBUG |
|
32 _LIT(KClientPanicCat, "D_EVENTTRACKER"); |
|
33 |
|
34 DEventTracker* TheEventTracker; |
|
35 |
|
36 ////////////////////////////////////////////////////////////////////////////// |
|
37 |
|
38 /** Data about objects being tracked. |
|
39 All tracked objects are kept in a tracking list. The object address |
|
40 is a key and so must be unique. |
|
41 */ |
|
42 |
|
43 TTrackedItem::TTrackedItem(const DBase* aObject) |
|
44 : iObject(aObject), iAccountedFor(EFalse) |
|
45 { |
|
46 } |
|
47 |
|
48 |
|
49 /** Subclass for DObjects being tracked */ |
|
50 |
|
51 TTrackedObject::TTrackedObject(DObject* aObject, TObjectType aType) |
|
52 : TTrackedItem(aObject), |
|
53 iType(aType) |
|
54 { |
|
55 aObject->FullName(iFullName); |
|
56 } |
|
57 |
|
58 TBool TTrackedObject::CheckIntegrity(const TDesC& aName, TObjectType aType) const |
|
59 { |
|
60 TBool ok = EFalse; |
|
61 |
|
62 if (aType == iType) |
|
63 { |
|
64 if (aType == EThread || aType == EProcess) |
|
65 { |
|
66 ok = (iFullName == aName); |
|
67 } |
|
68 else |
|
69 { |
|
70 ok = ETrue; |
|
71 } |
|
72 } |
|
73 |
|
74 if (!ok) |
|
75 { |
|
76 Kern::Printf("EVENTTRACKER: container / tracking list mismatch (0x%08x)", iObject); |
|
77 Kern::Printf("EVENTTRACKER: \tcontainer: %S (type %d)", &aName, aType); |
|
78 Kern::Printf("EVENTTRACKER: \ttracking list: %S (type %d)", &iFullName, iType); |
|
79 } |
|
80 |
|
81 return ok; |
|
82 } |
|
83 |
|
84 /** Subclass for DCodeSegs being tracked */ |
|
85 |
|
86 TTrackedCodeSeg::TTrackedCodeSeg(const DCodeSeg* aCodeSeg) |
|
87 : TTrackedItem(aCodeSeg), |
|
88 iAccessCount(aCodeSeg ? aCodeSeg->iAccessCount : 0) |
|
89 { |
|
90 } |
|
91 |
|
92 TBool TTrackedCodeSeg::CheckIntegrity(TInt aAccessCount) const |
|
93 { |
|
94 const TBool ok = (aAccessCount == iAccessCount); |
|
95 |
|
96 if (!ok) |
|
97 { |
|
98 Kern::Printf("EVENTTRACKER: code seg list / tracking list mismatch (0x%08x)", iObject); |
|
99 Kern::Printf("EVENTTRACKER: \tcode seg list: %d", aAccessCount); |
|
100 Kern::Printf("EVENTTRACKER: \ttracking list: %d", iAccessCount); |
|
101 } |
|
102 |
|
103 return ok; |
|
104 } |
|
105 |
|
106 |
|
107 /** Event handler and container for all objects being tracked. */ |
|
108 |
|
109 DEventTracker::DEventTracker() |
|
110 : DKernelEventHandler(EventHandler, this) |
|
111 { |
|
112 __ASSERT_DEBUG(!TheEventTracker, Kern::Fault(KPanicCat, __LINE__)); |
|
113 |
|
114 TheEventTracker = this; |
|
115 } |
|
116 |
|
117 |
|
118 // |
|
119 // If aUseHook is true, the event tracker hooks the stop-mode debugger |
|
120 // breakpoint in preference to adding itself to the kernel event handler |
|
121 // queue. In order to clean up on its destruction, it has to |
|
122 // reset the breakpoint by installing a dummy nop breakpoint |
|
123 // handler, which is cut-and-pasted from kdebug.dll in order to |
|
124 // avoid a dependency on kdebug.dll. In order to use the event |
|
125 // tracker using the stop-mode debugger breakpoint rather than |
|
126 // the kernel event handler queue, kdebug.dll must be present in |
|
127 // the ROM |
|
128 // |
|
129 TInt DEventTracker::Create(DLogicalDevice* aDevice, TBool aUseHook) |
|
130 { |
|
131 TInt err = aDevice->Open(); |
|
132 |
|
133 if (err) |
|
134 { |
|
135 return err; |
|
136 } |
|
137 |
|
138 iDevice = aDevice; |
|
139 |
|
140 err = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdNone); |
|
141 |
|
142 if (!err) |
|
143 { |
|
144 if (aUseHook) |
|
145 { |
|
146 // Find debugger info, if any |
|
147 DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo; |
|
148 |
|
149 // Test stop-mode breakpoint if available |
|
150 if (debugInfo) |
|
151 { |
|
152 #ifdef __MARM__ |
|
153 // Receive all events |
|
154 for (TInt i = 0; i < ((EEventLimit + 31) >> 5); ++i) |
|
155 { |
|
156 debugInfo->iEventMask[i] = 0xffffffffu; |
|
157 } |
|
158 |
|
159 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Copying breakpoint (0x%x) into handler (0x%x), size %d", &BranchToEventHandler, debugInfo->iEventHandlerBreakpoint, BreakPointSize())); |
|
160 |
|
161 // Set up breakpoint to call handler |
|
162 memcpy((TAny*)debugInfo->iEventHandlerBreakpoint, (TAny*) &BranchToEventHandler, BreakPointSize()); |
|
163 #else // !__MARM__ |
|
164 err = KErrNotFound; |
|
165 #endif // __MARM__ |
|
166 } |
|
167 else |
|
168 { |
|
169 err = KErrNotFound; |
|
170 } |
|
171 } |
|
172 else |
|
173 { |
|
174 err = Add(); |
|
175 } |
|
176 } |
|
177 |
|
178 return err; |
|
179 } |
|
180 |
|
181 |
|
182 DEventTracker::~DEventTracker() |
|
183 { |
|
184 #ifdef __MARM__ |
|
185 // Remove breakpoint, if any |
|
186 DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo; |
|
187 if (debugInfo) |
|
188 { |
|
189 CopyDummyHandler(debugInfo->iEventHandlerBreakpoint); |
|
190 } |
|
191 #endif //__MARM__ |
|
192 |
|
193 // clean-up tracking list |
|
194 SDblQueLink* link = iItems.GetFirst(); |
|
195 while (link) |
|
196 { |
|
197 delete _LOFF(link, TTrackedItem, iLink); |
|
198 link = iItems.GetFirst(); |
|
199 } |
|
200 |
|
201 if (iLock) |
|
202 { |
|
203 iLock->Close(NULL); |
|
204 } |
|
205 |
|
206 if (iDevice) |
|
207 { |
|
208 iDevice->Close(NULL); |
|
209 } |
|
210 |
|
211 TheEventTracker = NULL; |
|
212 } |
|
213 |
|
214 |
|
215 TInt DEventTracker::Start() |
|
216 { |
|
217 TInt err = AddExistingObjects(); |
|
218 |
|
219 if (!err) |
|
220 { |
|
221 iTracking = ETrue; |
|
222 } |
|
223 |
|
224 return err; |
|
225 } |
|
226 |
|
227 |
|
228 TInt DEventTracker::Stop() |
|
229 { |
|
230 NKern::ThreadEnterCS(); |
|
231 Kern::MutexWait(*iLock); |
|
232 |
|
233 iTracking = EFalse; |
|
234 |
|
235 Kern::MutexSignal(*iLock); |
|
236 NKern::ThreadLeaveCS(); |
|
237 |
|
238 DumpCounters(); |
|
239 |
|
240 return CheckIntegrity(); |
|
241 } |
|
242 |
|
243 |
|
244 TUint DEventTracker::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis) |
|
245 { |
|
246 return ((DEventTracker*)aThis)->HandleEvent(aType, a1, a2); |
|
247 } |
|
248 |
|
249 |
|
250 TUint DEventTracker::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2) |
|
251 { |
|
252 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling event type 0x%x", aType)); |
|
253 |
|
254 Kern::MutexWait(*iLock); |
|
255 |
|
256 if (iTracking) |
|
257 { |
|
258 ++iCounters[aType]; |
|
259 |
|
260 switch (aType) |
|
261 { |
|
262 case EEventAddProcess: |
|
263 AddObject(EProcess, (DObject*)a1); |
|
264 break; |
|
265 case EEventUpdateProcess: |
|
266 // could be renaming or chunk addition/deletion |
|
267 UpdateObject(EProcess, (DObject*)a1, EFalse); |
|
268 break; |
|
269 case EEventRemoveProcess: |
|
270 RemoveObject(EProcess, (DObject*)a1); |
|
271 break; |
|
272 case EEventAddThread: |
|
273 AddObject(EThread, (DObject*)a1); |
|
274 break; |
|
275 case EEventUpdateThread: |
|
276 UpdateObject(EThread, (DObject*)a1, ETrue); |
|
277 break; |
|
278 case EEventRemoveThread: |
|
279 RemoveObject(EThread, (DObject*)a1); |
|
280 break; |
|
281 case EEventAddLibrary: |
|
282 { |
|
283 DLibrary* pL = (DLibrary*)a1; |
|
284 if (pL->iMapCount == 1) |
|
285 AddObject(ELibrary, pL); |
|
286 } |
|
287 break; |
|
288 case EEventRemoveLibrary: |
|
289 { |
|
290 DLibrary* pL = (DLibrary*)a1; |
|
291 if (pL->iMapCount == 0) |
|
292 RemoveObject(ELibrary, pL); |
|
293 } |
|
294 break; |
|
295 case EEventNewChunk: |
|
296 AddObject(EChunk, (DObject*)a1); |
|
297 break; |
|
298 case EEventDeleteChunk: |
|
299 RemoveObject(EChunk, (DObject*)a1); |
|
300 break; |
|
301 case EEventAddCodeSeg: |
|
302 { |
|
303 AddCodeSeg((DCodeSeg*)a1, (DProcess*)a2); |
|
304 } |
|
305 break; |
|
306 case EEventRemoveCodeSeg: |
|
307 { |
|
308 RemoveCodeSeg((DCodeSeg*)a1, (DProcess*)a2); |
|
309 } |
|
310 break; |
|
311 case EEventLoadedProcess: |
|
312 { |
|
313 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O loaded", a1)); |
|
314 ProcessLoaded((DProcess*)a1); |
|
315 } |
|
316 break; |
|
317 case EEventUnloadingProcess: |
|
318 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O unloaded", a1)); |
|
319 break; |
|
320 default: |
|
321 // no-op |
|
322 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling default case")); |
|
323 break; |
|
324 } |
|
325 } |
|
326 |
|
327 Kern::MutexSignal(*iLock); |
|
328 |
|
329 // Allow other handlers to see this event |
|
330 return DKernelEventHandler::ERunNext; |
|
331 } |
|
332 |
|
333 |
|
334 void DEventTracker::AddObject(TObjectType aType, DObject* aObject) |
|
335 { |
|
336 TTrackedObject* trackedObject = (TTrackedObject*)LookupItem(aObject); |
|
337 |
|
338 if (trackedObject) |
|
339 { |
|
340 Kern::Printf("EVENTTRACKER: Found orphaned object %O in tracking list while adding new object", aObject); |
|
341 ++iErrorCount; |
|
342 return; |
|
343 } |
|
344 |
|
345 NKern::ThreadEnterCS(); |
|
346 trackedObject = new TTrackedObject(aObject, aType); |
|
347 NKern::ThreadLeaveCS(); |
|
348 |
|
349 if (trackedObject) |
|
350 { |
|
351 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %O (type %d) to tracking list", aObject, aType)); |
|
352 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", trackedObject->iObject)); |
|
353 iItems.Add(&trackedObject->iLink); |
|
354 } |
|
355 else |
|
356 { |
|
357 iOOM = ETrue; |
|
358 ++iErrorCount; |
|
359 } |
|
360 } |
|
361 |
|
362 |
|
363 void DEventTracker::RemoveObject(TObjectType aType, DObject* aObject) |
|
364 { |
|
365 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject); |
|
366 |
|
367 if (trackedObject) |
|
368 { |
|
369 TFullName name; |
|
370 aObject->FullName(name); |
|
371 if (!trackedObject->CheckIntegrity(name, aType)) |
|
372 { |
|
373 ++iErrorCount; |
|
374 } |
|
375 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %S (type %d) from tracking list", &name, aType)); |
|
376 trackedObject->iLink.Deque(); |
|
377 |
|
378 NKern::ThreadEnterCS(); |
|
379 delete trackedObject; |
|
380 NKern::ThreadLeaveCS(); |
|
381 } |
|
382 else |
|
383 { |
|
384 Kern::Printf("EVENTTRACKER: %O (type %d) removed but not in tracking list", aObject, aType); |
|
385 ++iErrorCount; |
|
386 } |
|
387 } |
|
388 |
|
389 |
|
390 void DEventTracker::UpdateObject(TObjectType aType, DObject* aObject, TBool aMustBeRenamed) |
|
391 { |
|
392 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject); |
|
393 |
|
394 if (trackedObject) |
|
395 { |
|
396 TFullName newName; |
|
397 aObject->FullName(newName); |
|
398 if (newName != trackedObject->iFullName) |
|
399 { |
|
400 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Renaming %S --> %S (type %d)", |
|
401 &trackedObject->iFullName, &newName)); |
|
402 trackedObject->iFullName = newName; |
|
403 } |
|
404 else if (aMustBeRenamed) |
|
405 { |
|
406 Kern::Printf("EVENTTRACKER: %O (type %d) renamed with same name", aObject, aType); |
|
407 ++iErrorCount; |
|
408 } |
|
409 } |
|
410 else |
|
411 { |
|
412 Kern::Printf("EVENTTRACKER: %O (type %d) updated but not in tracking list", aObject, aType); |
|
413 Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", (DBase*)aObject); |
|
414 ++iErrorCount; |
|
415 } |
|
416 } |
|
417 |
|
418 void DEventTracker::AddCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess) |
|
419 { |
|
420 TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg); |
|
421 |
|
422 if (trackedCodeSeg) |
|
423 { |
|
424 if (aProcess && (aProcess->iTempCodeSeg == aCodeSeg)) |
|
425 { |
|
426 // This is the exe code seg for a loading process |
|
427 // and hence the access count is currently |
|
428 // incremented by one |
|
429 ++trackedCodeSeg->iAccessCount; |
|
430 } |
|
431 |
|
432 if (trackedCodeSeg->iAccessCount != aCodeSeg->iAccessCount) |
|
433 { |
|
434 Kern::Printf( |
|
435 "EVENTTRACKER: Access count for %C (%d) does not match the tracking list (%d)", |
|
436 aCodeSeg, |
|
437 aCodeSeg->iAccessCount, |
|
438 trackedCodeSeg->iAccessCount |
|
439 ); |
|
440 ++iErrorCount; |
|
441 return; |
|
442 } |
|
443 } |
|
444 |
|
445 if (!trackedCodeSeg) |
|
446 { |
|
447 NKern::ThreadEnterCS(); |
|
448 trackedCodeSeg = new TTrackedCodeSeg(aCodeSeg); |
|
449 NKern::ThreadLeaveCS(); |
|
450 |
|
451 if (trackedCodeSeg) |
|
452 { |
|
453 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %C to tracking list", aCodeSeg)); |
|
454 iItems.Add(&trackedCodeSeg->iLink); |
|
455 } |
|
456 } |
|
457 else // trackedCodeSeg |
|
458 { |
|
459 if (aProcess) |
|
460 { |
|
461 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Updating access count for %C (%d), attaching to process %O", aCodeSeg, aCodeSeg->iAccessCount, aProcess)); |
|
462 } |
|
463 else // !aProcess |
|
464 { |
|
465 Kern::Printf("EVENTTRACKER: Found orphaned code seg %C in tracking list while adding new code seg", aCodeSeg); |
|
466 ++iErrorCount; |
|
467 } |
|
468 } |
|
469 |
|
470 if (!trackedCodeSeg) |
|
471 { |
|
472 iOOM = ETrue; |
|
473 ++iErrorCount; |
|
474 } |
|
475 } |
|
476 |
|
477 void DEventTracker::ProcessLoaded(DProcess* aProcess) |
|
478 { |
|
479 if (aProcess->iCodeSeg) |
|
480 { |
|
481 TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aProcess->iCodeSeg); |
|
482 |
|
483 if (trackedCodeSeg) |
|
484 { |
|
485 // This is the exe code seg for a process that |
|
486 // has completed loading and hence the access |
|
487 // count has just been decremented by one |
|
488 --trackedCodeSeg->iAccessCount; |
|
489 } |
|
490 } |
|
491 } |
|
492 |
|
493 void DEventTracker::RemoveCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess) |
|
494 { |
|
495 TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg); |
|
496 |
|
497 if (trackedCodeSeg) |
|
498 { |
|
499 if (!trackedCodeSeg->CheckIntegrity(aCodeSeg->iAccessCount)) |
|
500 { |
|
501 ++iErrorCount; |
|
502 } |
|
503 |
|
504 if (aCodeSeg->iAccessCount == 1) |
|
505 { |
|
506 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %C from tracking list, process %O", aCodeSeg, aProcess)); |
|
507 trackedCodeSeg->iLink.Deque(); |
|
508 |
|
509 NKern::ThreadEnterCS(); |
|
510 delete trackedCodeSeg; |
|
511 NKern::ThreadLeaveCS(); |
|
512 } |
|
513 } |
|
514 else |
|
515 { |
|
516 Kern::Printf("EVENTTRACKER: %C removed but not in tracking list. Removing from process %O", aCodeSeg, aProcess); |
|
517 ++iErrorCount; |
|
518 } |
|
519 } |
|
520 |
|
521 |
|
522 /** Add all objects from relevant containers into the tracking list. */ |
|
523 |
|
524 TInt DEventTracker::AddExistingObjects() |
|
525 { |
|
526 // Tracking can be started only after all containers read to avoid |
|
527 // race conditions. |
|
528 __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__)); |
|
529 |
|
530 TInt err = KErrNone; |
|
531 Kern::Printf("Adding processes"); |
|
532 err = AddObjectsFromContainer(EProcess); |
|
533 if (err) |
|
534 { |
|
535 return err; |
|
536 } |
|
537 Kern::Printf("Adding threads"); |
|
538 err = AddObjectsFromContainer(EThread); |
|
539 if (err) |
|
540 { |
|
541 return err; |
|
542 } |
|
543 Kern::Printf("Adding libraries"); |
|
544 err = AddObjectsFromContainer(ELibrary); |
|
545 if (err) |
|
546 { |
|
547 return err; |
|
548 } |
|
549 Kern::Printf("Adding chunks"); |
|
550 err = AddObjectsFromContainer(EChunk); |
|
551 if (err) |
|
552 { |
|
553 return err; |
|
554 } |
|
555 Kern::Printf("Adding LDDs"); |
|
556 err = AddObjectsFromContainer(ELogicalDevice); |
|
557 if (err) |
|
558 { |
|
559 return err; |
|
560 } |
|
561 Kern::Printf("Adding PDDs"); |
|
562 err = AddObjectsFromContainer(EPhysicalDevice); |
|
563 if (err) |
|
564 { |
|
565 return err; |
|
566 } |
|
567 Kern::Printf("Adding code segs"); |
|
568 return AddCodeSegsFromList(); |
|
569 } |
|
570 |
|
571 /** Add all objects from specified container into tracking list. */ |
|
572 |
|
573 TInt DEventTracker::AddObjectsFromContainer(TObjectType aType) |
|
574 { |
|
575 DObjectCon* const container = Kern::Containers()[aType]; |
|
576 |
|
577 NKern::ThreadEnterCS(); |
|
578 container->Wait(); |
|
579 |
|
580 const TInt count = container->Count(); |
|
581 TInt err = KErrNone; |
|
582 |
|
583 for (TInt i = 0; (i < count && err == KErrNone); ++i) |
|
584 { |
|
585 DObject* const object = (*container)[i]; |
|
586 if (object->Open() == KErrNone) |
|
587 { |
|
588 AddObject(aType, object); |
|
589 if (iOOM) |
|
590 { |
|
591 err = KErrNoMemory; |
|
592 } |
|
593 object->Close(NULL); |
|
594 } |
|
595 } |
|
596 |
|
597 container->Signal(); |
|
598 NKern::ThreadLeaveCS(); |
|
599 |
|
600 return err; |
|
601 } |
|
602 |
|
603 TInt DEventTracker::AddCodeSegsFromList() |
|
604 { |
|
605 Kern::AccessCode(); |
|
606 |
|
607 const SDblQueLink* const anchor = &Kern::CodeSegList()->iA; |
|
608 for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext) |
|
609 { |
|
610 DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink); |
|
611 AddCodeSeg(codeSeg, NULL); |
|
612 } |
|
613 |
|
614 Kern::EndAccessCode(); |
|
615 |
|
616 return KErrNone; |
|
617 } |
|
618 |
|
619 |
|
620 /** Check that tracking list matches existing objects. |
|
621 @return number of discrepancies found |
|
622 */ |
|
623 |
|
624 TInt DEventTracker::CheckIntegrity() |
|
625 { |
|
626 // Tracking must be stopped to avoid race conditions. |
|
627 __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__)); |
|
628 |
|
629 if (iOOM) |
|
630 { |
|
631 Kern::Printf("EVENTTRACKER: OOM during tracking"); |
|
632 } |
|
633 |
|
634 CheckContainerIntegrity(EProcess); |
|
635 CheckContainerIntegrity(EThread); |
|
636 CheckContainerIntegrity(ELibrary); |
|
637 CheckContainerIntegrity(EChunk); |
|
638 CheckContainerIntegrity(ELogicalDevice); |
|
639 CheckContainerIntegrity(EPhysicalDevice); |
|
640 CheckCodeSegListIntegrity(); |
|
641 |
|
642 CheckAllAccountedFor(); |
|
643 |
|
644 if (iErrorCount) |
|
645 { |
|
646 Kern::Printf("EVENTTRACKER: %d error(s) found", iErrorCount); |
|
647 return KErrGeneral; |
|
648 } |
|
649 |
|
650 return KErrNone; |
|
651 } |
|
652 |
|
653 /** Check all objects in specified container are in tracking list. */ |
|
654 |
|
655 void DEventTracker::CheckContainerIntegrity(TObjectType aType) |
|
656 { |
|
657 DObjectCon* const container = Kern::Containers()[aType]; |
|
658 |
|
659 NKern::ThreadEnterCS(); |
|
660 container->Wait(); |
|
661 |
|
662 const TInt count = container->Count(); |
|
663 |
|
664 for (TInt i = 0; i < count; ++i) |
|
665 { |
|
666 DObject* const object = (*container)[i]; |
|
667 if (object->Open() == KErrNone) |
|
668 { |
|
669 TFullName name; |
|
670 object->FullName(name); |
|
671 |
|
672 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(object); |
|
673 |
|
674 if (trackedObject) |
|
675 { |
|
676 trackedObject->iAccountedFor = ETrue; |
|
677 if (!trackedObject->CheckIntegrity(name, aType)) |
|
678 { |
|
679 ++iErrorCount; |
|
680 } |
|
681 } |
|
682 else |
|
683 { |
|
684 Kern::Printf("EVENTTRACKER: %S (type %d) is in container but not in tracking list", &name, aType); |
|
685 ++iErrorCount; |
|
686 } |
|
687 |
|
688 object->Close(NULL); |
|
689 } |
|
690 } |
|
691 |
|
692 container->Signal(); |
|
693 NKern::ThreadLeaveCS(); |
|
694 } |
|
695 |
|
696 void DEventTracker::CheckCodeSegListIntegrity() |
|
697 { |
|
698 Kern::AccessCode(); |
|
699 |
|
700 const SDblQueLink* const anchor = &Kern::CodeSegList()->iA; |
|
701 for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext) |
|
702 { |
|
703 DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink); |
|
704 TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(codeSeg); |
|
705 |
|
706 if (trackedCodeSeg) |
|
707 { |
|
708 trackedCodeSeg->iAccountedFor = ETrue; |
|
709 if (!trackedCodeSeg->CheckIntegrity(codeSeg->iAccessCount)) |
|
710 { |
|
711 ++iErrorCount; |
|
712 } |
|
713 } |
|
714 else |
|
715 { |
|
716 Kern::Printf("EVENTTRACKER: %C is in global list but not in tracking list", codeSeg); |
|
717 ++iErrorCount; |
|
718 } |
|
719 } |
|
720 |
|
721 Kern::EndAccessCode(); |
|
722 } |
|
723 |
|
724 |
|
725 /** Check that all objects in tracking list have been accounted for. */ |
|
726 void DEventTracker::CheckAllAccountedFor() |
|
727 { |
|
728 const SDblQueLink* link = iItems.GetFirst(); |
|
729 while (link) |
|
730 { |
|
731 TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink); |
|
732 if (!item->iAccountedFor) |
|
733 { |
|
734 Kern::Printf( |
|
735 "EVENTTRACKER: 0x%x is in tracking list but not in container / list", |
|
736 &item->iObject |
|
737 ); |
|
738 ++iErrorCount; |
|
739 } |
|
740 link = iItems.GetFirst(); |
|
741 } |
|
742 } |
|
743 |
|
744 /** Look for specified object in the tracking list. |
|
745 @pre iLock held |
|
746 @post iLock held |
|
747 */ |
|
748 TTrackedItem* DEventTracker::LookupItem(DBase* aItem) const |
|
749 { |
|
750 const SDblQueLink* const anchor = &iItems.iA; |
|
751 |
|
752 for (SDblQueLink* link = iItems.First(); link != anchor; link = link->iNext) |
|
753 { |
|
754 TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink); |
|
755 |
|
756 if (item->iObject == aItem) |
|
757 { |
|
758 return item; |
|
759 } |
|
760 } |
|
761 |
|
762 return NULL; |
|
763 } |
|
764 |
|
765 |
|
766 void DEventTracker::DumpCounters() const |
|
767 { |
|
768 static const char* const KEventName[] = |
|
769 { |
|
770 "SwExc ", |
|
771 "HwExc ", |
|
772 "AddProcess ", |
|
773 "UpdateProcess ", |
|
774 "RemoveProcess ", |
|
775 "AddThread ", |
|
776 "StartThread ", |
|
777 "UpdateThread ", |
|
778 "KillThread ", |
|
779 "RemoveThread ", |
|
780 "NewChunk ", |
|
781 "UpdateChunk ", |
|
782 "DeleteChunk ", |
|
783 "AddLibrary ", |
|
784 "RemoveLibrary ", |
|
785 "LoadLdd ", |
|
786 "UnloadLdd ", |
|
787 "LoadPdd ", |
|
788 "UnloadPdd ", |
|
789 "UserTrace ", |
|
790 "AddCodeSeg ", |
|
791 "RemoveCodeSeg ", |
|
792 "LoadedProcess ", |
|
793 "UnloadingProcess" |
|
794 }; |
|
795 |
|
796 Kern::Printf("EVENT USAGE STATISTICS:"); |
|
797 |
|
798 for (TInt i = 0; i < EEventLimit; ++i) |
|
799 { |
|
800 Kern::Printf("\t%s\t\t %d times", KEventName[i], iCounters[i]); |
|
801 } |
|
802 } |
|
803 |
|
804 #ifdef __MARM__ |
|
805 void DEventTracker::CopyDummyHandler(TLinAddr aLinAddr) |
|
806 { |
|
807 const TUint handlerSize = DummyHandlerSize(); |
|
808 |
|
809 // Copy the breakpoint-able handler into RAM by copying from the one (possibly) in ROM |
|
810 memcpy((TAny*)aLinAddr, (TAny*) &DummyHandler, handlerSize); |
|
811 __KTRACE_OPT(KBOOT, Kern::Printf("Breakpoint-able handler copied from 0x%x to (va) 0x%x, size %d", &DummyHandler, aLinAddr, handlerSize)); |
|
812 } |
|
813 #endif |
|
814 |
|
815 ////////////////////////////////////////////////////////////////////////////// |
|
816 |
|
817 class DTestChannel : public DLogicalChannelBase |
|
818 { |
|
819 public: |
|
820 virtual ~DTestChannel(); |
|
821 protected: |
|
822 // from DLogicalChannelBase |
|
823 virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); |
|
824 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
825 private: |
|
826 DEventTracker* iHandler; |
|
827 }; |
|
828 |
|
829 |
|
830 // called in thread critical section |
|
831 TInt DTestChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
832 { |
|
833 if((TUint)aUnit>=2) |
|
834 return KErrNotSupported; |
|
835 |
|
836 TBool useHook = aUnit; |
|
837 |
|
838 iHandler = new DEventTracker; |
|
839 |
|
840 if (!iHandler) |
|
841 { |
|
842 return KErrNoMemory; |
|
843 } |
|
844 |
|
845 return iHandler->Create(iDevice, useHook); |
|
846 } |
|
847 |
|
848 // called in thread critical section |
|
849 DTestChannel::~DTestChannel() |
|
850 { |
|
851 if (iHandler) |
|
852 { |
|
853 iHandler->Close(); |
|
854 } |
|
855 } |
|
856 |
|
857 |
|
858 TInt DTestChannel::Request(TInt aFunction, TAny* /*a1*/, TAny* /*a2*/) |
|
859 { |
|
860 TInt r = KErrNone; |
|
861 switch (aFunction) |
|
862 { |
|
863 case REventTracker::EStart: |
|
864 iHandler->Start(); |
|
865 break; |
|
866 case REventTracker::EStop: |
|
867 iHandler->Stop(); |
|
868 break; |
|
869 default: |
|
870 Kern::PanicCurrentThread(KClientPanicCat, __LINE__); |
|
871 break; |
|
872 } |
|
873 return r; |
|
874 } |
|
875 |
|
876 |
|
877 ////////////////////////////////////////////////////////////////////////////// |
|
878 |
|
879 class DTestFactory : public DLogicalDevice |
|
880 { |
|
881 public: |
|
882 DTestFactory(); |
|
883 // from DLogicalDevice |
|
884 virtual TInt Install(); |
|
885 virtual void GetCaps(TDes8& aDes) const; |
|
886 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
887 }; |
|
888 |
|
889 DTestFactory::DTestFactory() |
|
890 { |
|
891 iVersion = REventTracker::Version(); |
|
892 iParseMask = KDeviceAllowUnit; |
|
893 iUnitsMask = 0x3; |
|
894 } |
|
895 |
|
896 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel) |
|
897 { |
|
898 aChannel = new DTestChannel; |
|
899 return (aChannel ? KErrNone : KErrNoMemory); |
|
900 } |
|
901 |
|
902 TInt DTestFactory::Install() |
|
903 { |
|
904 return SetName(&KTestLddName); |
|
905 } |
|
906 |
|
907 void DTestFactory::GetCaps(TDes8& /*aDes*/) const |
|
908 { |
|
909 } |
|
910 |
|
911 ////////////////////////////////////////////////////////////////////////////// |
|
912 |
|
913 DECLARE_STANDARD_LDD() |
|
914 { |
|
915 return new DTestFactory; |
|
916 } |