commands/fdb/fdb.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // fdb.cpp
       
     2 // 
       
     3 // Copyright (c) 2009 - 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 <fshell/ioutils.h>
       
    14 #include <fshell/memoryaccesscmd.h>
       
    15 #include <fshell/ltkutils.h>
       
    16 #include <fshell/bsym.h>
       
    17 #include <fshell/descriptorutils.h>
       
    18 #include <fshell/iocons_writer.h>
       
    19 #include <fshell/line_editor.h>
       
    20 #include <fshell/qr3dll.h>
       
    21 #include <u32std.h> // Is this available in all environments? If not, need to define TDesType ourselves
       
    22 #include <babitflags.h>
       
    23 #include <badesca.h>
       
    24 _LIT(KCrLf, "\r\n");
       
    25 _LIT(KPrompt, "fdb>");
       
    26 
       
    27 using namespace IoUtils;
       
    28 using namespace LtkUtils;
       
    29 
       
    30 const TInt KMaxRegisters = 32;
       
    31 
       
    32 class CCmdFdb : public CMemoryAccessCommandBase, public MLineEditorObserver, public MLineCompleter
       
    33 	{
       
    34 public:
       
    35 	static CCommandBase* NewLC();
       
    36 	~CCmdFdb();
       
    37 private:
       
    38 	struct SThreadContext;
       
    39 	CCmdFdb();
       
    40 	void InstallL();
       
    41 	void AttachL(TUint aThreadId);
       
    42 	void Detach(SThreadContext* aContext);
       
    43 	void PrintThreadInfo(SThreadContext& aContext);
       
    44 	void PrintRegistersL(SThreadContext& aThread);
       
    45 	void PrintRegistersL(SThreadContext& aThread, TBool aUserMode);
       
    46 	void PrintRegistersLRPC(SThreadContext& aThread, TBool aUserMode);
       
    47 	void RefreshL(SThreadContext& aContext);
       
    48 	void RefreshIfRunningL(SThreadContext& aContext);
       
    49 	TPtrC LookupSymbol(TUint32 aAddress);
       
    50 	void StartCommandParsingL();
       
    51 	void ProcessLineL(const TDesC& aLine);
       
    52 	void FocusL(TUint aThreadId);
       
    53 	SThreadContext* ContextForThread(TUint aThreadId) const;
       
    54 	SThreadContext& CurrentL();
       
    55 	SThreadContext& CurrentNoRefreshL();
       
    56 	enum TPrintMode { EJustSymbols, EAllData, EHexDump };
       
    57 	void PrintMemL(TUint aThreadId, TUint32 aStart, TUint32 aEnd, TPrintMode aMode);
       
    58 	void BrrrrrainsL();
       
    59 	void ShowHelpTextL();
       
    60 	TBool IsSymbol(TUint aAddress) const;
       
    61 	void StartInteractiveViewL(TLinAddr aAddress);
       
    62 	void DrawMemViewL(TBool aUpdate);
       
    63 	void UpdateMemForMemViewL();
       
    64 	static TInt IsDescriptorHeader(TUint8 const* aHeaderPtr, TInt aMaxLen);
       
    65 	void ShowBreakpointsL();
       
    66 	static TInt BreakTest(TAny* aPtr);
       
    67 	static TInt BreakTestLtk(TAny* aPtr);
       
    68 	static TInt BreakTestCond(TAny* aPtr);
       
    69 	void ClearAllBreakpointsL();
       
    70 	void BreakpointHit(const RMemoryAccess::TBreakpointNotification& aNotif);
       
    71 	void CompleteLineWithSymbolL(TConsoleLine& aLine, TLex& aLex);
       
    72 	void CheckForConditionL(TLex& aLex, RMemoryAccess::TPredicate& aCondition);
       
    73 	
       
    74 private: // From MLineCompleter
       
    75 	void LcCompleteLineL(TConsoleLine& aLine, const TChar& aEscapeChar);
       
    76 
       
    77 private: // From MLineEditorObserver
       
    78 	void LeoHandleLine(const TDesC& aLine);
       
    79 
       
    80 private: // From CCommandBase.
       
    81 	virtual const TDesC& Name() const;
       
    82 	virtual void DoRunL();
       
    83 	virtual void ArgumentsL(RCommandArgumentList& aArguments);
       
    84 	virtual void OptionsL(RCommandOptionList& aOptions);
       
    85 	void RunL();
       
    86 	void DoCancel();
       
    87 
       
    88 private:
       
    89 	// Command line stuff
       
    90 	TBool iAllThreads;
       
    91 	TUint iThreadId;
       
    92 	TFileName2 iBsymFile;
       
    93 	TFileName2 iMapFileDir;
       
    94 
       
    95 	// Thread context
       
    96 	struct SThreadContext
       
    97 		{
       
    98 		SThreadContext() : iUserValidRegisters(0), iSupervisorValidRegisters(0), iFlags(0) {}
       
    99 
       
   100 		RThread iThread;
       
   101 		TUint32 iUserRegisters[KMaxRegisters];
       
   102 		TUint32 iUserValidRegisters;
       
   103 		TUint32 iSupervisorRegisters[KMaxRegisters];
       
   104 		TUint32 iSupervisorValidRegisters;
       
   105 		TThreadKernelInfo iKernelInfo;
       
   106 		enum TFlags { ERunning = 1, };
       
   107 		TBitFlags32 iFlags;
       
   108 		};
       
   109 	SThreadContext* iCurrent;
       
   110 	RPointerArray<SThreadContext> iThreads;
       
   111 
       
   112 	// Other stuff
       
   113 	CSymbolics* iSymbols;
       
   114 	TBuf<256> iTempNameBuf;
       
   115 
       
   116 	// Line editor support
       
   117 	TIoConsWriterAdaptor iConsoleAdapter;
       
   118 	CLineEditor* iLineEditor;
       
   119 	TBuf<256> iCommandLineBuf;
       
   120 	TBool iFinishedCommand;
       
   121 	TBool iShouldExit;
       
   122 
       
   123 	// Interactive wossname support
       
   124 	enum TViewType
       
   125 		{
       
   126 		EUnspecified,
       
   127 		EStack,
       
   128 		EHeap,
       
   129 		};
       
   130 	TViewType iMemoryViewType;
       
   131 	TLinAddr iMemStart;
       
   132 	RBuf8 iMemBuf;
       
   133 	/*
       
   134 	class TCrumb
       
   135 		{
       
   136 		enum TType { EAddress, EHeapCell, };
       
   137 		TType iType;
       
   138 		TLinAddr iAddress;
       
   139 		TInt iIndex;
       
   140 		}
       
   141 	RArray<TCrumb> iBreadcrumbs;
       
   142 	RArray<TLinAddr> iMarks;
       
   143 	RArray<TLinAddr> iLinks;
       
   144 	*/
       
   145 
       
   146 	// Breakpoint support
       
   147 	RMemoryAccess::TBreakpointNotification iBreakpointNotification;
       
   148 	TPckg<RMemoryAccess::TBreakpointNotification> iBreakpointNotificationPkg;
       
   149 	class CBreakpointNotifier : public CActive
       
   150 		{
       
   151 	public:
       
   152 		CBreakpointNotifier(CCmdFdb& aCmd);
       
   153 		~CBreakpointNotifier();
       
   154 
       
   155 	private:
       
   156 		void Request();
       
   157 		void RunL();
       
   158 		void DoCancel();
       
   159 
       
   160 	private:
       
   161 		CCmdFdb& iCmd;
       
   162 		};
       
   163 	friend class CBreakpointNotifier; // Declaration needed for gcc 2.9
       
   164 	CBreakpointNotifier* iBreakpointNotifier;
       
   165 	};
       
   166 
       
   167 EXE_BOILER_PLATE(CCmdFdb)
       
   168 
       
   169 CCommandBase* CCmdFdb::NewLC()
       
   170 	{
       
   171 	CCmdFdb* self = new(ELeave) CCmdFdb();
       
   172 	CleanupStack::PushL(self);
       
   173 	self->BaseConstructL();
       
   174 	return self;
       
   175 	}
       
   176 
       
   177 CCmdFdb::~CCmdFdb()
       
   178 	{
       
   179 	Cancel();
       
   180 	delete iLineEditor;
       
   181 	for (TInt i = 0; i < iThreads.Count(); i++)
       
   182 		{
       
   183 		SThreadContext* thread = iThreads[i];
       
   184 		thread->iThread.Close();
       
   185 		delete thread;
       
   186 		}
       
   187 	iThreads.Close();
       
   188 	delete iSymbols;
       
   189 	iMemBuf.Close();
       
   190 	delete iBreakpointNotifier;
       
   191 	/*
       
   192 	iLinks.Close();
       
   193 	iBreadcrumbs.Close();
       
   194 	iMarks.Close();
       
   195 	*/
       
   196 	}
       
   197 
       
   198 CCmdFdb::CCmdFdb()
       
   199 	: CMemoryAccessCommandBase(EManualComplete), iConsoleAdapter(Stdout()), iBreakpointNotificationPkg(iBreakpointNotification)
       
   200 	{
       
   201 	}
       
   202 
       
   203 const TDesC& CCmdFdb::Name() const
       
   204 	{
       
   205 	_LIT(KName, "fdb");	
       
   206 	return KName;
       
   207 	}
       
   208 
       
   209 void CCmdFdb::ArgumentsL(RCommandArgumentList& aArguments)
       
   210 	{
       
   211 	aArguments.AppendUintL(iThreadId, _L("threadid"));
       
   212 	}
       
   213 
       
   214 void CCmdFdb::OptionsL(RCommandOptionList& aOptions)
       
   215 	{
       
   216 	aOptions.AppendBoolL(iAllThreads, _L("all"));
       
   217 	aOptions.AppendFileNameL(iBsymFile, _L("symbols"));
       
   218 	aOptions.AppendFileNameL(iMapFileDir, _L("mapfiles"));
       
   219 	}
       
   220 
       
   221 struct STestData
       
   222 	{
       
   223 	STestData() : iPtr8(NULL, 0) {}
       
   224 
       
   225 	char iPad1[12];
       
   226 	TBuf8<6> iBuf8;
       
   227 	TInt iPad2;
       
   228 	TBufC8<9> iBufC8;
       
   229 	char iPad3;
       
   230 	TPtrC8 iPtrC8;
       
   231 	TUint64 iPad4;
       
   232 	TPtr8 iPtr8;
       
   233 	char iPad5[3];
       
   234 	};
       
   235 
       
   236 
       
   237 void CCmdFdb::DoRunL()
       
   238 	{
       
   239 	LoadMemoryAccessL();
       
   240 	TInt mode = iMemAccess.GetZombieDebugMode();
       
   241 	LeaveIfErr(mode, _L("Couldn't get zombie mode from driver"));
       
   242 
       
   243 	iSymbols = new(ELeave) CSymbolics(FsL());
       
   244 	if (iBsymFile.Length())
       
   245 		{
       
   246 		//Printf(_L("Loading symbolics... ")); // It can take a while...
       
   247 		iSymbols->AddBsymFileL(iBsymFile);
       
   248 		//Printf(_L("done.\r\n"));
       
   249 		}
       
   250 	if (iMapFileDir.Length())
       
   251 		{
       
   252 		iSymbols->SetFallbackMapFileDirL(iMapFileDir);
       
   253 		}
       
   254 
       
   255 	// Testing
       
   256 	//CMapFile* map = CMapFile::NewL(FsL(), _L("C:\\symbols\\QResources3.exe.map"));
       
   257 	//iSymbols->AddMapFileL(map);
       
   258 	//const TDesC& symName = iSymbols->LookupL(_L("QResources3.exe"), 0x10abc);
       
   259 	//Printf(_L("Found symbol = %S\r\n"), &symName);
       
   260 	
       
   261 	if (Env().IsDefined(_L("FDB_TEST")))
       
   262 		{
       
   263 		STestData test;
       
   264 		test.iBuf8 = _L8("12345");
       
   265 		test.iBufC8 = _L8("abcdefg");
       
   266 		test.iPtrC8.Set(test.iBufC8);
       
   267 		TPckg<STestData> pkg(test);
       
   268 		iMemBuf.Assign(pkg.AllocL());
       
   269 		DrawMemViewL(EFalse);
       
   270 		return;
       
   271 		}
       
   272 	
       
   273 	TBool install = ETrue;
       
   274 	// Figure out something sensible to do
       
   275 	if (mode != 0 || iThreadId != 0) install = EFalse;
       
   276 
       
   277 	if (iAllThreads) Printf(_L("Note that because --all-threads was specified, this and all future commands will hang rather than exiting!\r\n"));
       
   278 
       
   279 	InstallL(); // Always do this, in case user has changed the --all-threads setting
       
   280 	if (install)
       
   281 		{
       
   282 		// This will really mess up evalid, but the toolkit doesn't really use it so I don't feel *too* guilty
       
   283 		Printf(_L8("Welcome to fdb (build " __DATE__ " " __TIME__ ").\r\nDebugger hook installed and will stay running until you type 'uninstall'.\r\nYou can exit fdb if required and it will stay running in the background.\r\nType 'help' for command info.\r\n"));
       
   284 		}
       
   285 	else
       
   286 		{
       
   287 		AttachL(iThreadId);
       
   288 		}
       
   289 
       
   290 	iBreakpointNotifier = new(ELeave) CBreakpointNotifier(*this);
       
   291 	TInt err = iMemAccess.RegisterPersistantBreakpoint(LtkUtils::BreakpointAddr());
       
   292 	if (err != KErrNone && err != KErrAlreadyExists)
       
   293 		{
       
   294 		LeaveIfErr(err, _L("Couldn't install the LtkUtils::Breakpoint() breakpoint"));
       
   295 		}
       
   296 	StartCommandParsingL();
       
   297 	}
       
   298 
       
   299 void CCmdFdb::InstallL()
       
   300 	{
       
   301 	LeaveIfErr(iMemAccess.SetZombieDebugMode(iAllThreads ? 2 : 1), _L("Couldn't install thread monitor"));
       
   302 	const TUint32 KAllThreadsSystem = 1; // Word 2, bit 0
       
   303 	TUint32 dbgmask = UserSvr::DebugMask(2);
       
   304 	if (dbgmask & KAllThreadsSystem)
       
   305 		{
       
   306 		Printf(_L("(Clearing KAllThreadsSystem attribute)\r\n"));
       
   307 		User::SetDebugMask(dbgmask & ~KAllThreadsSystem, 2);
       
   308 		}
       
   309 	}
       
   310 
       
   311 void CCmdFdb::AttachL(TUint aThreadId)
       
   312 	{
       
   313 	if (aThreadId == 0)
       
   314 		{
       
   315 		// Need to figure out something to attach to
       
   316 		TBuf8<64> buf; // TODO handle more than this many zombies
       
   317 		TInt res = iMemAccess.GetZombies(buf);
       
   318 		LeaveIfErr(res, _L("Couldn't get zombie info from driver"));
       
   319 		//TInt leftOver = 0;
       
   320 		//if (res > buf.MaxLength()) leftOver = (res - buf.MaxLength()) / sizeof(TUint);
       
   321 		RMemoryAccess::TZombieInfo* ptr = (RMemoryAccess::TZombieInfo*)buf.Ptr();
       
   322 		TInt zombiecount = buf.Length() / sizeof(RMemoryAccess::TZombieInfo);
       
   323 		for (TInt i = 0; i < zombiecount; i++)
       
   324 			{
       
   325 			TUint id = ptr[i].iThreadId;
       
   326 			if (ContextForThread(id)) continue; // already attached to this thread, keep looking
       
   327 			RThread thread;
       
   328 			TInt err = iMemAccess.RThreadForceOpen(thread, id);
       
   329 			if (err)
       
   330 				{
       
   331 				PrintWarning(_L("Couldn't open thread %u"), id);
       
   332 				continue;
       
   333 				}
       
   334 			iTempNameBuf = thread.FullName();
       
   335 			Printf(_L("(Found thread id %u %S)\r\n"), id, &iTempNameBuf);
       
   336 			if (aThreadId == 0) aThreadId = id;
       
   337 			thread.Close();
       
   338 			}
       
   339 		if (aThreadId == 0)
       
   340 			{
       
   341 			if (buf.Length())
       
   342 				Printf(_L("No zombied threads found that aren't already attached.\r\n"));
       
   343 			else
       
   344 				PrintWarning(_L("No zombied threads found to attach to."));
       
   345 			return;
       
   346 			}
       
   347 		else
       
   348 			{
       
   349 			Printf(_L("(Attaching to thread %u)\r\n"), aThreadId);
       
   350 			}
       
   351 		}
       
   352 
       
   353 	SThreadContext* context = ContextForThread(aThreadId);
       
   354 	if (context)
       
   355 		{
       
   356 		PrintWarning(_L("Already attached to thread %u, focussing it instead."), aThreadId);
       
   357 		iCurrent = context;
       
   358 		return;
       
   359 		}
       
   360 
       
   361 	context = new(ELeave) SThreadContext;
       
   362 	CleanupStack::PushL(context);
       
   363 	RThread& thread(context->iThread);
       
   364 	CleanupClosePushL(thread);
       
   365 	LeaveIfErr(iMemAccess.RThreadForceOpen(thread, aThreadId), _L("Couldn't open thread %u"), aThreadId);
       
   366 	RefreshL(*context);
       
   367 	iThreads.AppendL(context);
       
   368 	CleanupStack::Pop(2, context); // context->iThread, context
       
   369 	iCurrent = context;
       
   370 
       
   371 	PrintThreadInfo(*context);
       
   372 	// Don't print any more than this - it makes the output too wordy
       
   373 	//PrintRegistersL(*context);
       
   374 	}
       
   375 
       
   376 void CCmdFdb::PrintThreadInfo(SThreadContext& aContext)
       
   377 	{
       
   378 	RThread& aThread = aContext.iThread;
       
   379 	TFullName name = aThread.FullName();
       
   380 	Write(_L("Name: "));
       
   381 	Write(name);
       
   382 
       
   383 	Printf(_L("\r\nThread Id: %d, exit type: "), (TUint)aThread.Id());
       
   384 	TExitType exitType = aThread.ExitType();
       
   385 	if (exitType == EExitPending)
       
   386 		{
       
   387 		Printf(_L("Still running\r\n"));
       
   388 		}
       
   389 	else if (exitType == EExitKill)
       
   390 		{
       
   391 		Printf(_L("Kill %d\r\n"), aThread.ExitReason());
       
   392 		}
       
   393 	else if (exitType == EExitTerminate)
       
   394 		{
       
   395 		Printf(_L("Terminate %d\r\n"), aThread.ExitReason());
       
   396 		}
       
   397 	else if (exitType == EExitPanic)
       
   398 		{
       
   399 		TExitCategoryName exitCategory = aThread.ExitCategory();
       
   400 		Printf(_L("Panic %S %d\r\n"), &exitCategory, aThread.ExitReason());
       
   401 		}
       
   402 
       
   403 	Printf(_L("User stack: base=%08x limit=%08x\r\n"), aContext.iKernelInfo.UserStackBase(), aContext.iKernelInfo.iUserStackLimit);
       
   404 	Printf(_L("Kern stack: base=%08x limit=%08x\r\n"), aContext.iKernelInfo.iSupervisorStack + aContext.iKernelInfo.iSupervisorStackSize, aContext.iKernelInfo.iSupervisorStack);
       
   405 	}
       
   406 
       
   407 void CCmdFdb::PrintRegistersL(SThreadContext& aThread)
       
   408 	{
       
   409 	PrintRegistersL(aThread, ETrue);
       
   410 	PrintRegistersL(aThread, EFalse);
       
   411 	}
       
   412 
       
   413 void CCmdFdb::PrintRegistersL(SThreadContext& aThread, TBool aUserMode)
       
   414 	{
       
   415 	if (aUserMode)
       
   416 		{
       
   417 		Printf(_L("User mode registers:\r\n"));
       
   418 		}
       
   419 	else
       
   420 		{
       
   421 		Printf(_L("Supervisor mode registers:\r\n"));
       
   422 		}
       
   423 
       
   424 	TUint32 valid = aThread.iUserValidRegisters;
       
   425 	TUint32* ptr = aThread.iUserRegisters;
       
   426 	if (!aUserMode)
       
   427 		{
       
   428 		valid = aThread.iSupervisorValidRegisters;
       
   429 		ptr = aThread.iSupervisorRegisters;
       
   430 		}
       
   431 
       
   432 	if (valid == 0) Printf(_L("(No valid registers)\r\n"));
       
   433 	// From here down is ARM specific, but since no other platforms implement this API there's no pressing need to ifdef it
       
   434 	// See TArmRegSet for the ordering
       
   435 	for (TInt i = 0; i < 16; i++)
       
   436 		{
       
   437 		if (valid & (1<<i))
       
   438 			{
       
   439 			if (i < 10) Write(_L(" ")); // extra space for padding
       
   440 			Printf(_L("  R%d: "), i);
       
   441 			Printf(_L("%08x "), ptr[i]);
       
   442 			Write(LookupSymbol(ptr[i]));
       
   443 			Write(KCrLf);
       
   444 			}
       
   445 		}
       
   446 	if (valid & (1<<16))
       
   447 		{
       
   448 		Printf(_L("Flags (%cPSR): %08x\r\n"), aUserMode ? 'C' : 'S', ptr[16]); // CPSR or SPSR
       
   449 		}
       
   450 	if (valid & (1<<17))
       
   451 		{
       
   452 		// Domain Access Control Register
       
   453 		Printf(_L(" DACR: %08x\r\n"), ptr[16]);
       
   454 		}
       
   455 	}
       
   456 
       
   457 void CCmdFdb::PrintRegistersLRPC(SThreadContext& aThread, TBool aUserMode)
       
   458 	{
       
   459 	// Print these in the format of the stack trace
       
   460 	TUint32 valid = aThread.iUserValidRegisters;
       
   461 	TUint32* ptr = aThread.iUserRegisters;
       
   462 	if (!aUserMode)
       
   463 		{
       
   464 		valid = aThread.iSupervisorValidRegisters;
       
   465 		ptr = aThread.iSupervisorRegisters;
       
   466 		}
       
   467 	
       
   468 	if (valid & 1<<15)
       
   469 		{
       
   470 		Printf(_L("     R15: %08x "), ptr[15]);
       
   471 		Write(LookupSymbol(ptr[15]));
       
   472 		Write(KCrLf);
       
   473 		}
       
   474 	if (valid & 1<<14)
       
   475 		{
       
   476 		Printf(_L("     R14: %08x "), ptr[14]);
       
   477 		Write(LookupSymbol(ptr[14]));
       
   478 		Write(KCrLf);
       
   479 		}
       
   480 	}
       
   481 
       
   482 void CCmdFdb::RefreshIfRunningL(SThreadContext& aContext)
       
   483 	{
       
   484 	if (iCurrent->iFlags.IsSet(SThreadContext::ERunning))
       
   485 		{
       
   486 		// Thread is still running, we should refresh our info
       
   487 		RefreshL(aContext);
       
   488 		}
       
   489 	}
       
   490 
       
   491 void CCmdFdb::RefreshL(SThreadContext& aContext)
       
   492 	{
       
   493 	aContext.iFlags.Assign(SThreadContext::ERunning, aContext.iThread.ExitType() == EExitPending);
       
   494 	TUint tid = aContext.iThread.Id();
       
   495 
       
   496 	// Get registers
       
   497 	TPtr8 userreg((TUint8*)&aContext.iUserRegisters[0], KMaxRegisters*sizeof(TUint32), KMaxRegisters*sizeof(TUint32));
       
   498 	userreg.FillZ();
       
   499 	aContext.iUserValidRegisters = 0;
       
   500 	TInt err = iMemAccess.GetRegisters(aContext.iThread, ETrue, userreg, aContext.iUserValidRegisters);
       
   501 	if (err) PrintError(err, _L("Couldn't read user registers for thread %u"), tid);
       
   502 
       
   503 	TPtr8 supreg((TUint8*)&aContext.iSupervisorRegisters[0], KMaxRegisters*sizeof(TUint32), KMaxRegisters*sizeof(TUint32));
       
   504 	supreg.FillZ();
       
   505 	aContext.iSupervisorValidRegisters = 0;
       
   506 	err = iMemAccess.GetRegisters(aContext.iThread, EFalse, supreg, aContext.iSupervisorValidRegisters);
       
   507 	if (err) PrintError(err, _L("Couldn't read supervisor registers for thread %u\r\n"), tid);
       
   508 
       
   509 	// And memaccess info
       
   510 	TPckg<TThreadKernelInfo> kerninfo(aContext.iKernelInfo);
       
   511 	err = iMemAccess.GetObjectInfoByHandle(EThread, RThread().Id(), aContext.iThread.Handle(), kerninfo);
       
   512 	if (err) PrintError(err, _L("Couldn't read thread info from memoryaccess for thread %u\r\n"), tid);
       
   513 	//aContext.iFlags.Assign(SThreadContext::ESuspended, aContext.iKernelInfo.iNThreadSuspendCount != 0);
       
   514 	}
       
   515 	
       
   516 TPtrC CCmdFdb::LookupSymbol(TUint32 aAddress)
       
   517 	{
       
   518 	TPtrC name;
       
   519 	if (iSymbols)
       
   520 		{
       
   521 		// Try straight ROM address lookup
       
   522 		TRAPD(err, name.Set(iSymbols->LookupL(aAddress)));
       
   523 		if (err) PrintError(err, _L("Failed to lookup symbol"));
       
   524 		if (name.Length()) return name;
       
   525 		}
       
   526 	// Try getting a codeseg from memaccess
       
   527 	TFullName8 codesegname;
       
   528 	TInt res = iMemAccess.FindAddressInCodeSegments(codesegname, (TAny*)aAddress);
       
   529 	if (res >= 0)
       
   530 		{
       
   531 		iTempNameBuf.Copy(codesegname);
       
   532 		if (iSymbols)
       
   533 			{
       
   534 			// Try codeseg lookup in CSymbolics (ie in a CMapFile)
       
   535 			TParsePtrC parse(iTempNameBuf);
       
   536 			TRAPD(err, name.Set(iSymbols->LookupL(parse.NameAndExt(), res)));
       
   537 			if (err) PrintError(err, _L("Failed to lookup symbol"));
       
   538 			if (name.Length()) return name;
       
   539 			}
       
   540 		// Otherwise fallback to just doing codeseg+offset
       
   541 		iTempNameBuf.AppendFormat(_L(" + 0x%x"), res);
       
   542 		return iTempNameBuf;
       
   543 		}
       
   544 	// Last ditch, check if euser thinks it's in ROM
       
   545 	if (RFs::IsRomAddress((TAny*)aAddress))
       
   546 		{
       
   547 		_LIT(KSomewhere, "[Somewhere in ROM]");
       
   548 		return KSomewhere();
       
   549 		}
       
   550 	return KNullDesC();
       
   551 	}
       
   552 
       
   553 void CCmdFdb::StartCommandParsingL()
       
   554 	{
       
   555 	TBuf<64> historyFile;
       
   556 	User::LeaveIfError(FsL().PrivatePath(historyFile));
       
   557 	historyFile.Insert(0, _L("c:"));
       
   558 	historyFile.Append(_L("fdb_history"));
       
   559 	Fs().CreatePrivatePath(EDriveC);
       
   560 
       
   561 	iLineEditor = CLineEditor::NewL(Fs(), iConsoleAdapter, *this, *this, historyFile);
       
   562 	iLineEditor->Start(KPrompt, iCommandLineBuf);
       
   563 	iLineEditor->ReinstatePromptAndUserInput();
       
   564 	SetErrorReported(EFalse);
       
   565 	Stdin().WaitForKey(iStatus);
       
   566 	SetActive();
       
   567 	}
       
   568 
       
   569 void CCmdFdb::RunL()
       
   570 	{
       
   571 	if (iStatus.Int() < 0)
       
   572 		{
       
   573 		// iosrv dead?
       
   574 		Complete(iStatus.Int());
       
   575 		return;
       
   576 		}
       
   577 
       
   578 	iLineEditor->HandleKey(Stdin().KeyCode(), Stdin().KeyModifiers());
       
   579 	if (iShouldExit)
       
   580 		{
       
   581 		Complete(KErrNone);
       
   582 		}
       
   583 	else if (iFinishedCommand)
       
   584 		{
       
   585 		iLineEditor->Start(KPrompt, iCommandLineBuf);
       
   586 		iLineEditor->ReinstatePromptAndUserInput();
       
   587 		iFinishedCommand = EFalse;
       
   588 		SetErrorReported(EFalse); // We need to clear this each time through
       
   589 		}
       
   590 	
       
   591 	if (!iShouldExit)
       
   592 		{
       
   593 		Stdin().WaitForKey(iStatus);
       
   594 		SetActive();
       
   595 		}
       
   596 	}
       
   597 
       
   598 void CCmdFdb::DoCancel()
       
   599 	{
       
   600 	Stdin().WaitForKeyCancel();
       
   601 	}
       
   602 
       
   603 void CCmdFdb::LcCompleteLineL(TConsoleLine& aLine, const TChar& /*aEscapeChar*/)
       
   604 	{
       
   605 	TPtrC line = aLine.ContentsToCursor();
       
   606 	TLex lex(line);
       
   607 	TPtrC cmd = lex.NextToken();
       
   608 	if (cmd != _L("b") && cmd != _L("break")) return; // We only currently do completion on the 'break' command
       
   609 
       
   610 	CompleteLineWithSymbolL(aLine, lex);
       
   611 	}
       
   612 
       
   613 void CCmdFdb::CompleteLineWithSymbolL(TConsoleLine& aLine, TLex& aLex)
       
   614 	{
       
   615 	// Have we got as far as a codeseg? We don't support completing on codeseg yet
       
   616 	TPtrC codeseg = aLex.NextToken();
       
   617 	TPtrC ext = codeseg.Right(4);
       
   618 	if (ext != _L(".dll") && ext != _L(".exe")) return;
       
   619 
       
   620 	aLex.SkipSpace();
       
   621 	TInt symbolStartPos = aLex.Offset();
       
   622 	TPtrC symbol = aLex.Remainder();
       
   623 	RLtkBuf buf;
       
   624 	buf.CreateLC(512);
       
   625 	buf.Copy(symbol);
       
   626 	CDesC16Array* suggestions = new(ELeave) CDesC16ArrayFlat(32);
       
   627 	CleanupStack::PushL(suggestions);
       
   628 	//TODO this can be slow first time, need some UI to warn the user
       
   629 	iSymbols->CompleteL(codeseg, buf, *suggestions);
       
   630 	if (buf.Length() > symbol.Length())
       
   631 		{
       
   632 		aLine.Replace(symbolStartPos, buf);
       
   633 		}
       
   634 	// If the tab added any chars we don't show choices
       
   635 	else if (suggestions->Count() > 1)
       
   636 		{
       
   637 		buf.Zero();
       
   638 		for (TInt i = 0; i < suggestions->Count(); i++)
       
   639 			{
       
   640 			if (i > 0) buf.AppendL('\t');
       
   641 			buf.AppendL((*suggestions)[i]);
       
   642 			}
       
   643 		aLine.PrintCompletionPossibilitiesL(buf);
       
   644 		}
       
   645 
       
   646 	CleanupStack::PopAndDestroy(suggestions);
       
   647 	CleanupStack::PopAndDestroy(&buf);
       
   648 	}
       
   649 
       
   650 void CCmdFdb::LeoHandleLine(const TDesC& aLine)
       
   651 	{
       
   652 	iFinishedCommand = ETrue;
       
   653 	if (aLine.Length())
       
   654 		{
       
   655 		TRAPD(err, ProcessLineL(aLine));
       
   656 		if (err)
       
   657 			{
       
   658 			PrintError(err, _L("Error executing command"));
       
   659 			}
       
   660 		}
       
   661 	}
       
   662 
       
   663 void CCmdFdb::ProcessLineL(const TDesC& aLine)
       
   664 	{
       
   665 	TLex lex(aLine);
       
   666 	TPtrC cmd = lex.NextToken();
       
   667 	lex.SkipSpace();
       
   668 
       
   669 	char ch = 0;
       
   670 	if (cmd.Length() == 1)
       
   671 		{
       
   672 		ch = cmd[0];
       
   673 		}
       
   674 
       
   675 	_LIT(KHelp, "help");
       
   676 	_LIT(KExit, "exit");
       
   677 	_LIT(KAttach, "attach");
       
   678 	_LIT(KDetach, "detach");
       
   679 	_LIT(KFocus, "focus");
       
   680 	_LIT(KRegisters, "registers");
       
   681 	_LIT(KLookup, "lookup");
       
   682 	_LIT(KStack, "stack");
       
   683 	_LIT(KKstack, "kstack");
       
   684 	_LIT(KList, "list");
       
   685 	_LIT(KMem, "mem");
       
   686 	_LIT(KUninstall, "uninstall");
       
   687 	_LIT(KBrowse, "browse");
       
   688 	_LIT(KBreak, "break");
       
   689 	_LIT(KContinue, "continue");
       
   690 	_LIT(KClear, "clear");
       
   691 	_LIT(KLoad, "load");
       
   692 	if (cmd == KHelp || ch == 'h')
       
   693 		{
       
   694 		ShowHelpTextL();
       
   695 		}
       
   696 	else if (cmd == KExit || ch == 'x')
       
   697 		{
       
   698 		iShouldExit = ETrue; // TODO check whether a detach is desired
       
   699 		}
       
   700 	else if (cmd == KUninstall || ch == 'u')
       
   701 		{
       
   702 		Printf(_L("Uninstalling thread hook, clearing all breakpoints, freeing all zombie threads. Undertakers will now get notified of the threads' exits.\r\n"));
       
   703 		iMemAccess.SetZombieDebugMode(0);
       
   704 		iShouldExit = ETrue;
       
   705 		}
       
   706 	else if (cmd == KAttach || ch == 'a')
       
   707 		{
       
   708 		TUint threadId = 0;
       
   709 		lex.Val(threadId);
       
   710 		AttachL(threadId);
       
   711 		}
       
   712 	else if (cmd == KFocus || ch == 'f')
       
   713 		{
       
   714 		TUint threadId = 0;
       
   715 		lex.Val(threadId);
       
   716 		if (threadId == 0)
       
   717 			{
       
   718 			PrintThreadInfo(CurrentL());
       
   719 			}
       
   720 		else
       
   721 			{
       
   722 			FocusL(threadId);
       
   723 			}
       
   724 		}
       
   725 	else if (cmd == KRegisters || ch == 'r')
       
   726 		{
       
   727 		PrintRegistersL(CurrentL());
       
   728 		}
       
   729 	else if (cmd == KLookup || ch == '?')
       
   730 		{
       
   731 		TUint32 addr = LtkUtils::HexLexL(lex);
       
   732 		Printf(_L("%08x: "), addr);
       
   733 		Write(LookupSymbol(addr));
       
   734 		Write(KCrLf);
       
   735 		}
       
   736 	else if (cmd == KDetach || ch == 'd')
       
   737 		{
       
   738 		TUint threadId = 0;
       
   739 		lex.Val(threadId);
       
   740 		SThreadContext* thread = NULL;
       
   741 		if (threadId == 0)
       
   742 			{
       
   743 			// No point refreshing, all it will do is possibly complain about reading the registers (which looks confusing)
       
   744 			thread = &CurrentNoRefreshL();
       
   745 			}
       
   746 		else
       
   747 			{
       
   748 			thread = ContextForThread(threadId);
       
   749 			if (!thread) LeaveIfErr(KErrNotFound, _L("Thread %u is not currently attached."), threadId);
       
   750 			}
       
   751 		Detach(thread);
       
   752 		}
       
   753 	else if (cmd == KStack || ch == 't')
       
   754 		{
       
   755 		TBool all = lex.NextToken() == _L("all");
       
   756 		SThreadContext& c = CurrentL();
       
   757 		TUint32 start = c.iKernelInfo.iUserStackLimit;
       
   758 		TUint32 end = c.iKernelInfo.UserStackBase();
       
   759 		if (start == 0)
       
   760 			{
       
   761 			Printf(_L("No user stack for this thread.\r\n"));
       
   762 			}
       
   763 		else
       
   764 			{
       
   765 			PrintRegistersLRPC(c, ETrue);
       
   766 			if ((c.iUserValidRegisters & (1 << 13)) && Rng(start, c.iUserRegisters[13], end)) start = c.iUserRegisters[13];
       
   767 			PrintMemL(c.iThread.Id(), start, end, all ? EAllData : EJustSymbols);
       
   768 			}
       
   769 		}
       
   770 	else if (cmd == KKstack || ch == 'k')
       
   771 		{
       
   772 		TBool all = lex.NextToken() == _L("all");
       
   773 		SThreadContext& c = CurrentL();
       
   774 		TUint32 start = c.iKernelInfo.iSupervisorStack;
       
   775 		TUint32 end = start + c.iKernelInfo.iSupervisorStackSize;
       
   776 		if (start == 0)
       
   777 			{
       
   778 			Printf(_L("Couldn't find kernel stack for this thread (!?).\r\n"));
       
   779 			}
       
   780 		else
       
   781 			{
       
   782 			PrintRegistersLRPC(c, EFalse);
       
   783 			if ((c.iSupervisorValidRegisters & (1 << 13)) && Rng(start, c.iSupervisorRegisters[13], end)) start = c.iSupervisorRegisters[13];
       
   784 			PrintMemL(0, start, end, all ? EAllData : EJustSymbols); // zero is the null thread, which is a kernel thread thus has the address space we're interested in
       
   785 			}
       
   786 		}
       
   787 	else if (cmd == KList || ch == 'l')
       
   788 		{
       
   789 		BrrrrrainsL();
       
   790 		}
       
   791 	else if (cmd == KMem || ch == 'm')
       
   792 		{
       
   793 		TUint32 start = LtkUtils::HexLexL(lex);
       
   794 		lex.SkipSpace();
       
   795 		TUint32 len = LtkUtils::HexLexL(lex);
       
   796 		PrintMemL(CurrentL().iThread.Id(), start, start+len, EHexDump);
       
   797 		}
       
   798 	else if (cmd == KBrowse)
       
   799 		{
       
   800 		TPtrC remainder = lex.Remainder();
       
   801 		TLinAddr addr = 0;
       
   802 		if (remainder.Length() == 0 || remainder == _L("heap"))
       
   803 			{
       
   804 			//TODO
       
   805 			}
       
   806 		else if (remainder == _L("stack"))
       
   807 			{
       
   808 			//TODO
       
   809 			}
       
   810 		else
       
   811 			{
       
   812 			addr = LtkUtils::HexLexL(lex);
       
   813 			}
       
   814 		StartInteractiveViewL(addr);
       
   815 		}
       
   816 	else if (cmd == KBreak || ch == 'b')
       
   817 		{
       
   818 		TInt res = KErrNone;
       
   819 		TBool set = ETrue;
       
   820 		TPtrC remainder = lex.Remainder();
       
   821 		if (remainder.Length() == 0)
       
   822 			{
       
   823 			ShowBreakpointsL();
       
   824 			set = EFalse;
       
   825 			}
       
   826 		else if (remainder == _L("test"))
       
   827 			{
       
   828 			// This is undocumented, for testing only
       
   829 			RThread me;
       
   830 			res = iMemAccess.SetBreakpoint(me, (TLinAddr)&LtkUtils::RawPrint);
       
   831 			LeaveIfErr(res, _L("Couldn't set test breakpoint"));
       
   832 			RThread testThread;
       
   833 			LeaveIfErr(testThread.Create(_L("BreakpointTestThread"), &BreakTest, 8192, NULL, NULL), _L("Couldn't create test thread"));
       
   834 			testThread.Resume();
       
   835 			testThread.Close();
       
   836 			}
       
   837 		else if (remainder == _L("testltk"))
       
   838 			{
       
   839 			// This is undocumented, for testing only
       
   840 			RThread testThread;
       
   841 			LeaveIfErr(testThread.Create(_L("BreakpointLtkTestThread"), &BreakTestLtk, 8192, NULL, NULL), _L("Couldn't create test thread"));
       
   842 			testThread.Resume();
       
   843 			testThread.Close();
       
   844 			set = EFalse;
       
   845 			}
       
   846 		else if (remainder == _L("testhw"))
       
   847 			{
       
   848 			// This is undocumented, for testing only
       
   849 			RThread testThread;
       
   850 			LeaveIfErr(testThread.Create(_L("BreakpointTestThread"), &BreakTest, 8192, NULL, NULL), _L("Couldn't create test thread"));
       
   851 			res = iMemAccess.SetBreakpoint(testThread, (TLinAddr)&LtkUtils::RawPrint);
       
   852 			LeaveIfErr(res, _L("Couldn't set test breakpoint"));
       
   853 			testThread.Resume();
       
   854 			testThread.Close();
       
   855 			}
       
   856 		else if (remainder == _L("testcond"))
       
   857 			{
       
   858 			// This is undocumented, for testing only
       
   859 			RThread testThread;
       
   860 			LeaveIfErr(testThread.Create(_L("BreakpointTestThread"), &BreakTestCond, 8192, NULL, NULL), _L("Couldn't create test thread"));
       
   861 			RMemoryAccess::TPredicate condition;
       
   862 			LeaveIfErr(condition.AddCondition(RMemoryAccess::TPredicate::ESignedEq, 0, (TUint)-5), _L("Couldn't add condition"));
       
   863 			res = iMemAccess.SetBreakpoint(testThread, (TLinAddr)&User::Leave, &condition);
       
   864 			LeaveIfErr(res, _L("Couldn't set test breakpoint"));
       
   865 			testThread.Resume();
       
   866 			testThread.Close();
       
   867 			}
       
   868 		else
       
   869 			{
       
   870 			TUint addr;
       
   871 			TInt err = HexLex(lex, addr);
       
   872 			if (err)
       
   873 				{
       
   874 				// Try codeseg and symbol name
       
   875 				TPtrC codeseg = lex.NextToken();
       
   876 				lex.SkipSpace();
       
   877 				TPtrC name = lex.Remainder();
       
   878 				// Hmm symbols can have spaces in, how to distinguish the condition? Assume if the last word starts with an 'r' it's a condition. Not very nice.
       
   879 				TInt space = name.LocateReverse(' ');
       
   880 				RMemoryAccess::TPredicate condition;
       
   881 				if (space >= 0 && space+1 < name.Length() && name[space+1] == 'r')
       
   882 					{
       
   883 					name.Set(name.Left(space));
       
   884 					lex.Inc(name.Length());
       
   885 					while (!lex.Eos())
       
   886 						{
       
   887 						CheckForConditionL(lex, condition);
       
   888 						}
       
   889 					}
       
   890 
       
   891 				TUint offset = 0;
       
   892 				TRAPL(offset = iSymbols->CodesegOffsetFromSymbolNameL(codeseg, name), _L("Couldn't find offset of symbol '%S' in codeseg '%S'"), &name, &codeseg);
       
   893 				RLtkBuf8 codeseg8;
       
   894 				CleanupClosePushL(codeseg8);
       
   895 				codeseg8.AppendL(codeseg);
       
   896 				res = iMemAccess.SetSymbolicBreakpoint(CurrentL().iThread, codeseg8, offset, &condition);
       
   897 				LeaveIfErr(res, _L("Couldn't create symbolic breakpoint"));
       
   898 				CleanupStack::PopAndDestroy(&codeseg8);
       
   899 				}
       
   900 			else
       
   901 				{
       
   902 				RMemoryAccess::TPredicate condition;
       
   903 				while (!lex.Eos())
       
   904 					{
       
   905 					CheckForConditionL(lex, condition);
       
   906 					}
       
   907 				res = iMemAccess.SetBreakpoint(CurrentL().iThread, addr, &condition);
       
   908 				LeaveIfErr(res, _L("Couldn't create breakpoint"));
       
   909 				Printf(_L("Breakpoint created at 0x%08x "), addr);
       
   910 				Write(LookupSymbol(addr));
       
   911 				Write(KCrLf);
       
   912 				}
       
   913 			}
       
   914 
       
   915 		if (set)
       
   916 			{
       
   917 			if (res & RMemoryAccess::TBreakpointInfo::EHardware)
       
   918 				{
       
   919 				Printf(_L("Hardware breakpoint %d set.\r\n"), res & ~RMemoryAccess::TBreakpointInfo::EHardware);
       
   920 				}
       
   921 			else if (res == 0)
       
   922 				{
       
   923 				Printf(_L("Pending breakpoint set (Note these don't work yet!)\r\n"));
       
   924 				}
       
   925 			else
       
   926 				{
       
   927 				Printf(_L("Breakpoint %d set.\r\n"), res);
       
   928 				}
       
   929 			}
       
   930 		}
       
   931 	else if (cmd == KContinue || ch =='c')
       
   932 		{
       
   933 		TInt err = iMemAccess.ContinueFromBreakpoint(CurrentL().iThread);
       
   934 		LeaveIfErr(err, _L("Couldn't continue - is the thread definitely stopped on a breakpoint?"));
       
   935 		}
       
   936 	else if (cmd == KClear)
       
   937 		{
       
   938 		TPtrC remainder = lex.Remainder();
       
   939 		if (remainder.Length() == 0)
       
   940 			{
       
   941 			ClearAllBreakpointsL();
       
   942 			}
       
   943 		else
       
   944 			{
       
   945 			TInt n;
       
   946 			User::LeaveIfError(lex.Val(n));
       
   947 			LeaveIfErr(iMemAccess.ClearBreakpoint(n), _L("Couldn't clear breakpoint %d"), n);
       
   948 			}
       
   949 		}
       
   950 	else if (cmd == KLoad)
       
   951 		{
       
   952 		TPtrC path = lex.Remainder();
       
   953 		if (path.Right(5).CompareF(_L(".bsym")) == 0)
       
   954 			{
       
   955 			//Printf(_L("Loading symbolics... ")); // It can take a while...
       
   956 			iSymbols->AddBsymFileL(path);
       
   957 			//Printf(_L("done.\r\n"));
       
   958 			}
       
   959 		else
       
   960 			{
       
   961 			iSymbols->SetFallbackMapFileDirL(path);
       
   962 			}
       
   963 		}
       
   964 	else
       
   965 		{
       
   966 		PrintError(KErrNotFound, _L("Unrecognised command '%S'. Try 'help'."), &cmd);
       
   967 		}
       
   968 	}
       
   969 
       
   970 CCmdFdb::SThreadContext* CCmdFdb::ContextForThread(TUint aThreadId) const
       
   971 	{
       
   972 	for (TInt i = 0; i < iThreads.Count(); i++)
       
   973 		{
       
   974 		if ((TUint)iThreads[i]->iThread.Id() == aThreadId)
       
   975 			{
       
   976 			return iThreads[i];
       
   977 			}
       
   978 		}
       
   979 	return NULL;
       
   980 	}
       
   981 
       
   982 CCmdFdb::SThreadContext& CCmdFdb::CurrentL()
       
   983 	{
       
   984 	CCmdFdb::SThreadContext& current = CurrentNoRefreshL();
       
   985 	RefreshIfRunningL(current);
       
   986 	return current;
       
   987 	}
       
   988 
       
   989 CCmdFdb::SThreadContext& CCmdFdb::CurrentNoRefreshL()
       
   990 	{
       
   991 	if (!iCurrent)
       
   992 		{
       
   993 		LeaveIfErr(KErrNotReady, _L("No currently focussed thread"));
       
   994 		}
       
   995 	return *iCurrent;
       
   996 	}
       
   997 
       
   998 void CCmdFdb::FocusL(TUint aThreadId)
       
   999 	{
       
  1000 	SThreadContext* c = ContextForThread(aThreadId);
       
  1001 	if (c) iCurrent = c;
       
  1002 	else
       
  1003 		{
       
  1004 		LeaveIfErr(KErrNotFound, _L("Couldn't find thread id %u in the attached threads. Do you need to do 'attach %u'?"), aThreadId, aThreadId);
       
  1005 		}
       
  1006 	}
       
  1007 
       
  1008 void CCmdFdb::Detach(SThreadContext* aContext)
       
  1009 	{
       
  1010 	TInt err = iMemAccess.ReleaseZombie(aContext->iThread);
       
  1011 	if (err && aContext->iFlags.IsSet(SThreadContext::ERunning))
       
  1012 		{
       
  1013 		// Don't complain about driver if the thread wasn't actually zombied
       
  1014 		PrintError(err, _L("Driver couldn't find zombie thread"));
       
  1015 		}
       
  1016 
       
  1017 	TInt arrayPos = iThreads.Find(aContext);
       
  1018 	iThreads.Remove(arrayPos);
       
  1019 	if (iCurrent == aContext) iCurrent = NULL;
       
  1020 	aContext->iThread.Close();
       
  1021 	delete aContext;
       
  1022 	}
       
  1023 
       
  1024 void CCmdFdb::PrintMemL(TUint aThreadId, TUint32 aStart, TUint32 aEnd, TPrintMode aMode)
       
  1025 	{
       
  1026 	// word-align start and end
       
  1027 	aStart &= ~3;
       
  1028 	aEnd = (aEnd+3) & (~3);
       
  1029 
       
  1030 	TInt size = aEnd - aStart;
       
  1031 	RBuf8 mem;
       
  1032 	CleanupClosePushL(mem);
       
  1033 	mem.CreateL(size);
       
  1034 
       
  1035 	TThreadMemoryAccessParamsBuf params;
       
  1036 	params().iId = aThreadId;
       
  1037 	params().iAddr = (TUint8*)aStart;
       
  1038 	params().iSize = size;
       
  1039 
       
  1040 	TInt err = iMemAccess.GetThreadMem(params, mem);
       
  1041 	LeaveIfErr(err, _L("Couldn't read thread memory %08x-%08x"), aStart, aEnd);
       
  1042 
       
  1043 	if (aMode == EHexDump)
       
  1044 		{
       
  1045 		TInt offset = (TInt)aStart;
       
  1046 		LtkUtils::HexDumpToOutput(mem, Stdout(), offset);
       
  1047 		}
       
  1048 	else
       
  1049 		{
       
  1050 		const TUint32* ptr = (const TUint32*)mem.Ptr();
       
  1051 		const TInt count = mem.Size() / 4;
       
  1052 		for (TInt i = 0; i < count; i++)
       
  1053 			{
       
  1054 			TUint32 word = ptr[i];
       
  1055 			TBool print = aMode == EAllData || IsSymbol(word);
       
  1056 			if (print)
       
  1057 				{
       
  1058 				Printf(_L("%08x: %08x "), aStart + i*4, word);
       
  1059 				Write(LookupSymbol(word));
       
  1060 				Write(KCrLf);
       
  1061 				}
       
  1062 			}
       
  1063 		}
       
  1064 	CleanupStack::PopAndDestroy(&mem);
       
  1065 	}
       
  1066 
       
  1067 void CCmdFdb::BrrrrrainsL()
       
  1068 	{
       
  1069 	RBuf8 buf;
       
  1070 	CleanupClosePushL(buf);
       
  1071 	buf.CreateL(1024);
       
  1072 	TInt res = iMemAccess.GetZombies(buf);
       
  1073 	LeaveIfErr(res, _L("Couldn't get zombie info from driver"));
       
  1074 	RMemoryAccess::TZombieInfo* ptr = (RMemoryAccess::TZombieInfo*)buf.Ptr();
       
  1075 	const TInt zombiecount = buf.Length()/sizeof(RMemoryAccess::TZombieInfo);
       
  1076 
       
  1077 	// Go through all the zombies
       
  1078 	for (TInt i = 0; i < zombiecount; i++)
       
  1079 		{
       
  1080 		TUint id = ptr[i].iThreadId;
       
  1081 		SThreadContext* context = ContextForThread(id);
       
  1082 		char stat = '-';
       
  1083 		char suspended = '-';
       
  1084 		if (context)
       
  1085 			{
       
  1086 			stat = 'a';
       
  1087 			if (context == iCurrent) stat = '*';
       
  1088 			iTempNameBuf = context->iThread.FullName();
       
  1089 			}
       
  1090 		else
       
  1091 			{
       
  1092 			RThread thread;
       
  1093 			TInt err = iMemAccess.RThreadForceOpen(thread, id);
       
  1094 			if (err)
       
  1095 				{
       
  1096 				PrintWarning(_L("Couldn't open thread %u"), id);
       
  1097 				continue;
       
  1098 				}
       
  1099 			iTempNameBuf = thread.FullName();
       
  1100 			thread.Close();
       
  1101 			}
       
  1102 		if (ptr[i].iFlags & RMemoryAccess::TZombieInfo::ESuspended) suspended = 's';
       
  1103 		if (ptr[i].iFlags & RMemoryAccess::TZombieInfo::EBreakpoint) suspended = 'b';
       
  1104 
       
  1105 		Printf(_L("%c%c %u "), stat, suspended, id);
       
  1106 		Write(iTempNameBuf);
       
  1107 		Write(KCrLf);
       
  1108 		}
       
  1109 
       
  1110 	// Now do any attached threads that aren't zombied
       
  1111 	for (TInt i = 0; i < iThreads.Count(); i++)
       
  1112 		{
       
  1113 		SThreadContext* c = iThreads[i];
       
  1114 		TUint id = (TUint)c->iThread.Id();
       
  1115 		RMemoryAccess::TZombieInfo dummy; dummy.iThreadId = id;
       
  1116 		TBool foundInZombies = EFalse;
       
  1117 		if (zombiecount) foundInZombies = RArray<RMemoryAccess::TZombieInfo>(sizeof(RMemoryAccess::TZombieInfo), ptr, zombiecount).Find(dummy) != KErrNotFound;
       
  1118 		if (!foundInZombies)
       
  1119 			{
       
  1120 			char stat = 'a';
       
  1121 			if (c == iCurrent) stat = '*';
       
  1122 			iTempNameBuf = c->iThread.FullName();
       
  1123 			Printf(_L("%c- %u "), stat, id);
       
  1124 			Write(iTempNameBuf);
       
  1125 			Write(KCrLf);
       
  1126 			}
       
  1127 		}
       
  1128 
       
  1129 	CleanupStack::PopAndDestroy(&buf);
       
  1130 	}
       
  1131 
       
  1132 void CCmdFdb::ShowHelpTextL()
       
  1133 	{
       
  1134 	// Possible TODOs: hEap, Save, Ymodem?
       
  1135 	_LIT(KStartOfCommands, "SUPPORTED COMMANDS\r\n\r\n");
       
  1136 	CTextBuffer* helpText = const_cast<CTextBuffer*>(GetHelpTextL());
       
  1137 	TInt found = helpText->Descriptor().Find(KStartOfCommands);
       
  1138 	helpText->Delete(0, found + KStartOfCommands().Length());
       
  1139 	helpText->Write(Stdout());
       
  1140 	delete helpText;
       
  1141 	}
       
  1142 
       
  1143 TBool CCmdFdb::IsSymbol(TUint aAddress) const
       
  1144 	{
       
  1145 	// Ranges probably not perfect, seem to be roughly ok though
       
  1146 	TBool okRange = Rng(0x70000000u, aAddress, 0xA0000000u) || Rng(0xC0000000u, aAddress, 0xFC000000u);
       
  1147 	return okRange && aAddress != 0xDEDEDEDE && aAddress != 0xAAAAAAAA && aAddress != 0xBBBBBBBB && aAddress != 0xCCCCCCCC; 
       
  1148 	}
       
  1149 
       
  1150 void CCmdFdb::StartInteractiveViewL(TLinAddr aAddress)
       
  1151 	{
       
  1152 	iMemStart = aAddress & (~3);
       
  1153 	if (iMemStart >= iCurrent->iKernelInfo.iUserStackLimit && iMemStart <= iCurrent->iKernelInfo.UserStackBase())
       
  1154 		{
       
  1155 		iMemoryViewType = EStack;
       
  1156 		}
       
  1157 	else //TODO EHeap
       
  1158 		{
       
  1159 		iMemoryViewType = EUnspecified;
       
  1160 		}
       
  1161 
       
  1162 	iMemBuf.Zero();
       
  1163 	TSize consoleSize(80,24);
       
  1164 	Stdout().GetScreenSize(consoleSize);
       
  1165 	iMemBuf.ReAllocL(consoleSize.iHeight * 16); // At most we display 16 bytes per line
       
  1166 	TInt numBytesOnLine = 16; // By default
       
  1167 	if (iMemoryViewType == EStack) numBytesOnLine = 4;
       
  1168 	TInt numBytesOnScreen = numBytesOnLine * consoleSize.iHeight;
       
  1169 
       
  1170 	TLinAddr lastAddr = 0;
       
  1171 	for (;;)
       
  1172 		{
       
  1173 		iMemStart &= ~3; // Just checking
       
  1174 		TBool update = (iMemStart != lastAddr);
       
  1175 		lastAddr = iMemStart;
       
  1176 		DrawMemViewL(update);
       
  1177 		TUint key = Stdin().ReadKey();
       
  1178 		switch (key)
       
  1179 			{
       
  1180 			case EKeyPageUp:
       
  1181 				iMemStart -= numBytesOnScreen;
       
  1182 				break;
       
  1183 			case EKeyPageDown:
       
  1184 				iMemStart += numBytesOnScreen;
       
  1185 				break;
       
  1186 			case EKeyUpArrow:
       
  1187 				iMemStart -= numBytesOnLine;
       
  1188 				break;
       
  1189 			case EKeyDownArrow:
       
  1190 				iMemStart += numBytesOnLine;
       
  1191 				break;
       
  1192 			case 'q':
       
  1193 			case 'x':
       
  1194 			case EKeyEscape:
       
  1195 				//Stdout().SetAttributesL(ConsoleAttributes::ENone);
       
  1196 				return;
       
  1197 			default:
       
  1198 				break;
       
  1199 			}
       
  1200 		}
       
  1201 	}
       
  1202 
       
  1203 void CCmdFdb::UpdateMemForMemViewL()
       
  1204 	{
       
  1205 	iMemBuf.Zero();
       
  1206 	
       
  1207 	TThreadMemoryAccessParamsBuf params;
       
  1208 	params().iId = iCurrent->iThread.Id();
       
  1209 	params().iAddr = (TUint8*)iMemStart;
       
  1210 	params().iSize = iMemBuf.MaxSize();
       
  1211 
       
  1212 	TInt err = iMemAccess.GetThreadMem(params, iMemBuf);
       
  1213 	if (err) PrintError(err, _L("Couldn't read thread memory %08x-%08x"), params().iAddr, params().iAddr+params().iSize);
       
  1214 	}
       
  1215 
       
  1216 /*
       
  1217 class TFocusable
       
  1218 	{
       
  1219 public:
       
  1220 	TLinAddr iAddr;
       
  1221 	enum TType
       
  1222 		{
       
  1223 		EHeapPtr,
       
  1224 		}
       
  1225 	}
       
  1226 */
       
  1227 
       
  1228 void CCmdFdb::DrawMemViewL(TBool aUpdate)
       
  1229 	{
       
  1230 	Stdout().ClearScreen();
       
  1231 	if (aUpdate) UpdateMemForMemViewL();
       
  1232 
       
  1233 
       
  1234 	// This is a really messy function. Can't seem to find a way of making it easier to read.
       
  1235 	const ConsoleAttributes::TAttributes KNormal(ConsoleAttributes::ENone, ConsoleAttributes::EBlack, ConsoleAttributes::EWhite);
       
  1236 	const ConsoleAttributes::TAttributes KSymbol(0, ConsoleAttributes::ERed, ConsoleAttributes::EUnchanged);
       
  1237 	const ConsoleAttributes::TAttributes KDescriptor(0, ConsoleAttributes::EUnchanged, ConsoleAttributes::EYellow);
       
  1238 	//const ConsoleAttributes::TAttributes KHeap(0, ConsoleAttributes::EUnchanged, ConsoleAttributes::ECyan);
       
  1239 	//const ConsoleAttributes::TAttributes KHeapAlternate(0, ConsoleAttributes::EUnchanged, ConsoleAttributes::EBlue);
       
  1240 	enum { ENoColor = 0, ESymbol = 1, EDescriptor = 2 };
       
  1241 
       
  1242 	TSize consoleSize(80,24);
       
  1243 	Stdout().GetScreenSize(consoleSize);
       
  1244 	TUint8 const*const bptr = iMemBuf.Ptr();
       
  1245 	TUint32 const*const ptr = (TUint32 const*)bptr;
       
  1246 	//iLinks.Reset();
       
  1247 	CTextBuffer* text = CTextBuffer::NewLC(1024);
       
  1248 	text->SetAttributesL(KNormal);
       
  1249 	
       
  1250 	TInt numBytesOnLine = 16; // By default
       
  1251 	if (iMemoryViewType == EStack)
       
  1252 		{
       
  1253 		numBytesOnLine = 4;
       
  1254 		}
       
  1255 	//TInt numBytesOnScreen = numBytesOnLine * consoleSize.iHeight;
       
  1256 	TInt remainingInDescriptor = 0; // Not in descriptor initially
       
  1257 	//TInt remainingInHeapCell = 0; // Not worrying about heap cells right now
       
  1258 
       
  1259 	for (TInt line = 0; line < consoleSize.iHeight - 1 && line*numBytesOnLine < iMemBuf.Length(); line++)
       
  1260 		{
       
  1261 		TBuf8<16> colorBuf; colorBuf.SetLength(colorBuf.MaxLength());
       
  1262 		TUint8* colorBufPtr = (TUint8*)colorBuf.Ptr();
       
  1263 		Mem::Fill(colorBufPtr, 16, ENoColor);
       
  1264 		text->AppendFormatL(_L("%08x: "), iMemStart + line*numBytesOnLine);
       
  1265 
       
  1266 		const TInt idxForLine = line * numBytesOnLine;
       
  1267 		TInt i;
       
  1268 		for (i = 0; i < numBytesOnLine; i += 4, colorBufPtr += 4)
       
  1269 			{
       
  1270 			const TInt idxInBuf = idxForLine + i;
       
  1271 			if (idxInBuf >= iMemBuf.Length()) break;
       
  1272 
       
  1273 			if (remainingInDescriptor == 0) remainingInDescriptor = IsDescriptorHeader(bptr + idxInBuf, 256);
       
  1274 			TInt runLen = 0;
       
  1275 			if (remainingInDescriptor > 0)
       
  1276 				{
       
  1277 				text->SetAttributesL(KDescriptor);
       
  1278 				runLen = Min(remainingInDescriptor, numBytesOnLine-i);
       
  1279 				if (runLen > 4) runLen = 4; // We only do up to 4 bytes at a time
       
  1280 				Mem::Fill(colorBufPtr, runLen, EDescriptor);
       
  1281 				}
       
  1282 
       
  1283 			// Check for symbols
       
  1284 			TUint32 word = ptr[idxInBuf / 4];
       
  1285 			if (IsSymbol(word))
       
  1286 				{
       
  1287 				text->SetAttributesL(KSymbol);
       
  1288 				colorBufPtr[0] |= ESymbol;
       
  1289 				colorBufPtr[1] |= ESymbol;
       
  1290 				colorBufPtr[2] |= ESymbol;
       
  1291 				colorBufPtr[3] |= ESymbol;
       
  1292 				if (iMemoryViewType == EStack)
       
  1293 					{
       
  1294 					TPtrC symb = LookupSymbol(word);
       
  1295 					text->AppendFormatL(_L("%08x %S"), word, &symb);
       
  1296 					text->SetAttributesL(KNormal);
       
  1297 					text->AppendL(KCrLf);
       
  1298 					continue;
       
  1299 					}
       
  1300 				}
       
  1301 
       
  1302 			// Actually print the hex bytes
       
  1303 			for (TInt ch = 0; ch < 4; ch++)
       
  1304 				{
       
  1305 				text->AppendFormatL(_L("%02X"), bptr[idxInBuf+ch]);
       
  1306 				if (runLen)
       
  1307 					{
       
  1308 					remainingInDescriptor--;
       
  1309 					runLen--;
       
  1310 					if (remainingInDescriptor == 0)	text->SetAttributesL(KNormal); // If we've just finished a run we clear the formatting before the space
       
  1311 					}
       
  1312 				text->AppendL(' ');
       
  1313 				}
       
  1314 			if (((i+4) % 16) == 0) text->SetAttributesL(KNormal); // In preparation for printing the ascii
       
  1315 			if (((i+4) % 8) == 0) text->AppendL(' '); // Extra space every 8th char
       
  1316 			}
       
  1317 
       
  1318 		TInt rem = numBytesOnLine - i;
       
  1319 		if (rem > 0)
       
  1320 			{
       
  1321 			// Need to fill in spaces for the hex bytes we don't have
       
  1322 			_LIT(K3Space, "   ");
       
  1323 			while (rem--) text->AppendL(K3Space);
       
  1324 			// And the final 2 spaces before the ascii
       
  1325 			text->AppendL(' ');
       
  1326 			text->AppendL(' ');
       
  1327 			}
       
  1328 
       
  1329 
       
  1330 		// Time to print the ascii
       
  1331 		const TInt max = Min(numBytesOnLine, iMemBuf.Length() - idxForLine);
       
  1332 		for (TInt j = 0; j < max; j++)
       
  1333 			{
       
  1334 			char ch = bptr[idxForLine + j];
       
  1335 			if (ch < 32 || ch >= 128) ch = '.';
       
  1336 			text->SetAttributesL(KNormal);
       
  1337 			if (colorBuf[j] & EDescriptor) text->SetAttributesL(KDescriptor);
       
  1338 			if (colorBuf[j] & ESymbol) text->SetAttributesL(KSymbol);
       
  1339 			text->AppendL(ch);
       
  1340 			}
       
  1341 		text->SetAttributesL(KNormal);
       
  1342 		text->AppendL(KCrLf);
       
  1343 		}
       
  1344 
       
  1345 	text->SetAttributesL(ConsoleAttributes::ENone);
       
  1346 	text->Write(Stdout());
       
  1347 	CleanupStack::PopAndDestroy(text);
       
  1348 	}
       
  1349 
       
  1350 /*static*/ TInt CCmdFdb::IsDescriptorHeader(TUint8 const* aHeaderPtr, TInt aMaxLen)
       
  1351 	{
       
  1352 	if (((TLinAddr)aHeaderPtr & 0x3) != 0) return 0; // Not aligned
       
  1353 	TInt type = *(TUint32*)aHeaderPtr >> 28;
       
  1354 
       
  1355 	if ((type == EPtr || type == EBufCPtr) && aMaxLen >= 12) return 12; // Len + maxlen + ptr
       
  1356 	else if (type == EPtrC && aMaxLen >= 8) return 8; // Len + ptr
       
  1357 	else if (type == EBuf || type == EBufC)
       
  1358 		{
       
  1359 		TInt len = (*(TInt32 const*)aHeaderPtr) & 0xfffffff;
       
  1360 		if (len > aMaxLen || (type == 0 && len == 0)) return 0;
       
  1361 		// Take a stab at whether it's a 16-bit descriptor
       
  1362 		TInt wideness = 1;
       
  1363 		TInt bufOffset = (type == EBuf ? 8 : 4);
       
  1364 		TUint16 const* wptr = (TUint16 const*)(aHeaderPtr + bufOffset);
       
  1365 		if (len > 4 && wptr[0] < 256 && wptr[1] < 256) wideness = 2;
       
  1366 		return bufOffset + len * wideness; // Add 4 so the header itself is included in the calculation
       
  1367 		}
       
  1368 	else
       
  1369 		{
       
  1370 		return 0;
       
  1371 		}
       
  1372 	}
       
  1373 
       
  1374 void CCmdFdb::ShowBreakpointsL()
       
  1375 	{
       
  1376 	RBuf8 buf;
       
  1377 	CleanupClosePushL(buf);
       
  1378 	buf.CreateL(1024);
       
  1379 	LeaveIfErr(iMemAccess.GetBreakpoints(buf), _L("Couldn't read breakpoint information"));
       
  1380 	RMemoryAccess::TBreakpointInfo* bs = (RMemoryAccess::TBreakpointInfo*)buf.Ptr();
       
  1381 	RLtkBuf desc;
       
  1382 	desc.CreateL(256);
       
  1383 	TInt count = buf.Length() / sizeof(RMemoryAccess::TBreakpointInfo);
       
  1384 	if (count)
       
  1385 		{
       
  1386 		for (TInt i = 0; i < count; i++)
       
  1387 			{
       
  1388 			RMemoryAccess::TBreakpointInfo& b = bs[i];
       
  1389 			Printf(_L("Breakpoint %d (thread id %u): "), b.iBreakpointId, b.iThreadId);
       
  1390 			Write(LookupSymbol(b.iAddress));
       
  1391 			TBool brackets = b.iFlags & (RMemoryAccess::TBreakpointInfo::EPending | b.iFlags & RMemoryAccess::TBreakpointInfo::EHardware) || !(b.iFlags & RMemoryAccess::TBreakpointInfo::EEnabled) || b.iCondition.HasConditions();
       
  1392 			if (brackets) Write(_L(" ("));
       
  1393 			desc.Zero();
       
  1394 			if (b.iFlags & RMemoryAccess::TBreakpointInfo::EPending) desc.Append(_L("PENDING "));
       
  1395 			if (!(b.iFlags & RMemoryAccess::TBreakpointInfo::EEnabled)) desc.Append(_L("DISABLED "));
       
  1396 			if (b.iFlags & RMemoryAccess::TBreakpointInfo::EHardware) desc.Append(_L("HARDWARE "));
       
  1397 			b.iCondition.Description(desc);
       
  1398 			if (desc.Length() && desc[desc.Length()-1] == ' ') desc.SetLength(desc.Length()-1);
       
  1399 			Write(desc);
       
  1400 			if (brackets) Write(_L(")"));
       
  1401 			Write(KCrLf);
       
  1402 			}
       
  1403 		}
       
  1404 	else
       
  1405 		{
       
  1406 		Printf(_L("No breakpoints defined.\r\n"));
       
  1407 		}
       
  1408 	CleanupStack::PopAndDestroy(&buf);
       
  1409 	}
       
  1410 
       
  1411 void CCmdFdb::CBreakpointNotifier::RunL()
       
  1412 	{
       
  1413 	if (iStatus.Int() < 0)
       
  1414 		{
       
  1415 		iCmd.PrintError(iStatus.Int(), _L("Error returned from NotifyBreakpoint"));
       
  1416 		return;
       
  1417 		}
       
  1418 	
       
  1419 	RMemoryAccess::TBreakpointNotification notif = iCmd.iBreakpointNotification;
       
  1420 	iCmd.iMemAccess.NotifyBreakpoint(iCmd.iBreakpointNotificationPkg, iStatus);
       
  1421 	SetActive();
       
  1422 
       
  1423 	iCmd.BreakpointHit(notif);
       
  1424 	}
       
  1425 
       
  1426 void CCmdFdb::CBreakpointNotifier::DoCancel()
       
  1427 	{
       
  1428 	iCmd.iMemAccess.CancelNotifyBreakpoint();
       
  1429 	}
       
  1430 
       
  1431 CCmdFdb::CBreakpointNotifier::CBreakpointNotifier(CCmdFdb& aCmd)
       
  1432 : CActive(CActive::EPriorityStandard), iCmd(aCmd)
       
  1433 	{
       
  1434 	CActiveScheduler::Add(this);
       
  1435 	iCmd.iMemAccess.NotifyBreakpoint(iCmd.iBreakpointNotificationPkg, iStatus);
       
  1436 	SetActive();
       
  1437 	}
       
  1438 
       
  1439 CCmdFdb::CBreakpointNotifier::~CBreakpointNotifier()
       
  1440 	{
       
  1441 	Cancel();
       
  1442 	}
       
  1443 
       
  1444 void CCmdFdb::BreakpointHit(const RMemoryAccess::TBreakpointNotification& aNotif)
       
  1445 	{
       
  1446 	iLineEditor->RemovePromptAndUserInput();
       
  1447 	Printf(_L("Breakpoint %d hit in thread %u: "), aNotif.iBreakpointId, aNotif.iThreadId);
       
  1448 	Write(LookupSymbol(aNotif.iAddress));
       
  1449 	Write(KCrLf);
       
  1450 	if (iCurrent == NULL)
       
  1451 		{
       
  1452 		Printf(_L("(Attaching to thread %u)\r\n"), aNotif.iThreadId);
       
  1453 		TRAP_IGNORE(AttachL(aNotif.iThreadId));
       
  1454 		}
       
  1455 	iLineEditor->ReinstatePromptAndUserInput();
       
  1456 	}
       
  1457 
       
  1458 TInt CCmdFdb::BreakTest(TAny* /*aPtr*/)
       
  1459 	{
       
  1460 	//LtkUtils::Breakpoint();
       
  1461 	LtkUtils::RawPrint(_L8("Breaktest has completed\r\n"));
       
  1462 	return 5;
       
  1463 	}
       
  1464 
       
  1465 TInt CCmdFdb::BreakTestLtk(TAny* /*aPtr*/)
       
  1466 	{
       
  1467 	LtkUtils::Breakpoint();
       
  1468 	return 6;
       
  1469 	}
       
  1470 
       
  1471 TInt CCmdFdb::BreakTestCond(TAny* /*aPtr*/)
       
  1472 	{
       
  1473 	CTrapCleanup* trap = CTrapCleanup::New();
       
  1474 	TRAPD(err, User::Leave(-1)); // This shouldn't trigger the break
       
  1475 	TRAP(err, User::Leave(-5)); // This should
       
  1476 	delete trap;
       
  1477 	return 0;
       
  1478 	}
       
  1479 
       
  1480 void CCmdFdb::ClearAllBreakpointsL()
       
  1481 	{
       
  1482 	RBuf8 buf;
       
  1483 	CleanupClosePushL(buf);
       
  1484 	buf.CreateL(1024);
       
  1485 	LeaveIfErr(iMemAccess.GetBreakpoints(buf), _L("Couldn't read breakpoint information"));
       
  1486 	RMemoryAccess::TBreakpointInfo* bs = (RMemoryAccess::TBreakpointInfo*)buf.Ptr();
       
  1487 	TInt count = buf.Length() / sizeof(RMemoryAccess::TBreakpointInfo);
       
  1488 	for (TInt i = 0; i < count; i++)
       
  1489 		{
       
  1490 		RMemoryAccess::TBreakpointInfo& b = bs[i];
       
  1491 		TInt err = iMemAccess.ClearBreakpoint(b.iBreakpointId);
       
  1492 		if (err) PrintWarning(_L("Couldn't clear breakpoint %d, err=%d"), b.iBreakpointId, err);
       
  1493 		}
       
  1494 	CleanupStack::PopAndDestroy(&buf);
       
  1495 	}
       
  1496 
       
  1497 void CCmdFdb::CheckForConditionL(TLex& aLex, RMemoryAccess::TPredicate& aCondition)
       
  1498 	{
       
  1499 	aLex.SkipSpace();
       
  1500 	if (aLex.Eos()) return;
       
  1501 	_LIT(KRegErr, "First argument in a conditional must be a register r0-r15");
       
  1502 	if (aLex.Get() != 'r') LeaveIfErr(KErrArgument, KRegErr);
       
  1503 	TInt reg;
       
  1504 	LeaveIfErr(aLex.Val(reg), KRegErr);
       
  1505 	if (reg < 0 || reg > 15) LeaveIfErr(KErrArgument, KRegErr);
       
  1506 	RMemoryAccess::TPredicate::TOp op = RMemoryAccess::TPredicate::ENothing;
       
  1507 	TUint opchar = aLex.Get();
       
  1508 	switch (opchar)
       
  1509 		{
       
  1510 		case '<':
       
  1511 			op = RMemoryAccess::TPredicate::ELt;
       
  1512 			if (aLex.Peek() == '=')
       
  1513 				{
       
  1514 				op = RMemoryAccess::TPredicate::ELe;
       
  1515 				aLex.Get();
       
  1516 				}
       
  1517 			break;
       
  1518 		case '>':
       
  1519 			op = RMemoryAccess::TPredicate::EGt;
       
  1520 			if (aLex.Peek() == '=')
       
  1521 				{
       
  1522 				op = RMemoryAccess::TPredicate::EGe;
       
  1523 				aLex.Get();
       
  1524 				}
       
  1525 			break;
       
  1526 		case '!':
       
  1527 			if (aLex.Get() != '=') LeaveIfErr(KErrArgument, _L("Unrecognised operand"));
       
  1528 			op = RMemoryAccess::TPredicate::ENe;
       
  1529 			break;
       
  1530 		case '=':
       
  1531 			op = RMemoryAccess::TPredicate::EEq;
       
  1532 			if (aLex.Peek() == '=') aLex.Get(); // We allow == as well as =
       
  1533 			break;
       
  1534 		default:
       
  1535 			LeaveIfErr(KErrArgument, _L("Unrecognised operand"));
       
  1536 			break;
       
  1537 		}
       
  1538 	TInt val;
       
  1539 	TInt err = LtkUtils::HexLex(aLex, (TUint&)val);
       
  1540 	if (err)
       
  1541 		{
       
  1542 		// Try normal - this handles signed negative numbers, which HexLex doesn't afaik
       
  1543 		err = aLex.Val(val);
       
  1544 		}
       
  1545 	LeaveIfErr(err, _L("Couldn't parse value"));
       
  1546 	TBool signedCompare = ETrue;
       
  1547 	if (aLex.Peek() == 'u' || aLex.Peek() == 'U')
       
  1548 		{
       
  1549 		aLex.Get();
       
  1550 		signedCompare = EFalse;
       
  1551 		}
       
  1552 	if (signedCompare)
       
  1553 		{
       
  1554 		op = (RMemoryAccess::TPredicate::TOp)(op + 6); // ELt -> ESignedLt etc
       
  1555 		//Printf(_L("Op=%d reg=%d val=%d\r\n"), op, reg, val);
       
  1556 		}
       
  1557 	//else Printf(_L("Op=%d reg=%d val=%uu\r\n"), op, reg, (TUint)val);
       
  1558 	if (aLex.Peek() == ',')
       
  1559 		{
       
  1560 		// Eat comma
       
  1561 		aLex.Get();
       
  1562 		}
       
  1563 	LeaveIfErr(aCondition.AddCondition(op, reg, (TUint32)val), _L("Couldn't add condition to TPredicate"));
       
  1564 	}