|
1 // debugRouter.cpp |
|
2 // |
|
3 // Copyright (c) 2007 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <nkern.h> |
|
14 #include <kernel.h> |
|
15 #include <kern_priv.h> |
|
16 #include <fshell/common.mmh> |
|
17 |
|
18 #include <e32cmn.h> |
|
19 #include "debugRouter.h" |
|
20 #include <platform.h> |
|
21 |
|
22 #include "dobject_compat.h" |
|
23 #include "debugRouter-kext.h" |
|
24 using namespace CloggerDebugRouter; |
|
25 |
|
26 //define this to get log output |
|
27 //#define DO_LOGGING |
|
28 |
|
29 #ifdef DO_LOGGING |
|
30 # define LOG Kern::Printf |
|
31 #else |
|
32 # ifdef __WINS__ |
|
33 inline void LOG(...) {} |
|
34 # else |
|
35 # define LOG(args...) |
|
36 # endif |
|
37 #endif |
|
38 |
|
39 #undef ASSERT |
|
40 #define ASSERT __NK_ASSERT_DEBUG |
|
41 |
|
42 EXPORT_C extern const TInt KChunkSize; // See patchables.cpp |
|
43 EXPORT_C extern const TInt KIsrBufSize; // Likewise |
|
44 EXPORT_C extern const TBool KEnableEarlyRdebug; // Likewise |
|
45 |
|
46 //////////////////////////////////////////////// |
|
47 |
|
48 |
|
49 const TInt KMajorVersionNumber=1; |
|
50 const TInt KMinorVersionNumber=0; |
|
51 const TInt KBuildVersionNumber=0; |
|
52 _LIT(KPanicCategory,"CloggerRouter"); |
|
53 const TUid KCloggerUid = { FSHELL_UID_CLOGGERSERVER }; |
|
54 |
|
55 class DCloggerDebugRouter; |
|
56 class DCloggerDebugRouterLDD; |
|
57 DCloggerDebugRouter* gRouter = NULL; |
|
58 |
|
59 // DCloggerDebugRouterFactory |
|
60 // |
|
61 NONSHARABLE_CLASS(DCloggerDebugRouterFactory) : public DLogicalDevice |
|
62 { |
|
63 public: |
|
64 DCloggerDebugRouterFactory(); |
|
65 private: |
|
66 TInt Install(); //overriding pure virtual |
|
67 void GetCaps(TDes8& aDes) const; //overriding pure virtual |
|
68 TInt Create(DLogicalChannelBase*& aChannel); //overriding pure virtual |
|
69 |
|
70 private: |
|
71 DOBJECT_PADDING; |
|
72 }; |
|
73 |
|
74 const TInt KMaxCrashDumpAreas = 8; |
|
75 |
|
76 NONSHARABLE_CLASS(DCloggerDebugRouter) : public DBase |
|
77 { |
|
78 public: |
|
79 DCloggerDebugRouter(); |
|
80 ~DCloggerDebugRouter(); |
|
81 |
|
82 static TInt Init(); |
|
83 static TBool TraceHook(const TDesC8& aText, TTraceSource aTraceSource); |
|
84 void SetCrashDumpFunctions(TRegisterFn aRegisterFn, TUnregisterFn aUnregisterFn); |
|
85 |
|
86 // Functions for the LDD |
|
87 TInt OpenChunk(); |
|
88 void CloseChunk(); |
|
89 TInt RegisterCrashDumpAreas(const TDesC8& aAreas); // Kernel must be unlocked & system lock not held |
|
90 TDfcQue& PrivateDfcQ(); |
|
91 void SetConsumeLogs(TBool aConsume); |
|
92 void SetEnabled(TBool aEnabled); |
|
93 void ClientRequestData(TRequestStatus* aStatus); |
|
94 |
|
95 // DFC callback functions |
|
96 static void HandleInterrupt(TAny* aSelf); |
|
97 static void KillThreadDFC(TAny* aSelf); |
|
98 static void CompleteClient(TAny* aSelf); |
|
99 |
|
100 static TBool StayEnabled(); |
|
101 private: |
|
102 TBool DoTraceHook(const TDesC8& aText, TTraceSource aTraceSource); |
|
103 TBool WriteOut(const TDesC8& aBuf, TInt aLengthToConsider = 0); |
|
104 void DoTrace(const TDesC8& aText, TTraceSource aTraceSource, TUint aTraceThread); |
|
105 void DoCompleteClient(); |
|
106 void NotifyClient(); |
|
107 TInt Construct(); |
|
108 void CheckInterruptBuffer(); |
|
109 |
|
110 private: |
|
111 DChunk* iChunk; |
|
112 TLinAddr iStartAddr; |
|
113 TLinAddr iEndAddr; |
|
114 TLinAddr iCurrent; |
|
115 TLinAddr iFirstFrame; // This isn't necessarily the same as iStartAddr, because if we wrap the first thing in the buffer will be continuation and not a header |
|
116 TTraceSource iTempBufTraceSource; |
|
117 |
|
118 TDfcQue iPrivateDfcQ; |
|
119 TDfc iHandleInterruptDfc; |
|
120 TDfc iCompleteClientDfc; |
|
121 HBuf8* iInterruptBuf; |
|
122 //TBuf8<2048> iTempBuf; // This is used to get the data from the unknown context of the trace handler to the DFC |
|
123 // Using iTempBuf means we can minimise the amount of time we have to run with interrupts off, while at the same |
|
124 // time allowing logging from ISRs and suchlike. |
|
125 #ifdef __SMP__ |
|
126 TSpinLock iInterruptBufLock; |
|
127 TSpinLock iBufferLock; |
|
128 #endif |
|
129 TBool iConsumeLogs; |
|
130 TUint iOverflows; |
|
131 TBool iInTheMiddleOfTracing; |
|
132 TBool iClientIsBeingNotified; |
|
133 |
|
134 TInt iNumCrashDumpAreas; |
|
135 SCrashDumpArea iCrashDumpAreas[KMaxCrashDumpAreas]; |
|
136 TRegisterFn iRegisterCrashDumpFn; |
|
137 TUnregisterFn iUnregisterCrashDumpFn; |
|
138 |
|
139 public: // Accessible by LDD class |
|
140 DThread* iClient; |
|
141 TLinAddr iClientStart; |
|
142 TLinAddr iClientEnd; |
|
143 TRequestStatus* iClientStatus; |
|
144 TBuf8<sizeof(SCloggerCrashDumpArea) * 8> iClientCrashDumpBuf; // For temporary use |
|
145 }; |
|
146 |
|
147 // Functions for testing purposes |
|
148 void DummyRegisterCrashDump(TAny* aAddr, TUint aSize, SCrashDumpArea& aCrashDumpArea) |
|
149 { |
|
150 LOG("Registering crashdump 0x%x %d %S", aAddr, aSize, &aCrashDumpArea.iName); |
|
151 LOG("First and last words are %x %x", ((TUint*)aAddr)[0], ((TUint*)aAddr)[(aSize/4)-1]); |
|
152 } |
|
153 void DummyUnregisterCrashDump(SCrashDumpArea& aCrashDumpArea) |
|
154 { |
|
155 LOG("Unregistering crashdump %S", &aCrashDumpArea.iName); |
|
156 } |
|
157 |
|
158 // DECLARE_STANDARD_LDD |
|
159 // Standard Extension Framework export |
|
160 DECLARE_STANDARD_EXTENSION() |
|
161 { |
|
162 //__BREAKPOINT(); |
|
163 TInt err = DCloggerDebugRouter::Init(); |
|
164 #ifdef __WINS__ |
|
165 // On WINS there's no way of setting the debug port to indicate we should enable ourselves. |
|
166 // Therefore we assume that if someone's gone to the trouble of adding "extension += clogger-debugrouter.ldd" to |
|
167 // their epoc.ini, then they want us to be enabled. |
|
168 if (!err) |
|
169 { |
|
170 err = gRouter->OpenChunk(); |
|
171 } |
|
172 if (!err) |
|
173 { |
|
174 gRouter->SetConsumeLogs(ETrue); |
|
175 gRouter->SetEnabled(ETrue); |
|
176 } |
|
177 #endif |
|
178 |
|
179 return err; |
|
180 } |
|
181 |
|
182 DECLARE_EXTENSION_LDD() |
|
183 { |
|
184 //__BREAKPOINT(); |
|
185 TBool ok = CalculateDObjectSize(); |
|
186 if (!ok) return NULL; |
|
187 return new DCloggerDebugRouterFactory(); |
|
188 } |
|
189 |
|
190 // DCloggerDebugRouter |
|
191 // |
|
192 NONSHARABLE_CLASS(DCloggerDebugRouterLDD) : public DLogicalChannel |
|
193 { |
|
194 public: |
|
195 DCloggerDebugRouterLDD(DCloggerDebugRouter* aRouter); |
|
196 ~DCloggerDebugRouterLDD(); |
|
197 private: |
|
198 //Framework |
|
199 TInt DoCreate(TInt aUnit,const TDesC* anInfo,const TVersion& aVer); |
|
200 void HandleMsg(TMessageBase* aMsg); |
|
201 void DoCancel(TInt aReqNo); |
|
202 TInt DoRequest(TInt aReqNo,TRequestStatus* aStatus,TAny* a1,TAny* a2); |
|
203 TInt DoControl(TInt aFunction,TAny *a1,TAny *a2); |
|
204 |
|
205 DCloggerDebugRouter* _iRouter; |
|
206 DOBJECT_PADDING; |
|
207 }; |
|
208 |
|
209 #define iRouter SAFE_MEMBER(_iRouter) |
|
210 |
|
211 DCloggerDebugRouterFactory::DCloggerDebugRouterFactory() |
|
212 { |
|
213 SAFE_MEMBER(iVersion)=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
214 } |
|
215 |
|
216 TInt DCloggerDebugRouterFactory::Create(DLogicalChannelBase*& aChannel) |
|
217 { |
|
218 TInt err = DCloggerDebugRouter::Init(); |
|
219 if (err) return err; |
|
220 |
|
221 aChannel = new DCloggerDebugRouterLDD(gRouter); |
|
222 if (aChannel==NULL) |
|
223 return KErrNoMemory; |
|
224 else |
|
225 return KErrNone; |
|
226 } |
|
227 |
|
228 TInt DCloggerDebugRouterFactory::Install() |
|
229 { |
|
230 return(SetName(&KDebugRouterName)); |
|
231 } |
|
232 |
|
233 void DCloggerDebugRouterFactory::GetCaps(TDes8& /*aDes*/) const |
|
234 { |
|
235 /* TCapsMemoryAccessV01 b; |
|
236 b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); |
|
237 aDes.FillZ(aDes.MaxLength()); |
|
238 aDes.Copy((TUint8*)&b,Min(aDes.MaxLength(),sizeof(b))); |
|
239 */ } |
|
240 |
|
241 // class DCloggerDebugRouter Implementation |
|
242 |
|
243 DCloggerDebugRouterLDD::DCloggerDebugRouterLDD(DCloggerDebugRouter* aRouter) |
|
244 : DLogicalChannel() |
|
245 { |
|
246 //SetBehaviour(-1); //JR |
|
247 iRouter = aRouter; |
|
248 } |
|
249 |
|
250 DCloggerDebugRouter::DCloggerDebugRouter() |
|
251 : iHandleInterruptDfc(NULL, NULL), iCompleteClientDfc(NULL, NULL) |
|
252 #ifdef __SMP__ |
|
253 , iInterruptBufLock(TSpinLock::EOrderGenericIrqLow0), iBufferLock(TSpinLock::EOrderGenericPreLow0) |
|
254 #endif |
|
255 { |
|
256 } |
|
257 |
|
258 const TInt KMemAccessDfcThreadPriority = 27; |
|
259 |
|
260 // DCloggerDebugRouter::DoCreate |
|
261 // Check capabilities & version & start listening for events |
|
262 TInt DCloggerDebugRouterLDD::DoCreate(TInt /*aUnit*/,const TDesC* /*anInfo*/,const TVersion& aVer) |
|
263 { |
|
264 TInt ret=KErrNone; |
|
265 |
|
266 /* |
|
267 //Require Power Management and All Files to use this driver |
|
268 //Not ideal, but better than nothing |
|
269 if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by MEMORYACCESS.LDD (Memory Access for Task Managers)"))) |
|
270 ret= KErrPermissionDenied; |
|
271 if(!Kern::CurrentThreadHasCapability(ECapabilityAllFiles,__PLATSEC_DIAGNOSTIC_STRING("Checked by MEMORYACCESS.LDD (Memory Access for Task Managers)"))) |
|
272 ret= KErrPermissionDenied; |
|
273 */ |
|
274 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer)) |
|
275 { |
|
276 return KErrNotSupported; |
|
277 } |
|
278 |
|
279 if (iRouter->iClient) |
|
280 { |
|
281 return KErrAlreadyExists; |
|
282 } |
|
283 |
|
284 iRouter->iClient=&Kern::CurrentThread(); |
|
285 |
|
286 SetDfcQ(&iRouter->PrivateDfcQ()); |
|
287 SAFE_MEMBER(iMsgQ).Receive(); |
|
288 |
|
289 //Kern::Printf("DCloggerDebugRouter::DoCreate %d",ret); |
|
290 return ret; |
|
291 } |
|
292 |
|
293 TDfcQue& DCloggerDebugRouter::PrivateDfcQ() |
|
294 { |
|
295 return iPrivateDfcQ; |
|
296 } |
|
297 |
|
298 TInt DCloggerDebugRouter::Init() |
|
299 { |
|
300 //__BREAKPOINT(); |
|
301 if (gRouter) return KErrNone; |
|
302 TInt err; |
|
303 #ifdef __WINS__ |
|
304 // WINSCW can't handle DLLs with WSD very well, particularly dynamically loaded ones like LDDs |
|
305 RPropertyRef property; // use this to stash the pointer that DLL loading keeps stomping over |
|
306 NKern::ThreadEnterCS(); |
|
307 const TInt EDebugRouterPtr = 1000; // from cliserv.h |
|
308 err = property.Open(KCloggerUid, EDebugRouterPtr); |
|
309 if (!err) |
|
310 { |
|
311 TInt& ptr = *reinterpret_cast<TInt*>(&gRouter); |
|
312 property.Get(ptr); |
|
313 } |
|
314 property.Close(); |
|
315 NKern::ThreadLeaveCS(); |
|
316 if (gRouter) return KErrNone; |
|
317 #endif |
|
318 |
|
319 DCloggerDebugRouter* self = new DCloggerDebugRouter; |
|
320 if (!self) return KErrNoMemory; |
|
321 |
|
322 err = self->Construct(); |
|
323 if (err == KErrNone && StayEnabled()) |
|
324 { |
|
325 // Then enable ourselves |
|
326 err = self->OpenChunk(); |
|
327 if (!err) |
|
328 { |
|
329 self->SetConsumeLogs(ETrue); |
|
330 self->SetEnabled(ETrue); |
|
331 } |
|
332 } |
|
333 if (err) |
|
334 { |
|
335 delete self; |
|
336 return err; |
|
337 } |
|
338 |
|
339 gRouter = self; |
|
340 #ifdef __WINS__ |
|
341 // See comment at top of function |
|
342 NKern::ThreadEnterCS(); |
|
343 err = property.Attach(KCloggerUid, EDebugRouterPtr); |
|
344 if (!err) |
|
345 { |
|
346 _LIT_SECURITY_POLICY_FAIL(KKernOnlyPolicy); |
|
347 err = property.Define(RProperty::EInt, KKernOnlyPolicy, KKernOnlyPolicy); |
|
348 } |
|
349 if (err == KErrNone || err == KErrAlreadyExists) |
|
350 { |
|
351 TInt& ptr = *reinterpret_cast<TInt*>(&gRouter); |
|
352 property.Set(ptr); |
|
353 } |
|
354 property.Close(); |
|
355 NKern::ThreadLeaveCS(); |
|
356 #endif |
|
357 |
|
358 // And finally, set up some dummy functions for debugging |
|
359 #ifdef __WINS__ |
|
360 CloggerDebugRouter::SetCrashDumpFunctions(&DummyRegisterCrashDump, &DummyUnregisterCrashDump); |
|
361 #endif |
|
362 |
|
363 return KErrNone; |
|
364 } |
|
365 |
|
366 TInt DCloggerDebugRouter::Construct() |
|
367 { |
|
368 iInterruptBuf = HBuf8::New(KIsrBufSize); |
|
369 if (!iInterruptBuf) return KErrNoMemory; |
|
370 |
|
371 _LIT(KDfcThreadName, "CloggerDebugRouter"); |
|
372 TInt err = Kern::DfcQInit(&iPrivateDfcQ, KMemAccessDfcThreadPriority, &KDfcThreadName); |
|
373 if (err) |
|
374 { |
|
375 return err; |
|
376 } |
|
377 iHandleInterruptDfc = TDfc(&HandleInterrupt, this, &iPrivateDfcQ, 1); // Interrupt handler DFC higher priority than completing client |
|
378 iCompleteClientDfc = TDfc(&CompleteClient, this, &iPrivateDfcQ, 0); |
|
379 return err; |
|
380 } |
|
381 |
|
382 // dtor |
|
383 // |
|
384 DCloggerDebugRouter::~DCloggerDebugRouter() |
|
385 { |
|
386 //__BREAKPOINT(); |
|
387 TTraceHandler old = Kern::SetTraceHandler(NULL); |
|
388 if (old != &TraceHook) |
|
389 { |
|
390 // Then set it back. What we wanted to do is if (TraceHandler == &TraceHook) { SetTraceHandler(NULL) } |
|
391 // But there is no API to get the hook without also setting it. |
|
392 Kern::SetTraceHandler(old); |
|
393 } |
|
394 CloseChunk(); |
|
395 |
|
396 // Finally queue a DFC to kill our DFC thread |
|
397 if (iPrivateDfcQ.iThread) |
|
398 { |
|
399 TDfc killDfcThread(KillThreadDFC, this, &iPrivateDfcQ, 0); |
|
400 killDfcThread.Enque(); |
|
401 } |
|
402 } |
|
403 |
|
404 DCloggerDebugRouterLDD::~DCloggerDebugRouterLDD() |
|
405 { |
|
406 //__BREAKPOINT(); |
|
407 ASSERT(!iRouter->iClientStatus); // Should have received a close message first |
|
408 iRouter->iClient = NULL; |
|
409 } |
|
410 |
|
411 void DCloggerDebugRouter::KillThreadDFC(TAny* /*aSelfP*/) |
|
412 { |
|
413 Kern::Exit(KErrNone); |
|
414 } |
|
415 |
|
416 void DCloggerDebugRouter::HandleInterrupt(TAny* aSelf) |
|
417 { |
|
418 static_cast<DCloggerDebugRouter*>(aSelf)->CheckInterruptBuffer(); |
|
419 } |
|
420 |
|
421 void DCloggerDebugRouter::CheckInterruptBuffer() |
|
422 { |
|
423 TBuf8<256> interruptBufCopy; // Using a stack buffer here means we don't have to lock the kernel just yet |
|
424 #ifdef __SMP__ |
|
425 TInt irq = __SPIN_LOCK_IRQSAVE(iInterruptBufLock); |
|
426 #else |
|
427 TInt irq = NKern::DisableAllInterrupts(); // Prevent an interrupt changing it while we're copying it |
|
428 #endif |
|
429 if (iInterruptBuf->Length() > 256) |
|
430 { |
|
431 // Need to rethink the stack buffer! |
|
432 __BREAKPOINT(); |
|
433 } |
|
434 interruptBufCopy.Copy(*iInterruptBuf); |
|
435 iInterruptBuf->Zero(); |
|
436 memclr((TAny*)iInterruptBuf->Ptr(), iInterruptBuf->Length()); // So that you don't see old data in the crashlog |
|
437 #ifdef __SMP__ |
|
438 __SPIN_UNLOCK_IRQRESTORE(iInterruptBufLock, irq); |
|
439 #else |
|
440 NKern::RestoreInterrupts(irq); |
|
441 #endif |
|
442 if (interruptBufCopy.Length()) |
|
443 { |
|
444 //__BREAKPOINT(); |
|
445 DoTrace(interruptBufCopy, EKernelTrace, 0); |
|
446 } |
|
447 } |
|
448 |
|
449 // DCloggerDebugRouter::HandleMsg |
|
450 // Called when user side sends us something |
|
451 void DCloggerDebugRouterLDD::HandleMsg(TMessageBase* aMsg) |
|
452 { |
|
453 //Kern::Printf("DCloggerDebugRouter::HandleMsg"); |
|
454 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
455 |
|
456 // Get message type |
|
457 TInt id=m.iValue; |
|
458 |
|
459 // Decode the message type and dispatch it to the relevent handler function... |
|
460 |
|
461 // A logical channel can be closed either explicitly by its user-side client, |
|
462 // or implicitly if the client thread dies. In the latter case, the channel |
|
463 // is closed in the context of the kernel supervisor thread. |
|
464 |
|
465 if (id==(TInt)ECloseMsg) |
|
466 { |
|
467 //Kern::Printf("DCloggerDebugRouter::HandleMsg Close"); |
|
468 // Channel Close |
|
469 DoCancel(RCloggerDebugRouter::EAllRequests); //JR |
|
470 m.Complete(KErrNone, EFalse); |
|
471 return; |
|
472 } |
|
473 |
|
474 // For all other message types, we check that the message is from the thread |
|
475 // that created us. |
|
476 if(m.Client()!=iRouter->iClient) |
|
477 { |
|
478 //Kern::Printf("DCloggerDebugRouter::HandleMsg About"); |
|
479 Kern::ThreadKill(m.Client(),EExitPanic,ERequestFromWrongThread,KPanicCategory); |
|
480 m.Complete(KErrNone,ETrue); |
|
481 return; |
|
482 } |
|
483 if (id==KMaxTInt) |
|
484 { |
|
485 //Kern::Printf("DCloggerDebugRouter::HandleMsg Cancel"); |
|
486 // DoCancel |
|
487 DoCancel(m.Int0()); |
|
488 m.Complete(KErrNone,ETrue); |
|
489 return; |
|
490 } |
|
491 if (id<0) |
|
492 { |
|
493 // DoRequest |
|
494 //Kern::Printf("DCloggerDebugRouter::HandleMsg Do Request"); |
|
495 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
496 TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); |
|
497 if (r!=KErrNone) |
|
498 Kern::RequestComplete(iRouter->iClient,pS,r); |
|
499 m.Complete(KErrNone,ETrue); |
|
500 } |
|
501 else |
|
502 { |
|
503 // DoControl |
|
504 //Kern::Printf("DCloggerDebugRouter::HandleMsg Do Control"); |
|
505 TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); |
|
506 m.Complete(r,ETrue); |
|
507 } |
|
508 } |
|
509 |
|
510 // DCloggerDebugRouter::DoRequest |
|
511 // Handles async messages, called from HandleMsg |
|
512 TInt DCloggerDebugRouterLDD::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* /*a1*/, TAny* /*a2*/) |
|
513 { |
|
514 if (aReqNo == RCloggerDebugRouter::ERequestGetData) |
|
515 { |
|
516 iRouter->ClientRequestData(aStatus); |
|
517 } |
|
518 return KErrNone; |
|
519 } |
|
520 |
|
521 void DCloggerDebugRouter::ClientRequestData(TRequestStatus* aStatus) |
|
522 { |
|
523 iClientStatus = aStatus; |
|
524 NKern::Lock(); |
|
525 #ifdef __SMP__ |
|
526 __SPIN_LOCK(iBufferLock); |
|
527 NotifyClient(); |
|
528 __SPIN_UNLOCK(iBufferLock); |
|
529 #else |
|
530 NotifyClient(); |
|
531 #endif |
|
532 NKern::Unlock(); |
|
533 } |
|
534 |
|
535 |
|
536 |
|
537 // DCloggerDebugRouter::DoCancel |
|
538 // Cancels async messages, called from HandleMsg |
|
539 void DCloggerDebugRouterLDD::DoCancel(TInt /*aReqNo*/) |
|
540 { |
|
541 if (iRouter->iClientStatus) |
|
542 { |
|
543 Kern::RequestComplete(iRouter->iClient, iRouter->iClientStatus, KErrCancel); |
|
544 } |
|
545 } |
|
546 |
|
547 void DCloggerDebugRouter::SetEnabled(TBool aEnabled) |
|
548 { |
|
549 if (aEnabled) |
|
550 { |
|
551 /*TTraceHandler old =*/ Kern::SetTraceHandler(&TraceHook); |
|
552 } |
|
553 else |
|
554 { |
|
555 if (Kern::SuperPage().iDebugPort != KCloggerDebugPort) |
|
556 { |
|
557 // If we are the debug port, we cannot unset our trace hook, there's nowhere else for the logs to go |
|
558 // Don't try and restore any previous trace handler - no guarantee the pointer is still valid or safe to call |
|
559 Kern::SetTraceHandler(NULL); |
|
560 iCurrent = iStartAddr; |
|
561 iFirstFrame = iCurrent; |
|
562 } |
|
563 // Reset client pointers |
|
564 iClientStart = iStartAddr; |
|
565 iClientEnd = iClientStart; |
|
566 } |
|
567 } |
|
568 |
|
569 void DCloggerDebugRouter::SetConsumeLogs(TBool aConsume) |
|
570 { |
|
571 if (Kern::SuperPage().iDebugPort == KCloggerDebugPort) |
|
572 { |
|
573 // Then the LDD has no say in whether we are allowed to consume the logs or not |
|
574 // Because there is nowhere else for them to go if we are the debug port, we must consume them |
|
575 aConsume = ETrue; |
|
576 } |
|
577 //iConsumeLogs = EFalse; // So that we can get logging from the kernel even when rdebug redirection is enabled |
|
578 iConsumeLogs = aConsume; |
|
579 } |
|
580 |
|
581 // DCloggerDebugRouter::DoControl |
|
582 // Handles sync messages, called from HandleMsg |
|
583 TInt DCloggerDebugRouterLDD::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
584 { |
|
585 //Kern::Printf("[DCloggerDebugRouter] ::DoControl; Function: %d", aFunction); |
|
586 switch (aFunction) |
|
587 { |
|
588 case RCloggerDebugRouter::EControlEnableRouting: |
|
589 { |
|
590 TBool consume = (TInt)a1 == RCloggerDebugRouter::EEnableRoutingAndConsume; |
|
591 TBool enable = (TBool)a1; |
|
592 |
|
593 iRouter->SetConsumeLogs(consume); |
|
594 iRouter->SetEnabled(enable); |
|
595 return KErrNone; |
|
596 } |
|
597 case RCloggerDebugRouter::EControlOpenChunk: |
|
598 { |
|
599 TInt res = iRouter->OpenChunk(); |
|
600 return res; |
|
601 } |
|
602 case RCloggerDebugRouter::EControlRegisterBuffers: |
|
603 { |
|
604 TInt err = Kern::ThreadDesRead(iRouter->iClient, a1, iRouter->iClientCrashDumpBuf, 0); |
|
605 if (!err) |
|
606 { |
|
607 err = iRouter->RegisterCrashDumpAreas(iRouter->iClientCrashDumpBuf); |
|
608 } |
|
609 return err; |
|
610 } |
|
611 case RCloggerDebugRouter::EControlCreateAndOpenAChunk: |
|
612 { |
|
613 SCreateChunkParams params; |
|
614 TInt res = Kern::ThreadRawRead(iRouter->iClient, a1, ¶ms, sizeof(SCreateChunkParams)); |
|
615 if (res != KErrNone) return res; |
|
616 |
|
617 DThread* otherThread = NULL; |
|
618 TInt otherThreadHandle = 0; |
|
619 if (params.iHandleOfOtherThread) |
|
620 { |
|
621 NKern::LockSystem(); |
|
622 otherThread = (DThread*)Kern::ObjectFromHandle(iRouter->iClient, params.iHandleOfOtherThread, EThread); |
|
623 if (otherThread) otherThread->Open(); // Make sure it doesn't disappear before we've finished with it |
|
624 NKern::UnlockSystem(); |
|
625 } |
|
626 |
|
627 DChunk* chunk = NULL; |
|
628 TChunkCreateInfo info; |
|
629 info.iType = TChunkCreateInfo::ESharedKernelSingle; |
|
630 info.iMaxSize = params.iMaxSize; |
|
631 #ifdef __EPOC32__ |
|
632 info.iMapAttr = (TInt)EMapAttrFullyBlocking; // Full caching |
|
633 #endif |
|
634 info.iOwnsMemory = ETrue; // Use memory from system's free pool |
|
635 info.iDestroyedDfc = NULL; |
|
636 |
|
637 TUint32 chunkMapAttr; |
|
638 TLinAddr addr; |
|
639 NKern::ThreadEnterCS(); |
|
640 res = Kern::ChunkCreate(info, chunk, addr, chunkMapAttr); |
|
641 if (res != KErrNone) |
|
642 { |
|
643 goto CloseAndBail; |
|
644 } |
|
645 if (params.iCommittedSize > 0) |
|
646 { |
|
647 res = Kern::ChunkCommit(chunk,0,params.iCommittedSize); |
|
648 } |
|
649 if(res!=KErrNone) |
|
650 { |
|
651 goto CloseAndBail; |
|
652 } |
|
653 |
|
654 // Still in CS |
|
655 |
|
656 if (otherThread) |
|
657 { |
|
658 // Create handle for other thread |
|
659 otherThreadHandle = Kern::MakeHandleAndOpen(otherThread, chunk); |
|
660 } |
|
661 if (otherThreadHandle < 0) |
|
662 { |
|
663 res = otherThreadHandle; |
|
664 goto CloseAndBail; |
|
665 } |
|
666 // Create handle for our thread |
|
667 res = Kern::MakeHandleAndOpen(iRouter->iClient, chunk); |
|
668 // Open our handle last so we don't have to worry about closing it in CloseAndBail if an error occurred later |
|
669 goto CloseAndBail; |
|
670 // All done. |
|
671 |
|
672 CloseAndBail: |
|
673 Kern::ChunkClose(chunk); |
|
674 if (res < 0 && otherThreadHandle > 0) Kern::CloseHandle(otherThread, otherThreadHandle); |
|
675 NKern::ThreadLeaveCS(); |
|
676 |
|
677 if (res > 0) |
|
678 { |
|
679 params.iOtherThreadChunkHandle = otherThreadHandle; |
|
680 params.iChunkHandle = res; |
|
681 res = KErrNone; |
|
682 Kern::ThreadRawWrite(iRouter->iClient, a1, ¶ms, sizeof(SCreateChunkParams)); |
|
683 } |
|
684 return res; |
|
685 } |
|
686 case RCloggerDebugRouter::EControlAdjustChunk: |
|
687 { |
|
688 TInt handle = (TInt)a1; |
|
689 TInt newSize = (TInt)a2; |
|
690 NKern::LockSystem(); |
|
691 DChunk* chunk = (DChunk*)Kern::ObjectFromHandle(iRouter->iClient, handle, EChunk); |
|
692 if (chunk) chunk->Open(); // Make sure it doesn't disappear before we've finished with it |
|
693 NKern::UnlockSystem(); |
|
694 TInt err = KErrNotFound; |
|
695 if (chunk) |
|
696 { |
|
697 NKern::ThreadEnterCS(); |
|
698 TInt oldSize = chunk->Size(); |
|
699 TInt diff = Kern::RoundToPageSize(newSize - oldSize); |
|
700 // Because kernel-created chunks appear to be specified as disconnected, we can't use the simple Adjust |
|
701 //err = chunk->Adjust(newSize); |
|
702 // even though that's the behaviour we want |
|
703 if (diff > 0) |
|
704 { |
|
705 err = Kern::ChunkCommit(chunk, oldSize, diff); |
|
706 if (err == KErrArgument) err = KErrNoMemory; // Generally that's what it means |
|
707 } |
|
708 else if (diff < 0) |
|
709 { |
|
710 // It appears that there is no way of decommitting memory from a shared chunk |
|
711 // So we will just stay the same size |
|
712 //err = chunk->Decommit(newSize, -diff); |
|
713 err = KErrNone; |
|
714 } |
|
715 else |
|
716 { |
|
717 // no change |
|
718 err = KErrNone; |
|
719 } |
|
720 Kern::ChunkClose(chunk); |
|
721 NKern::ThreadLeaveCS(); |
|
722 } |
|
723 return err; |
|
724 } |
|
725 default: |
|
726 (void)a2; |
|
727 return KErrNotSupported; |
|
728 } |
|
729 } |
|
730 |
|
731 |
|
732 TBool DCloggerDebugRouter::TraceHook(const TDesC8& aText, TTraceSource aTraceSource) |
|
733 { |
|
734 #if defined(DO_LOGGING) // || defined(_DEBUG) |
|
735 // This code is here so it's easier to debug problems in my trace hook that cause kern faults (that in turn |
|
736 // try to call Kern::Printf...) |
|
737 if (aTraceSource == EKernelTrace) return EFalse; |
|
738 #endif |
|
739 #ifdef __WINS__ |
|
740 // This is necessary in case loading the LDD stomped over the global data |
|
741 if (!gRouter) return ETrue; |
|
742 #endif |
|
743 return gRouter->DoTraceHook(aText, aTraceSource); |
|
744 } |
|
745 |
|
746 TBool DCloggerDebugRouter::DoTraceHook(const TDesC8& aText, TTraceSource aTraceSource) |
|
747 { |
|
748 TBool consume = iConsumeLogs; |
|
749 |
|
750 TUint traceThread = 0; // 0 means non-thread (ie interrupt or IDFC) that will appear as the generic "Kern::Printf" |
|
751 TInt context = NKern::CurrentContext(); |
|
752 if (context == NKern::EInterrupt) |
|
753 { |
|
754 // Interrupts copy to a special buffer. No timestamping or prettying up is done at the point of the interrupt |
|
755 // It is handled next time someone logs or when the DFC fires, whichever is sooner |
|
756 #ifdef __SMP__ |
|
757 TInt irq = __SPIN_LOCK_IRQSAVE(iInterruptBufLock); |
|
758 iInterruptBuf->Append(aText); |
|
759 __SPIN_UNLOCK_IRQRESTORE(iInterruptBufLock, irq); |
|
760 #else |
|
761 iInterruptBuf->Append(aText); |
|
762 #endif |
|
763 |
|
764 iHandleInterruptDfc.Add(); |
|
765 return consume; |
|
766 } |
|
767 |
|
768 if (context == NKern::EThread) |
|
769 { |
|
770 DThread& thread = Kern::CurrentThread(); |
|
771 traceThread = thread.iId; |
|
772 } |
|
773 |
|
774 // Before doing our logging, check if there's anything in the interrupt buffer. This means that (barring interrupt logging that happens while we're running the TraceHook function) the logging should still end up sequential |
|
775 CheckInterruptBuffer(); |
|
776 |
|
777 if (aTraceSource == EUserTrace) |
|
778 { |
|
779 DProcess& userProc = Kern::CurrentProcess(); |
|
780 if (userProc.iS.iSecureId == (TUint)KCloggerUid.iUid) |
|
781 { |
|
782 return EFalse; // Debugs from clogger itself should be passed through to the debugport |
|
783 } |
|
784 } |
|
785 |
|
786 DoTrace(aText, aTraceSource, traceThread); |
|
787 return consume; |
|
788 } |
|
789 |
|
790 void DCloggerDebugRouter::DoTrace(const TDesC8& aText, TTraceSource aTraceSource, TUint aTraceThread) |
|
791 { |
|
792 LOG("+DoTrace iStartAddr=%x iEndAddr=%x iCurrent=%x iClientStart=%x iClientEnd=%x", iStartAddr, iEndAddr, iCurrent, iClientStart, iClientEnd); |
|
793 SCloggerTraceInfo info; |
|
794 info.iTraceType = aTraceSource == EUserTrace ? 'U' : aTraceSource == EPlatSecTrace ? 'P' : 'K'; |
|
795 info.iReserved = 0; |
|
796 info.iLength = aText.Length(); |
|
797 info.iTickCount = NKern::TickCount(); |
|
798 info.iThreadId = aTraceThread; |
|
799 TPckg<SCloggerTraceInfo> id(info); |
|
800 |
|
801 NKern::Lock(); |
|
802 #ifdef __SMP__ |
|
803 __SPIN_LOCK(iBufferLock); |
|
804 #endif |
|
805 if (iInTheMiddleOfTracing) |
|
806 { |
|
807 // In a recursive loop, probably due to an assertion failure in the below code triggering a kern::printf |
|
808 __BREAKPOINT(); |
|
809 } |
|
810 iInTheMiddleOfTracing = ETrue; |
|
811 |
|
812 TBool ok = WriteOut(id, id.Length() + aText.Length()); |
|
813 if (ok) WriteOut(aText); |
|
814 if (!ok) |
|
815 { |
|
816 //consume = EFalse; // Don't consume if the buffer overflowed |
|
817 if (iOverflows != KMaxTUint) |
|
818 { |
|
819 // Don't overflow the overflow counter! |
|
820 iOverflows++; |
|
821 } |
|
822 } |
|
823 NotifyClient(); |
|
824 iInTheMiddleOfTracing = EFalse; |
|
825 LOG("-DoTrace iStartAddr=%x iEndAddr=%x iCurrent=%x iClientStart=%x iClientEnd=%x", iStartAddr, iEndAddr, iCurrent, iClientStart, iClientEnd); |
|
826 #ifdef __SMP__ |
|
827 __SPIN_UNLOCK(iBufferLock); |
|
828 #endif |
|
829 |
|
830 NKern::Unlock(); |
|
831 } |
|
832 |
|
833 TBool DCloggerDebugRouter::WriteOut(const TDesC8& aBuf, TInt aLengthToConsider) |
|
834 { |
|
835 /* |
|
836 In the case we are using the end of the buffer and the client is writing the start (canWrap == TRUE) |
|
837 +-----------+ |
|
838 | | |
|
839 iClientStart -> | | |
|
840 | | |
|
841 | | |
|
842 iClientEnd -> | | ^ |
|
843 | | | This is what needs writing out next |
|
844 | | | (currently) |
|
845 | | v |
|
846 | | <- iCurrent |
|
847 | | |
|
848 | | |
|
849 +-----------+ |
|
850 |
|
851 In the case where the client is writing near the end and we have wrapped round to the beginning (canWrap == FALSE) |
|
852 +-----------+ |
|
853 | | |
|
854 | | |
|
855 | | <- iCurrent |
|
856 | | |
|
857 | | |
|
858 | | |
|
859 | | |
|
860 | | |
|
861 iClientStart -> | | |
|
862 | | |
|
863 iClientEnd -> | | |
|
864 +-----------+ |
|
865 */ |
|
866 |
|
867 TUint endSpace, startSpace; |
|
868 if (iClient && iClientStart) |
|
869 { |
|
870 TBool canWrap = iClientStart <= iCurrent; // If the client is still using the end of the buffer, we can't wrap around |
|
871 endSpace = (canWrap ? iEndAddr : iClientStart) - iCurrent; |
|
872 startSpace = canWrap ? (iClientStart - iStartAddr) : 0; |
|
873 } |
|
874 else |
|
875 { |
|
876 // If there's no client yet, we can ignore the client ptrs. |
|
877 // TODO if there's no client, we should also do a rolling overwrite of the buffer (ie better to drop the oldest statements than the recent ones |
|
878 // TODO however this has its problems because this is not a pure byte stream - it'd mess up the headers if you were to try and save what was in the buffer rather than clearing it when it gets full |
|
879 endSpace = iEndAddr - iCurrent; |
|
880 startSpace = 0; //iCurrent - iStartAddr; |
|
881 } |
|
882 |
|
883 ASSERT(endSpace <= iEndAddr - iStartAddr); |
|
884 ASSERT(startSpace < iEndAddr - iStartAddr); |
|
885 |
|
886 TInt lenToTest = aLengthToConsider; |
|
887 if (lenToTest == 0) lenToTest = aBuf.Length(); |
|
888 |
|
889 if ((TUint)lenToTest > startSpace + endSpace) return EFalse; |
|
890 |
|
891 TPtrC8 endFrag = aBuf.Left(endSpace); |
|
892 memcpy((TAny*)iCurrent, endFrag.Ptr(), endFrag.Size()); |
|
893 iCurrent += endFrag.Size(); |
|
894 |
|
895 if (endFrag.Length() < aBuf.Length()) |
|
896 { |
|
897 LOG("Wrapping round"); |
|
898 ASSERT(iCurrent == iEndAddr); |
|
899 iCurrent = iStartAddr; |
|
900 TPtrC8 remainder = aBuf.Mid(endSpace); |
|
901 memcpy((TAny*)iStartAddr, remainder.Ptr(), remainder.Size()); |
|
902 iCurrent += remainder.Size(); |
|
903 iFirstFrame = iCurrent; // iFirstFrame is now no longer iStartAddr, it's the earliest point in the buffer that a frame starts at |
|
904 } |
|
905 return ETrue; |
|
906 } |
|
907 |
|
908 void DCloggerDebugRouter::CloseChunk() |
|
909 { |
|
910 if (iChunk) |
|
911 { |
|
912 NKern::ThreadEnterCS(); |
|
913 Kern::ChunkClose(iChunk); |
|
914 iChunk = NULL; |
|
915 NKern::ThreadLeaveCS(); |
|
916 } |
|
917 } |
|
918 |
|
919 TInt DCloggerDebugRouter::OpenChunk() |
|
920 { |
|
921 TInt r = KErrNone; |
|
922 if (iChunk == NULL) |
|
923 { |
|
924 TChunkCreateInfo info; |
|
925 info.iType = TChunkCreateInfo::ESharedKernelSingle; |
|
926 info.iMaxSize = KChunkSize; |
|
927 #ifdef __EPOC32__ |
|
928 info.iMapAttr = (TInt)EMapAttrFullyBlocking; // Full caching |
|
929 #endif |
|
930 info.iOwnsMemory = ETrue; // Use memory from system's free pool |
|
931 info.iDestroyedDfc = NULL; |
|
932 |
|
933 TUint32 chunkMapAttr; |
|
934 TLinAddr addr; |
|
935 NKern::ThreadEnterCS(); |
|
936 if (KErrNone != (r = Kern::ChunkCreate(info, iChunk, addr, chunkMapAttr))) |
|
937 { |
|
938 NKern::ThreadLeaveCS(); |
|
939 return r; |
|
940 } |
|
941 r = Kern::ChunkCommit(iChunk,0,KChunkSize); |
|
942 if(r!=KErrNone) |
|
943 { |
|
944 Kern::ChunkClose(iChunk); |
|
945 iChunk = NULL; |
|
946 NKern::ThreadLeaveCS(); |
|
947 return r; |
|
948 } |
|
949 NKern::ThreadLeaveCS(); |
|
950 //TLinAddr addr = (TLinAddr)iChunk->Base(); |
|
951 iStartAddr = addr + sizeof(SDebugChunkHeader); // Bottom few words are reserved for metadata |
|
952 iEndAddr = addr + KChunkSize; |
|
953 iCurrent = iStartAddr; |
|
954 iFirstFrame = iStartAddr; |
|
955 RegisterCrashDumpAreas(KNullDesC8); // As now we have our main chunk |
|
956 } |
|
957 if (iClient) |
|
958 { |
|
959 NKern::ThreadEnterCS(); |
|
960 r = Kern::MakeHandleAndOpen(iClient, iChunk); |
|
961 NKern::ThreadLeaveCS(); |
|
962 /* |
|
963 if(r < KErrNone) |
|
964 { |
|
965 Kern::ChunkClose(iChunk); |
|
966 iChunk = NULL; |
|
967 NKern::ThreadLeaveCS(); |
|
968 return r; |
|
969 } |
|
970 */ |
|
971 iClientStart = iFirstFrame; |
|
972 iClientEnd = iClientStart; |
|
973 } |
|
974 |
|
975 return r; |
|
976 } |
|
977 |
|
978 void DCloggerDebugRouter::NotifyClient() |
|
979 { |
|
980 LOG("NotifyClient"); |
|
981 if (iCompleteClientDfc.Queued()) |
|
982 { |
|
983 // The DFC that will signal the client has already been fired and the client pointers calculated. Don't get in its way. |
|
984 return; |
|
985 } |
|
986 if (!iClientStatus || !iClient) |
|
987 { |
|
988 // Client not ready |
|
989 return; |
|
990 } |
|
991 if (iCurrent == iClientEnd) |
|
992 { |
|
993 // No new data to send |
|
994 return; |
|
995 } |
|
996 |
|
997 LOG("Notifying client enqueuing client DFC"); |
|
998 |
|
999 // The start of the chunk stores the info for the client about which bits of the buffer it needs to read |
|
1000 TUint realStartAddr = iStartAddr - sizeof(SDebugChunkHeader); |
|
1001 SDebugChunkHeader* header = (SDebugChunkHeader*)realStartAddr; |
|
1002 TUint* clientStartPtr = &header->iStartOffset; |
|
1003 TUint* clientEndPtr = &header->iEndOffset; |
|
1004 TUint* overflows = &header->iOverflows; |
|
1005 |
|
1006 LOG("Notifying with iClientStart=%x iClientEnd=%x iCurrent=%x", iClientStart, iClientEnd, iCurrent); |
|
1007 |
|
1008 *overflows = iOverflows; |
|
1009 iOverflows = 0; // Reset this each time we write to the client, it's not cumulative |
|
1010 |
|
1011 TLinAddr end = iCurrent; |
|
1012 iClientStart = iClientEnd; |
|
1013 iClientEnd = end; |
|
1014 |
|
1015 *clientStartPtr = iClientStart - realStartAddr; // Offset of the end of the last read from the start of the chunk |
|
1016 *clientEndPtr = iClientEnd - realStartAddr; // Offset of current ptr from start of chunk |
|
1017 |
|
1018 LOG("Signalling client start %08x end %08x", *clientStartPtr, *clientEndPtr); |
|
1019 iCompleteClientDfc.DoEnque(); |
|
1020 } |
|
1021 |
|
1022 void DCloggerDebugRouter::CompleteClient(TAny* aSelf) |
|
1023 { |
|
1024 DCloggerDebugRouter* self = static_cast<DCloggerDebugRouter*>(aSelf); |
|
1025 self->DoCompleteClient(); |
|
1026 } |
|
1027 |
|
1028 void DCloggerDebugRouter::DoCompleteClient() |
|
1029 { |
|
1030 // Kern::RequestComplete involves taking the system lock, which will cause debug if NKERN is set |
|
1031 // So temporarily unset it |
|
1032 TInt debugMask = 0; |
|
1033 TInt oldVal = (TInt)NKern::SafeSwap((TAny*)debugMask, (TAny*&)Kern::SuperPage().iDebugMask[0]); |
|
1034 Kern::RequestComplete(iClient, iClientStatus, KErrNone); |
|
1035 Kern::SuperPage().iDebugMask[0] = oldVal; |
|
1036 } |
|
1037 |
|
1038 EXPORT_C void CloggerDebugRouter::DebugPortChanged() |
|
1039 { |
|
1040 DCloggerDebugRouter* self = gRouter; |
|
1041 if (self) |
|
1042 { |
|
1043 if (Kern::SuperPage().iDebugPort == KCloggerDebugPort) |
|
1044 { |
|
1045 // Then enable ourselves |
|
1046 TInt err = self->OpenChunk(); |
|
1047 if (!err) |
|
1048 { |
|
1049 self->SetConsumeLogs(ETrue); |
|
1050 self->SetEnabled(ETrue); |
|
1051 } |
|
1052 } |
|
1053 else |
|
1054 { |
|
1055 // Disable? Or should we just stay running until explicitly disabled by the LDD? |
|
1056 //self->SetEnabled(EFalse); |
|
1057 |
|
1058 // I think we should stay enabled until the LDD tells us otherwise... |
|
1059 } |
|
1060 } |
|
1061 } |
|
1062 |
|
1063 EXPORT_C void CloggerDebugRouter::SetCrashDumpFunctions(TRegisterFn aRegisterFn, TUnregisterFn aUnregisterFn) |
|
1064 { |
|
1065 if (gRouter) |
|
1066 { |
|
1067 gRouter->SetCrashDumpFunctions(aRegisterFn, aUnregisterFn); |
|
1068 } |
|
1069 } |
|
1070 |
|
1071 void DCloggerDebugRouter::SetCrashDumpFunctions(TRegisterFn aRegisterFn, TUnregisterFn aUnregisterFn) |
|
1072 { |
|
1073 NKern::Lock(); |
|
1074 iRegisterCrashDumpFn = aRegisterFn; |
|
1075 iUnregisterCrashDumpFn = aUnregisterFn; |
|
1076 NKern::Unlock(); |
|
1077 RegisterCrashDumpAreas(KNullDesC8); |
|
1078 } |
|
1079 |
|
1080 TInt DCloggerDebugRouter::RegisterCrashDumpAreas(const TDesC8& aAreas) |
|
1081 { |
|
1082 if (!iRegisterCrashDumpFn || !iUnregisterCrashDumpFn) |
|
1083 { |
|
1084 return KErrNotReady; |
|
1085 } |
|
1086 |
|
1087 LOG("Unregistering current crashdumps"); |
|
1088 // Unregister current ones |
|
1089 for (TInt i = 0; i < iNumCrashDumpAreas; i++) |
|
1090 { |
|
1091 (*iUnregisterCrashDumpFn)(iCrashDumpAreas[i]); |
|
1092 DChunk* chunk = iCrashDumpAreas[i].iChunk; |
|
1093 if (chunk) |
|
1094 { |
|
1095 LOG("Closing chunk %O", chunk); |
|
1096 NKern::ThreadEnterCS(); |
|
1097 chunk->Close(NULL); |
|
1098 NKern::ThreadLeaveCS(); |
|
1099 LOG("Closed chunk %O", chunk); |
|
1100 } |
|
1101 } |
|
1102 iNumCrashDumpAreas = 0; |
|
1103 |
|
1104 // Register our ones |
|
1105 LOG("Registering new crashdumps"); |
|
1106 if (iChunk) |
|
1107 { |
|
1108 LOG("Registering rdebugprint buffer"); |
|
1109 _LIT8(KLddBuf, "Clogger RDebug::Print buffer"); |
|
1110 SCrashDumpArea& area = iCrashDumpAreas[iNumCrashDumpAreas++]; |
|
1111 area.iChunk = NULL; // Only specify the chunk for client-side chunks we otherwise don't hold open |
|
1112 area.iName = KLddBuf; |
|
1113 (*iRegisterCrashDumpFn)((TAny*)iStartAddr, iEndAddr-iStartAddr, area); |
|
1114 } |
|
1115 LOG("Registering ISR buffer"); |
|
1116 _LIT8(KIsrBuf, "Clogger ISR buffer"); |
|
1117 SCrashDumpArea& area = iCrashDumpAreas[iNumCrashDumpAreas++]; |
|
1118 area.iChunk = NULL; // Only specify the chunk for client-side chunks we otherwise don't hold open |
|
1119 area.iName = KIsrBuf; |
|
1120 (*iRegisterCrashDumpFn)((TAny*)iInterruptBuf->Ptr(), iInterruptBuf->MaxSize(), area); |
|
1121 |
|
1122 // Now do client ones |
|
1123 const SCloggerCrashDumpArea* clientAreas = (const SCloggerCrashDumpArea*)aAreas.Ptr(); |
|
1124 TInt num = aAreas.Length() / sizeof(SCloggerCrashDumpArea); |
|
1125 for (TInt i = 0; i < num && iNumCrashDumpAreas < KMaxCrashDumpAreas; i++) |
|
1126 { |
|
1127 const SCloggerCrashDumpArea& clientArea = clientAreas[i]; |
|
1128 LOG("Getting chunk for client buffer %d", i); |
|
1129 NKern::LockSystem(); |
|
1130 DChunk* chunk = (DChunk*)Kern::ObjectFromHandle(iClient, clientArea.iChunkHandle, EChunk); |
|
1131 NKern::UnlockSystem(); |
|
1132 LOG("Got client chunk %O", chunk); |
|
1133 if (chunk && chunk->Open() == KErrNone) |
|
1134 { |
|
1135 SCrashDumpArea& area = iCrashDumpAreas[iNumCrashDumpAreas++]; |
|
1136 area.iChunk = chunk; |
|
1137 area.iName = clientArea.iName; |
|
1138 TAny* ptr = (TAny*)(chunk->Base() + clientArea.iOffset); |
|
1139 (*iRegisterCrashDumpFn)(ptr, clientArea.iSize, area); |
|
1140 } |
|
1141 } |
|
1142 LOG("Completed registering new crashdump areas"); |
|
1143 return KErrNone; |
|
1144 } |
|
1145 |
|
1146 TBool DCloggerDebugRouter::StayEnabled() |
|
1147 { |
|
1148 return KEnableEarlyRdebug || Kern::SuperPage().iDebugPort == KCloggerDebugPort; |
|
1149 } |
|
1150 |
|
1151 // End of File |