libraries/clogger/debugRouter/debugRouter.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     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, &params, 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, &params, 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