libraries/memoryaccess/fdebuggerkernel.cpp
changeset 0 7f656887cf89
child 9 257450419d10
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // fdebuggerkernel.cpp
       
     2 // 
       
     3 // Copyright (c) 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 #include "fdebuggerkernel.h"
       
    13 #include "DynamicDfcSupport.h"
       
    14 #ifdef __MARM__
       
    15 #	include <arm/arm.h>
       
    16 #	if defined(FSHELL_ARM11XX_SUPPORT) || defined(FSHELL_ARM_MEM_MAPPED_DEBUG)
       
    17 //#		ifndef __MEMMODEL_MULTIPLE__
       
    18 //#			error "FSHELL_ARM11XX_SUPPORT is only supported on platforms using the multiple memory model!"
       
    19 //#		endif
       
    20 #	include <multiple/memmodel.h>
       
    21 #	endif
       
    22 #endif
       
    23 #include "memoryaccess.h"
       
    24 
       
    25 #if !defined(__EABI__) && defined(FSHELL_ARM_MEM_MAPPED_DEBUG)
       
    26 #undef FSHELL_ARM_MEM_MAPPED_DEBUG
       
    27 #endif
       
    28 
       
    29 #ifdef ASSERT
       
    30 #undef ASSERT
       
    31 #endif
       
    32 #ifdef __WINS__
       
    33 #define ASSERT(x) __ASSERT_ALWAYS((x), Kern::Fault("Assertion failed: " #x, __LINE__))
       
    34 #else
       
    35 #define ASSERT(x) if (!(x)) { Kern::Printf("Assertion failed @ %d: " #x, __LINE__); NKern::Sleep(NKern::TimerTicks(5000)); }
       
    36 #endif
       
    37 
       
    38 #define ASSERT_LOCKED() ASSERT(Kern::CurrentThread().iNThread.iHeldFastMutex == &iLock)
       
    39 #define ASSERT_UNLOCKED() ASSERT(Kern::CurrentThread().iNThread.iHeldFastMutex == NULL)
       
    40 #define ASSERT_BREAKPOINT_LOCKED() ASSERT(iBreakpointMutex->iCleanup.iThread == &Kern::CurrentThread());
       
    41 #define ASSERT_BREAKPOINT_UNLOCKED() ASSERT(iBreakpointMutex->iCleanup.iThread != &Kern::CurrentThread());
       
    42 
       
    43 //#define LOG(args...) Kern::Printf(args)
       
    44 #define LOG(args...)
       
    45 
       
    46 void MCR_SetContextIdBrp(TInt aRegister, TUint aContextId);
       
    47 void MCR_SetBreakpointPair(TInt aRegister, TUint aBvrValue, TUint aBcrValue);
       
    48 TUint MRC_ReadBcr(TInt aRegister);
       
    49 TUint32 GetDscr();
       
    50 void MCR_SetDscr(TUint32 aVal);
       
    51 TUint32 GetDsar();
       
    52 TUint32 GetDrar();
       
    53 TUint32 GetContextId();
       
    54 void Dsb();
       
    55 void Isb();
       
    56 void Imb();
       
    57 
       
    58 enum TMemMappedDebugAddresses
       
    59 	{
       
    60 	EDscrOffset = 0x88,
       
    61 	EBvrOffset = 0x100,
       
    62 	EBcrOffset = 0x140,
       
    63 	ELockAccessOffset = 0xFB0,
       
    64 	EAuthStatusOffset = 0xFB8,
       
    65 	};
       
    66 
       
    67 
       
    68 DDebuggerEventHandler* DDebuggerEventHandler::New(TDfcQue* aQue)
       
    69 	{
       
    70 	// This is backwards from the usual constructor, 2nd phase construction pattern because I can't do anything that could
       
    71 	// error after creating a DKernelEventHandler, because we get called from DLogicalDevice::Install(). So the stuff that would normally
       
    72 	// be done as 2nd-phase construction is done first
       
    73 
       
    74 	DMutex* breakpointMutex = NULL;
       
    75 	TInt err = Kern::MutexCreate(breakpointMutex, _L("FDebuggerBreakpointMutex"), KMutexOrdGeneral5); // No special reason for using 5
       
    76 	if (err) return NULL;
       
    77 
       
    78 	DDebuggerEventHandler* self = new DDebuggerEventHandler(aQue);
       
    79 	if (self)
       
    80 		{
       
    81 		self->iBreakpointMutex = breakpointMutex;
       
    82 		self->Add();
       
    83 		}
       
    84 	else
       
    85 		{
       
    86 		breakpointMutex->Close(NULL);
       
    87 		}
       
    88 	return self;
       
    89 	}
       
    90 
       
    91 DDebuggerEventHandler::DDebuggerEventHandler(TDfcQue* aQue)
       
    92 	: DKernelEventHandler(&Event, this), iNextBreakpointId(1), iHandleCodesegRemovedDfc(&HandleCodesegRemoved, this, aQue, 0)
       
    93 	{
       
    94 #if defined(FSHELL_ARM11XX_SUPPORT) || defined(FSHELL_ARM_MEM_MAPPED_DEBUG)
       
    95 	iFreeHwBreakpoints = 0x3F; // BRPs 0,1,2,3,4,5 (at a minimum) are supported on ARM11xx or later
       
    96 #endif
       
    97 	}
       
    98 
       
    99 /*static*/ TUint DDebuggerEventHandler::Event(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aPrivateData)
       
   100 	{
       
   101 	DDebuggerEventHandler* self = static_cast<DDebuggerEventHandler*>(aPrivateData);
       
   102 	return self->DoEvent(aEvent, a1, a2);
       
   103 	}
       
   104 
       
   105 TUint DDebuggerEventHandler::DoEvent(TKernelEvent aEvent, TAny* a1, TAny* a2)
       
   106 	{
       
   107 	//if (aEvent != EEventUserTrace) Kern::Printf("fdbk: Event %d a1=%d a2=%d", aEvent, a1, a2);
       
   108 
       
   109 	if (aEvent == EEventKillThread)
       
   110 		{
       
   111 #ifdef __MARM__
       
   112 		LOG("Thread %x %O with contextId %x killed", &Kern::CurrentThread().iNThread, &Kern::CurrentThread(), GetContextId());
       
   113 #endif
       
   114 		if (iZombieMode == EAllExits || (iZombieMode == EAbnormalExit && Kern::CurrentThread().iExitType != EExitKill))
       
   115 			{
       
   116 			// The thread in question is Kern::CurrentThread()
       
   117 			Zombify();
       
   118 			}
       
   119 		RemoveAllHardwareBreakpointsForThread(&Kern::CurrentThread()); // The thread ID could get reused so make sure we clean up
       
   120 		}
       
   121 	else if (aEvent == EEventHwExc)
       
   122 		{
       
   123 		// Breakpoint?
       
   124 #ifdef __MARM__
       
   125 		TArmExcInfo* info = (TArmExcInfo*)a1;
       
   126 		LOG("fdbk: Exception excCode=%d addr=0x%08x", info->iExcCode, info->iR15);
       
   127 		SBreakpoint* b = NULL;
       
   128 		TLinAddr excAddr = info->iR15 & ~1;
       
   129 		BreakpointLock();
       
   130 		if (info->iExcCode == 0)
       
   131 			{
       
   132 			// EArmExceptionPrefetchAbort - Could be a HW breakpoint
       
   133 			b = FindHardwareBreakpoint(&Kern::CurrentThread(), excAddr);
       
   134 			}
       
   135 		else if (info->iExcCode == 2)
       
   136 			{
       
   137 			// EArmExceptionUndefinedOpcode - SW breakpoint?
       
   138 			b = FindBreakpointByAddress(excAddr);
       
   139 			}
       
   140 		
       
   141 		LOG("fdbk: Found breakpoint %d", b ? b->iBreakpointId : -1);
       
   142 
       
   143 		if (b == NULL)
       
   144 			{
       
   145 			// Not one of ours, we should allow it to blow up (or be handled by someone else)
       
   146 			// It could of course be a thread hitting a breakpoint we've just removed, in which case I'm not sure what we can do other than let
       
   147 			// the thread crash... hopefully this won't happen in practice!
       
   148 			BreakpointUnlock();
       
   149 			return ERunNext;
       
   150 			}
       
   151 
       
   152 		TBool shouldBreak = b->MatchesThread(&Kern::CurrentThread()); // Check if it's the wrong thread
       
   153 		if (b->iFlags & SBreakpoint::ETempContinue)
       
   154 			{
       
   155 			// It's a temporary break-at-next-instruction used while continuing a thread.
       
   156 			if (shouldBreak)
       
   157 				{
       
   158 				// Excellent, we have sucessfully continued from a breakpoint. Restore the original, clear the temp (and any threads waiting on it), resume this thread and we're done
       
   159 				SBreakpoint* orig = b->iRealBreakpoint;
       
   160 				if (orig->IsHardware()) ClearBreakpoint(b, ETrue); // Clear HW first 
       
   161 				TInt err = KErrNone;
       
   162 				if ((orig->iFlags & SBreakpoint::EDisabled) == SBreakpoint::EDisabledDuringContinue)
       
   163 					{
       
   164 					// Only resume it if it hasn't been disabled for some other reason in the meantime
       
   165 					err = ApplyBreakpoint(orig);
       
   166 					}
       
   167 
       
   168 				if (err)
       
   169 					{
       
   170 					Kern::Printf("fdbk: failed to re-enable breakpoint id %d", orig->iBreakpointId);
       
   171 					// What to do?
       
   172 					}
       
   173 				else
       
   174 					{
       
   175 					// Clear the disabled flag
       
   176 					orig->iFlags &= ~SBreakpoint::EDisabledDuringContinue;
       
   177 					}
       
   178 
       
   179 				if (!orig->IsHardware()) ClearBreakpoint(b, ETrue);
       
   180 				BreakpointUnlock();
       
   181 				return (TUint)EExcHandled;
       
   182 				}
       
   183 			else
       
   184 				{
       
   185 				// Any other threads unlucky enough to hit our temp breakpoint will just have to wait until we see our target thread - otherwise
       
   186 				// we'll end up with temp breakpoints for the temp breakpoints and the universe will implode.
       
   187 				BreakpointUnlock();
       
   188 				Zombify(excAddr);
       
   189 				return (TUint)EExcHandled;
       
   190 				}
       
   191 			}
       
   192 		TInt id = b->iBreakpointId;
       
   193 		BreakpointUnlock();
       
   194 		if (shouldBreak)
       
   195 			{
       
   196 			// TODO should we suspend the thread rather than semaphoring it, to be more efficient?
       
   197 			if (iBreakpointNotifyClient)
       
   198 				{
       
   199 				RMemoryAccess::TBreakpointNotification notif;
       
   200 				notif.iThreadId = Kern::CurrentThread().iId;
       
   201 				notif.iBreakpointId = id;
       
   202 				notif.iAddress = excAddr;
       
   203 				TPckg<RMemoryAccess::TBreakpointNotification> pkg(notif);
       
   204 				// We shouldn't really pass blobs of data...
       
   205 				iBreakpointNotifyClient->BreakpointHit(pkg);
       
   206 				}
       
   207 			Zombify(excAddr);
       
   208 			}
       
   209 		else
       
   210 			{
       
   211 			TInt err = ContinueFromBreakpoint(&Kern::CurrentThread(), excAddr);
       
   212 			if (err) return ERunNext; // If we failed to continue, we shouldn't pretend we've handled it
       
   213 			}
       
   214 		return (TUint)DKernelEventHandler::EExcHandled;
       
   215 #else
       
   216 		(void)a1;
       
   217 #endif
       
   218 		}
       
   219 	else if (aEvent == EEventRemoveCodeSeg)
       
   220 		{
       
   221 		DCodeSeg* codeseg = (DCodeSeg*)a1;
       
   222 		DProcess* proc = (DProcess*)a2;
       
   223 		// We can't scan the breakpoint list at this point, because we'd need to call BreakpointLock() and 
       
   224 		// we're currently holding the codeseg lock. So queue a DFC.
       
   225 		SRemovedCodeseg* removed = new SRemovedCodeseg;
       
   226 		if (removed)
       
   227 			{
       
   228 			removed->iCodeseg = codeseg;
       
   229 			removed->iProcess = proc;
       
   230 			Lock();
       
   231 			iRemovedCodesegs.Add(&removed->iLink);
       
   232 			Unlock();
       
   233 			NKern::ThreadEnterCS();
       
   234 			iHandleCodesegRemovedDfc.Enque();
       
   235 			NKern::ThreadLeaveCS();
       
   236 			}
       
   237 		}
       
   238 	else if (aEvent == EEventRemoveThread)
       
   239 		{
       
   240 		DThread* thread = (DThread*)a1;
       
   241 		TCreatorInfo dummy(thread->iId, 0);
       
   242 		BreakpointLock(); // It's not actually breakpoint related but never mind
       
   243 		TInt found = iCreatorInfo.FindInUnsignedKeyOrder(dummy);
       
   244 		if (found != KErrNotFound)
       
   245 			{
       
   246 			iCreatorInfo.Remove(found);
       
   247 			}
       
   248 		BreakpointUnlock();
       
   249 		}
       
   250 	else if (aEvent == EEventRemoveProcess)
       
   251 		{
       
   252 		// In case a thread dies before creating its first thread, try to remove the creator info we stashed
       
   253 		DProcess* proc = (DProcess*)a1;
       
   254 		TCreatorInfo dummy(proc->iId, 0);
       
   255 		BreakpointLock();
       
   256 		TInt found = iCreatorInfo.FindInUnsignedKeyOrder(dummy);
       
   257 		if (found != KErrNotFound)
       
   258 			{
       
   259 			iCreatorInfo.Remove(found);
       
   260 			}
       
   261 		BreakpointUnlock();
       
   262 		}
       
   263 	else if (aEvent == EEventAddProcess)
       
   264 		{
       
   265 		// We need to use EEventAddProcess as well as EEventAddThread, because EEventAddThread doesn't do the special check for the creator not being the current thread, meaning for process creation the main thread always appears to have been created by the loader and not be the person who created the process
       
   266 		// Remember the process for when we come to add the thread
       
   267 		DProcess* process = (DProcess*)a1;
       
   268 		DThread* creator = (DThread*)a2;
       
   269 		BreakpointLock();
       
   270 		TCreatorInfo threadInfo(process->iId, creator->iId);
       
   271 		TInt err = iCreatorInfo.InsertInUnsignedKeyOrder(threadInfo);
       
   272 		if (err)
       
   273 			{
       
   274 			LOG("Failed to InsertInUnsignedKeyOrder err=%d", err);
       
   275 			}
       
   276 		BreakpointUnlock();
       
   277 		}
       
   278 	else if (aEvent == EEventAddThread)
       
   279 		{
       
   280 		DThread* thread = (DThread*)a1;
       
   281 		DThread* creator = (DThread*)a2;
       
   282 		TCreatorInfo threadInfo(thread->iId, creator->iId);
       
   283 
       
   284 		BreakpointLock(); // It's not actually breakpoint related but never mind
       
   285 		if (thread->Owner() != creator->Owner())
       
   286 			{
       
   287 			// This means we're probably the first thread of a new process, and our 'creator' is the loader thread. Use the info we stashed earlier about the process's creator instead
       
   288 			TCreatorInfo dummy(((DProcess*)thread->Owner())->iId, 0);
       
   289 			TInt found = iCreatorInfo.FindInUnsignedKeyOrder(dummy);
       
   290 			if (found != KErrNotFound)
       
   291 				{
       
   292 				threadInfo.iCreatorThreadId = iCreatorInfo[found].iCreatorThreadId;
       
   293 				// We don't need to track the process creator for anything else
       
   294 				iCreatorInfo.Remove(found);
       
   295 				}
       
   296 			}
       
   297 		TInt err = iCreatorInfo.InsertInUnsignedKeyOrder(threadInfo);
       
   298 		if (err)
       
   299 			{
       
   300 			LOG("Failed to InsertInUnsignedKeyOrder err=%d", err);
       
   301 			}
       
   302 		BreakpointUnlock();
       
   303 		}
       
   304 	return ERunNext;
       
   305 	}
       
   306 
       
   307 TInt DDebuggerEventHandler::Zombify(TLinAddr aBreakpointAddr)
       
   308 	{
       
   309 	// The purpose of this code is to prevent dying threads from taking down their address space, so that we can still poke at their memory
       
   310 	// Currently, it is also used to pause a thread on a breakpoint
       
   311 	SZombie zom; // zombies go on the stack of the thread that is being halted. That way avoids having to alloc.
       
   312 	zom.iThread = &Kern::CurrentThread();
       
   313 	zom.iBlocker = NULL;
       
   314 	zom.iBreakpointAddress = aBreakpointAddr;
       
   315 	TBuf8<32> semName;
       
   316 	semName.Append(_L8("ThreadZombiefier-"));
       
   317 	semName.AppendNum((TUint)zom.iThread->iId);
       
   318 	NKern::ThreadEnterCS();
       
   319 	TInt err = Kern::SemaphoreCreate(zom.iBlocker, semName, 0);
       
   320 	if (err)
       
   321 		{
       
   322 		NKern::ThreadLeaveCS();
       
   323 		return err;
       
   324 		}
       
   325 	Lock();
       
   326 	iZombies.Add(&zom.iLink);
       
   327 	iZombieCount++;
       
   328 	Unlock();
       
   329 	zom.iThread->Open(); // So no-one is tempted to destroy it
       
   330 	NKern::ThreadLeaveCS();
       
   331 	Kern::SemaphoreWait(*zom.iBlocker);
       
   332 	// The above blocks until a "fdb detach" or equivalent has happened, at which point we'll get signalled on this semaphore and should clean up
       
   333 	zom.iBlocker->Close(NULL);
       
   334 	zom.iThread->Close(NULL);
       
   335 	return KErrNone;
       
   336 	}
       
   337 
       
   338 TInt DDebuggerEventHandler::GetZombieMode()
       
   339 	{
       
   340 	Lock();
       
   341 	TInt res = iZombieMode;
       
   342 	Unlock();
       
   343 	return res;
       
   344 	}
       
   345 
       
   346 TInt DDebuggerEventHandler::SetZombieMode(TInt aMode)
       
   347 	{
       
   348 	Lock();
       
   349 	iZombieMode = (TZombieMode)aMode;
       
   350 	Unlock();
       
   351 	if (aMode == EDisabled)
       
   352 		{
       
   353 		ClearAllBreakpoints(); // This is not exactly obvious, but unblocking a zombie that's blocked on a breakpoint necessarily means you have to remove the breakpoint
       
   354 		CompleteZombies();
       
   355 		}
       
   356 	
       
   357 	return KErrNone;
       
   358 	}
       
   359 
       
   360 void DDebuggerEventHandler::CompleteZombies()
       
   361 	{
       
   362 	ASSERT_UNLOCKED();
       
   363 	// enter and exit with lock not held
       
   364 	for (;;)
       
   365 		{
       
   366 		Lock();
       
   367 		SDblQueLink* link = iZombies.IsEmpty() ? NULL : iZombies.First();
       
   368 		if (!link)
       
   369 			{
       
   370 			Unlock();
       
   371 			break;
       
   372 			}
       
   373 		SZombie* zom = _LOFF(link, SZombie, iLink);
       
   374 		ReleaseZombieAndUnlock(zom);
       
   375 		}
       
   376 	}
       
   377 
       
   378 void DDebuggerEventHandler::UnsuspendThread(SZombie* aZombie)
       
   379 	{
       
   380 	Kern::ThreadResume(*aZombie->iThread);
       
   381 	aZombie->iThread->Close(NULL);
       
   382 	delete aZombie;
       
   383 	}
       
   384 
       
   385 TInt DDebuggerEventHandler::SuspendThread(DThread* aThread)
       
   386 	{
       
   387 	// This is the only case where an SZombie goes on the heap - usually they are created in the context of their thread so go on that thread's stack
       
   388 	SZombie* zom = new SZombie;
       
   389 	if (!zom) return KErrNoMemory;
       
   390 	zom->iThread = aThread;
       
   391 	zom->iThread->Open();
       
   392 	zom->iBlocker = NULL;
       
   393 	Lock();
       
   394 	iZombies.Add(&zom->iLink);
       
   395 	iZombieCount++;
       
   396 	Unlock();
       
   397 	Kern::ThreadSuspend(*zom->iThread, 1);
       
   398 	return KErrNone;
       
   399 	}
       
   400 
       
   401 void DDebuggerEventHandler::Lock()
       
   402 	{
       
   403 	NKern::FMWait(&iLock);
       
   404 	}
       
   405 
       
   406 void DDebuggerEventHandler::Unlock()
       
   407 	{
       
   408 	NKern::FMSignal(&iLock);
       
   409 	}
       
   410 
       
   411 DDebuggerEventHandler::~DDebuggerEventHandler()
       
   412 	{
       
   413 	// The call to SetZombieMode below is actually pretty pointless: the kernel increments our access count while calling
       
   414 	// our Event function, which means DKernelEventHandler::Close will never get as far as our destructor
       
   415 	// while we are blocking on zombies.
       
   416 	SetZombieMode(EDisabled); // This frees up any outstanding zombies via CompleteZombies()
       
   417 
       
   418 	iHandleCodesegRemovedDfc.Cancel();
       
   419 
       
   420 	if (iCodeModifierInited)
       
   421 		{
       
   422 #ifdef __EPOC32__
       
   423 		DebugSupport::CloseCodeModifier();
       
   424 #endif
       
   425 		}
       
   426 
       
   427 	if (iBreakpointMutex)
       
   428 		{
       
   429 		iBreakpointMutex->Close(NULL);
       
   430 		}
       
   431 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
   432 	if (iDebugRegistersChunk)
       
   433 		{
       
   434 		iDebugRegistersChunk->Close(NULL);
       
   435 		}
       
   436 #endif
       
   437 	iCreatorInfo.Close();
       
   438 	}
       
   439 
       
   440 HBuf* DDebuggerEventHandler::GetZombieThreadIds()
       
   441 	{
       
   442 	TInt count = iZombieCount;
       
   443 	TInt size = count*sizeof(RMemoryAccess::TZombieInfo);
       
   444 	HBuf* result = HBuf::New(size);
       
   445 	if (!result) return NULL;
       
   446 	result->SetLength(size);
       
   447 	RMemoryAccess::TZombieInfo* ptr = (RMemoryAccess::TZombieInfo*)result->Ptr();
       
   448 	Lock();
       
   449 	TInt i = 0;
       
   450 	for (SDblQueLink* link = iZombies.First(); link != NULL && link != &iZombies.iA && i < count; i++, link=link->iNext)
       
   451 		{
       
   452 		SZombie& zom = *_LOFF(link, SZombie, iLink);
       
   453 		ptr[i].iThreadId = zom.iThread->iId;
       
   454 		ptr[i].iFlags = 0;
       
   455 		if (zom.iBlocker == NULL) ptr[i].iFlags |= RMemoryAccess::TZombieInfo::ESuspended;
       
   456 		else if (zom.iBreakpointAddress != 0) ptr[i].iFlags |= RMemoryAccess::TZombieInfo::EBreakpoint;
       
   457 		}
       
   458 	Unlock();
       
   459 	return result;
       
   460 	}
       
   461 
       
   462 DDebuggerEventHandler::SZombie* DDebuggerEventHandler::FindZombie(DThread* aThread)
       
   463 	{
       
   464 	// Enter and leave locked
       
   465 	ASSERT_LOCKED();
       
   466 	for (SDblQueLink* link = iZombies.First(); link != NULL && link != &iZombies.iA; link=link->iNext)
       
   467 		{
       
   468 		SZombie* zom = _LOFF(link, SZombie, iLink);
       
   469 		if (zom->iThread == aThread)
       
   470 			{
       
   471 			return zom;
       
   472 			}
       
   473 		}
       
   474 	return NULL;
       
   475 	}
       
   476 
       
   477 TInt DDebuggerEventHandler::ReleaseZombie(DThread* aThread)
       
   478 	{
       
   479 	ASSERT_UNLOCKED();
       
   480 	Lock();
       
   481 	SZombie* found = FindZombie(aThread);
       
   482 	if (found)
       
   483 		{
       
   484 		if (found->iBreakpointAddress)
       
   485 			{
       
   486 			// It's actually paused on a breakpoint, so we need to do a continue instead
       
   487 			Unlock();
       
   488 			return ContinueFromBreakpoint(aThread, 0);
       
   489 			}
       
   490 		else
       
   491 			{
       
   492 			ReleaseZombieAndUnlock(found);
       
   493 			return KErrNone;
       
   494 			}
       
   495 		}
       
   496 	else
       
   497 		{
       
   498 		Unlock();
       
   499 		return KErrNotFound;
       
   500 		}
       
   501 	}
       
   502 
       
   503 void DDebuggerEventHandler::ReleaseZombieAndUnlock(SZombie* aZombie)
       
   504 	{
       
   505 	ASSERT_LOCKED();
       
   506 	ReleaseZombie(aZombie);
       
   507 	Unlock();
       
   508 	}
       
   509 
       
   510 void DDebuggerEventHandler::ReleaseZombie(SZombie* aZombie)
       
   511 	{
       
   512 	ASSERT_LOCKED();
       
   513 	aZombie->iLink.Deque();
       
   514 	iZombieCount--;
       
   515 	if (aZombie->iBlocker)
       
   516 		{
       
   517 		Kern::SemaphoreSignal(*aZombie->iBlocker);
       
   518 		}
       
   519 	else
       
   520 		{
       
   521 		UnsuspendThread(aZombie);
       
   522 		}
       
   523 	}
       
   524 
       
   525 TInt DDebuggerEventHandler::RegisterForBreakpointNotification(MDebuggerEventClient* aClient)
       
   526 	{
       
   527 	Lock();
       
   528 	TInt err = KErrAlreadyExists;
       
   529 	if (iBreakpointNotifyClient == NULL || iBreakpointNotifyClient == aClient)
       
   530 		{
       
   531 		err = KErrNone;
       
   532 		iBreakpointNotifyClient = aClient;
       
   533 		}
       
   534 	Unlock();
       
   535 	return err;
       
   536 	}
       
   537 
       
   538 void DDebuggerEventHandler::UnregisterForBreakpointNotification(MDebuggerEventClient* aClient)
       
   539 	{
       
   540 	Lock();
       
   541 	if (aClient == iBreakpointNotifyClient)
       
   542 		{
       
   543 		iBreakpointNotifyClient = NULL;
       
   544 		}
       
   545 	Unlock();
       
   546 	}
       
   547 
       
   548 TInt DDebuggerEventHandler::SetBreakpoint(DThread* aThread, TLinAddr aAddress, const RMemoryAccess::TPredicate& aCondition)
       
   549 	{
       
   550 	TInt codemodifierErr = KErrNone;
       
   551 	if (!iCodeModifierInited)
       
   552 		{
       
   553 #ifdef __EPOC32__
       
   554 		TUint caps;
       
   555 		const TInt KMaxBreakpoints = 32;
       
   556 		codemodifierErr = DebugSupport::InitialiseCodeModifier(caps, KMaxBreakpoints);
       
   557 #else
       
   558 		codemodifierErr = KErrNotSupported;
       
   559 #endif
       
   560 		if (!codemodifierErr) iCodeModifierInited = ETrue;
       
   561 		// It's not necessarily fatal that we can't init the code modifier - we may still be able to set a H/W breakpoint
       
   562 		}
       
   563 
       
   564 	SBreakpoint* b = new SBreakpoint(aThread, iNextBreakpointId, aAddress, aCondition); // iNextBreakpointId gets incremented later
       
   565 	if (!b) return KErrNoMemory;
       
   566 
       
   567 	// Get the codeseg for this address
       
   568 	Kern::AccessCode();
       
   569 	b->iCodeSeg = Kern::CodeSegFromAddress(b->iAddress, b->iThread->iOwningProcess);
       
   570 	Kern::EndAccessCode();
       
   571 
       
   572 	BreakpointLock();
       
   573 	
       
   574 	// Check if there's already a HW breakpoint for this thread and address - we don't allow duplicates, just for sanity's sake
       
   575 	SBreakpoint* existingHwBreakpoint = FindHardwareBreakpoint(b->iThread, b->iAddress);
       
   576 	if (existingHwBreakpoint)
       
   577 		{
       
   578 		BreakpointUnlock();
       
   579 		delete b;
       
   580 		return KErrAlreadyExists;
       
   581 		}
       
   582 
       
   583 	TBreakpointPolicy policy = EWhatever;
       
   584 	// Check if we already have a breakpoint for this address. Because all software breakpoints are global, if we add repeated breakpoints on the same address (but on threads in different processes) DebugSupport will happily allow it and create nested nastyness
       
   585 	SBreakpoint* existingBreakpoint = FindBreakpointByAddress(b->iAddress);
       
   586 	if (existingBreakpoint)	policy = EHardwareOnly; // To prevent another SW breakpoint at this location. Multiple HW breakpoints are fine because they're per-thread
       
   587 	if (codemodifierErr != KErrNone) policy = EHardwareOnly; // If we failed to init code modifier, can only do h/w
       
   588 
       
   589 	iBreakpoints.Add(&b->iLink);
       
   590 	TInt err = ApplyBreakpoint(b, policy);
       
   591 	if (err && existingBreakpoint)
       
   592 		{
       
   593 		// If we couldn't set a HW breakpoint, no worries, fall back to relying on the existing SW breakpoint
       
   594 		b->iRealBreakpoint = existingBreakpoint;
       
   595 		err = KErrNone;
       
   596 		}
       
   597 
       
   598 	if (err < 0)
       
   599 		{
       
   600 		b->iLink.Deque();
       
   601 		delete b;
       
   602 		}
       
   603 	else
       
   604 		{
       
   605 		iNextBreakpointId++; // Now we know we're actually using it
       
   606 		}
       
   607 
       
   608 	BreakpointUnlock();
       
   609 	if (err)
       
   610 		{
       
   611 		return err;
       
   612 		}
       
   613 	else
       
   614 		{
       
   615 		TInt result = b->iBreakpointId;
       
   616 		if (b->IsHardware()) result |= RMemoryAccess::TBreakpointInfo::EHardware;
       
   617 		return result;
       
   618 		}
       
   619 	}
       
   620 
       
   621 TInt DDebuggerEventHandler::SetSymbolicBreakpoint(DThread* aThread, HBuf* aCodesegName, TUint32 aOffset, const RMemoryAccess::TPredicate& aCondition)
       
   622 	{
       
   623 	// See if the codeseg is currently loaded
       
   624 	Kern::AccessCode();
       
   625 	SDblQue* list = Kern::CodeSegList();
       
   626 	for (SDblQueLink* link = list->First(); link != &list->iA; link = link->iNext)
       
   627 		{
       
   628 		DCodeSeg* codeSeg = _LOFF(link, DCodeSeg, iLink);
       
   629 		if (codeSeg->iRootName == *aCodesegName)
       
   630 			{
       
   631 			TUint addr = codeSeg->iRunAddress + aOffset;
       
   632 			Kern::EndAccessCode();
       
   633 			TInt res = SetBreakpoint(aThread, addr, aCondition);
       
   634 			if (res >= KErrNone) delete aCodesegName;
       
   635 			return res;
       
   636 			}
       
   637 		}
       
   638 	Kern::EndAccessCode();
       
   639 	// If we get here, codeseg isn't currently loaded so need to create it as a pending breakpoint
       
   640 
       
   641 	SBreakpoint* b = new SBreakpoint(aThread, iNextBreakpointId++, aOffset, aCondition);
       
   642 	if (!b) return KErrNoMemory;
       
   643 	b->iCodeSeg = aCodesegName;
       
   644 	b->iFlags |= SBreakpoint::EDisabledPendingCodesegLoad;
       
   645 	BreakpointLock();
       
   646 	iBreakpoints.Add(&b->iLink);
       
   647 	BreakpointUnlock();
       
   648 	return KErrNone;
       
   649 	}
       
   650 
       
   651 TInt DDebuggerEventHandler::ApplyBreakpoint(SBreakpoint* aBreakpoint, TBreakpointPolicy aPolicy)
       
   652 	{
       
   653 	ASSERT_BREAKPOINT_LOCKED();
       
   654 	// These magic constants don't appear to be defined anywhere, they're just undefined instructions that will cause an exception that we can then handle
       
   655 	const TUint32 KArmBreakPoint = 0xE7F123F4;
       
   656 	const TUint16 KThumbBreakPoint = 0xDE56;
       
   657 	TUint32 inst = KArmBreakPoint;
       
   658 	TInt instSize = 4;
       
   659 	if (aBreakpoint->iFlags & SBreakpoint::EThumb)
       
   660 		{
       
   661 		inst = KThumbBreakPoint;
       
   662 		instSize = 2;
       
   663 		}
       
   664 
       
   665 #ifdef __EPOC32__
       
   666 	// Before modifying stuff, save the original instruction (needed for ReadInstructions())
       
   667 	TInt err = Kern::ThreadRawRead(aBreakpoint->iThread, (TAny*)aBreakpoint->iAddress, (TAny*)aBreakpoint->iOrigInstruction.Ptr(), instSize);
       
   668 	if (!err)
       
   669 		{
       
   670 		aBreakpoint->iOrigInstruction.SetLength(instSize);
       
   671 		if (aPolicy != ESoftwareOnly)
       
   672 			{
       
   673 			err = ApplyHardwareBreakpoint(aBreakpoint);
       
   674 			// If we manage to set a hardware breakpoint, we don't need to call ModifyCode
       
   675 			if (err == KErrNone)
       
   676 				{
       
   677 				LOG("HW breakpoint set ok");
       
   678 				aBreakpoint->iFlags |= SBreakpoint::EHardware;
       
   679 				}
       
   680 			else
       
   681 				{
       
   682 				Kern::Printf("Failed to set hardware breakpoint - %d", err);
       
   683 				}
       
   684 			}
       
   685 
       
   686 		if (aPolicy != EHardwareOnly && !aBreakpoint->IsHardware())
       
   687 			{
       
   688 			// Last check that we don't conflict with another breakpoint
       
   689 			err = (FindBreakpointByAddress(aBreakpoint->iAddress) == NULL ? KErrNone : KErrAlreadyExists);
       
   690 			if (!err) err = DebugSupport::ModifyCode(aBreakpoint->iThread, aBreakpoint->iAddress, instSize, inst, DebugSupport::EBreakpointGlobal);
       
   691 			if (err > 0) err = KErrNone; // Really don't care about what the breakpoint type is
       
   692 			}
       
   693 		}
       
   694 #else
       
   695 	TInt err = KErrNotSupported;
       
   696 	(void)aPolicy;
       
   697 #endif
       
   698 	return err;
       
   699 	}
       
   700 
       
   701 DDebuggerEventHandler::SBreakpoint* DDebuggerEventHandler::FindBreakpointByAddress(/*DThread* aThread,*/ TLinAddr aAddress)
       
   702 	{
       
   703 	// Enter and leave holding lock
       
   704 	// This only finds 'real' breakpoints, ie ones which have a ModifyCode outstanding, or are persistant. (NOT hardware breakpoints)
       
   705 	ASSERT_BREAKPOINT_LOCKED();
       
   706 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
   707 		{
       
   708 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   709 		if (/*b->iThread == aThread &&*/ b->iAddress == aAddress && (b->HasModifiedCode() || (b->iFlags & SBreakpoint::EPersistant)))
       
   710 			{
       
   711 			return b;
       
   712 			}
       
   713 		}
       
   714 	return NULL;
       
   715 	}
       
   716 
       
   717 DDebuggerEventHandler::SBreakpoint* DDebuggerEventHandler::FindHardwareBreakpoint(DThread* aThread, TLinAddr aAddress)
       
   718 	{
       
   719 	// Enter and leave holding lock
       
   720 	ASSERT_BREAKPOINT_LOCKED();
       
   721 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
   722 		{
       
   723 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   724 		if (b->iThread == aThread && b->iAddress == aAddress && b->IsHardware())
       
   725 			{
       
   726 			return b;
       
   727 			}
       
   728 		}
       
   729 	return NULL;
       
   730 	}
       
   731 
       
   732 DDebuggerEventHandler::SBreakpoint* DDebuggerEventHandler::FindBreakpointById(TInt aId)
       
   733 	{
       
   734 	// Enter and leave holding lock
       
   735 	ASSERT_BREAKPOINT_LOCKED();
       
   736 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
   737 		{
       
   738 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   739 		if (b->iBreakpointId == aId)
       
   740 			{
       
   741 			return b;
       
   742 			}
       
   743 		}
       
   744 	return NULL;
       
   745 	}
       
   746 
       
   747 DDebuggerEventHandler::SBreakpoint* DDebuggerEventHandler::FindBreakpointUsingHardwareContextRegister(TInt aRegister)
       
   748 	{
       
   749 	// Enter and leave holding lock
       
   750 	ASSERT_BREAKPOINT_LOCKED();
       
   751 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
   752 		{
       
   753 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   754 		if (b->IsHardware() && b->iHardwareBreakpointContextReg == aRegister)
       
   755 			{
       
   756 			return b;
       
   757 			}
       
   758 		}
       
   759 	return NULL;
       
   760 	}
       
   761 
       
   762 TInt DDebuggerEventHandler::SetBreakpointEnabled(TInt aBreakpointId, TBool aFlag)
       
   763 	{
       
   764 	BreakpointLock();
       
   765 	SBreakpoint* b = FindBreakpointById(aBreakpointId);
       
   766 	if (!b)
       
   767 		{
       
   768 		BreakpointUnlock();
       
   769 		return KErrNotFound;
       
   770 		}
       
   771 
       
   772 	TInt err = KErrNone;
       
   773 	if (aFlag)
       
   774 		{
       
   775 		if (b->iFlags & SBreakpoint::EDisabled == SBreakpoint::EDisabledByUser)
       
   776 			{
       
   777 			// Provided it's not disabled for any reason other than the user asked for it, re-enable it
       
   778 			err = ApplyBreakpoint(b);
       
   779 			if (err == KErrNone) b->iFlags |= ~SBreakpoint::EDisabledByUser;
       
   780 			}
       
   781 		else
       
   782 			{
       
   783 			err = KErrNotReady;
       
   784 			}
       
   785 		}
       
   786 	else
       
   787 		{
       
   788 		if (!(b->iFlags & SBreakpoint::EDisabled))
       
   789 			{
       
   790 			// If it's not already disabled for any reason, disable it
       
   791 			UnapplyBreakpoint(b);
       
   792 			}
       
   793 		b->iFlags |= SBreakpoint::EDisabledByUser;
       
   794 		}
       
   795 	BreakpointUnlock();
       
   796 	return KErrNone;
       
   797 	}
       
   798 
       
   799 TInt DDebuggerEventHandler::ClearBreakpoint(TInt aBreakpointId)
       
   800 	{
       
   801 	BreakpointLock();
       
   802 	SBreakpoint* b = FindBreakpointById(aBreakpointId);
       
   803 	if (!b)
       
   804 		{
       
   805 		BreakpointUnlock();
       
   806 		return KErrNotFound;
       
   807 		}
       
   808 
       
   809 	ClearBreakpoint(b);
       
   810 	BreakpointUnlock();
       
   811 	return KErrNone;
       
   812 	}
       
   813 
       
   814 void DDebuggerEventHandler::ClearBreakpoint(SBreakpoint* aBreakpoint, TBool aResumeAllBlocked /*=EFalse*/)
       
   815 	{
       
   816 	// enter and leave locked
       
   817 	ASSERT_BREAKPOINT_LOCKED();
       
   818 	TLinAddr addr = aBreakpoint->iAddress;
       
   819 	aBreakpoint->iLink.Deque();
       
   820 	UnapplyBreakpoint(aBreakpoint);
       
   821 	delete aBreakpoint;
       
   822 
       
   823 	if (aResumeAllBlocked)
       
   824 		{
       
   825 		Lock();
       
   826 		for (SDblQueLink* link = iZombies.First(); link != NULL && link != &iZombies.iA; link=link->iNext)
       
   827 			{
       
   828 			SZombie* zom = _LOFF(link, SZombie, iLink);
       
   829 			if (zom->iBreakpointAddress == addr)
       
   830 				{
       
   831 				ReleaseZombie(zom);
       
   832 				}
       
   833 			}
       
   834 		Unlock();
       
   835 		}
       
   836 	}
       
   837 
       
   838 void DDebuggerEventHandler::UnapplyBreakpoint(SBreakpoint* aBreakpoint)
       
   839 	{
       
   840 #ifdef __EABI__
       
   841 	if (aBreakpoint->HasModifiedCode())
       
   842 		{
       
   843 		DebugSupport::RestoreCode(aBreakpoint->iThread, aBreakpoint->iAddress);
       
   844 		HandleRestoreCode(aBreakpoint->iAddress);
       
   845 		}
       
   846 	if (aBreakpoint->IsHardware())
       
   847 		{
       
   848 #ifdef __SMP__
       
   849 		TInt num = NKern::NumberOfCpus();
       
   850 		TUint32 origAffinity = 0;
       
   851 		for (TInt i = 0; i < num; i++)
       
   852 			{
       
   853 			TUint32 affinity = NKern::ThreadSetCpuAffinity(&Kern::CurrentThread().iNThread, i);
       
   854 			if (i == 0) origAffinity = affinity;
       
   855 			DoClearHardwareBreakpoint(aBreakpoint);
       
   856 			}
       
   857 		NKern::ThreadSetCpuAffinity(&Kern::CurrentThread().iNThread, origAffinity);
       
   858 #else
       
   859 		DoClearHardwareBreakpoint(aBreakpoint);
       
   860 #endif // __SMP__
       
   861 		iFreeHwBreakpoints |= (1 << aBreakpoint->iHardwareBreakpointId);
       
   862 		}
       
   863 #else
       
   864 	(void)aBreakpoint;
       
   865 #endif // __EABI__
       
   866 	}
       
   867 
       
   868 #ifdef __EABI__
       
   869 void DDebuggerEventHandler::DoClearHardwareBreakpoint(SBreakpoint* aBreakpoint)
       
   870 	{
       
   871 	TUint32 bcr = ReadBcr(aBreakpoint->iHardwareBreakpointId);
       
   872 	bcr = bcr & ~1; // Clear the enabled bit
       
   873 	SetBreakpointPair(aBreakpoint->iHardwareBreakpointId, 0, bcr);
       
   874 	}
       
   875 #endif
       
   876 
       
   877 void DDebuggerEventHandler::ClearAllBreakpoints()
       
   878 	{
       
   879 	ASSERT_UNLOCKED();
       
   880 	ASSERT_BREAKPOINT_UNLOCKED();
       
   881 	// enter and exit with lock not held
       
   882 	BreakpointLock();
       
   883 	for (;;)
       
   884 		{
       
   885 		SDblQueLink* link = iBreakpoints.IsEmpty() ? NULL : iBreakpoints.First();
       
   886 		if (!link)
       
   887 			{
       
   888 			break;
       
   889 			}
       
   890 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   891 		ClearBreakpoint(b);
       
   892 		}
       
   893 	BreakpointUnlock();
       
   894 	}
       
   895 
       
   896 TInt DDebuggerEventHandler::ContinueFromBreakpoint(DThread* aThread, TLinAddr aExceptionAddress)
       
   897 	{
       
   898 	// First find the SZombie
       
   899 	SZombie* zombie = NULL;
       
   900 	TLinAddr breakpointAddr = 0;
       
   901 	// If aExceptionAddress is non-zero, it means we're being called from inside the exception handler and we haven't actually created a zombie
       
   902 	if (aExceptionAddress)
       
   903 		{
       
   904 		breakpointAddr = aExceptionAddress;
       
   905 		}
       
   906 	else
       
   907 		{
       
   908 		Lock();
       
   909 		zombie = FindZombie(aThread);
       
   910 		if (!zombie)
       
   911 			{
       
   912 			Unlock();
       
   913 			return KErrNotFound;
       
   914 			}
       
   915 		else if (zombie->iBreakpointAddress == 0)
       
   916 			{
       
   917 			// It's a zombie but not one on a breakpoint
       
   918 			Unlock();
       
   919 			return KErrNotReady;
       
   920 			}
       
   921 		// Deque early while we still hold lock, twiddle the pointers so the deque in ReleaseZombieAndUnlock won't break
       
   922 		zombie->iLink.Deque();
       
   923 		zombie->iLink.iPrev = &zombie->iLink;
       
   924 		zombie->iLink.iNext = &zombie->iLink;
       
   925 		breakpointAddr = zombie->iBreakpointAddress;
       
   926 		Unlock();
       
   927 		}
       
   928 
       
   929 	BreakpointLock();
       
   930 	SBreakpoint* breakpoint = FindHardwareBreakpoint(aThread, breakpointAddr);
       
   931 	if (breakpoint == NULL) breakpoint = FindBreakpointByAddress(breakpointAddr);
       
   932 	// This could be null if someone has already cleared the breakpoint
       
   933 	if (!breakpoint)
       
   934 		{
       
   935 		BreakpointUnlock();
       
   936 		if (zombie)
       
   937 			{
       
   938 			Lock();
       
   939 			ReleaseZombieAndUnlock(zombie);
       
   940 			}
       
   941 		return KErrNone;
       
   942 		}
       
   943 	// the above logic doesn't handle if someone has cleared a persistant breakpoint that aThread is on - but if
       
   944 	// the user has done that then they're on their own.
       
   945 	// (Mitigated by us not listing persistant breakpoints in the GetBreakpoints fn)
       
   946 	if (breakpoint->iFlags & SBreakpoint::EPersistant)
       
   947 		{
       
   948 		// It's a persistant breakpoint, so we don't actually want to clear the breakpoint we just need to modify the PC to step over the break instruction
       
   949 		TLinAddr breakAddress = breakpoint->iAddress;
       
   950 		TInt err = SetProgramCounter(aThread, breakAddress + 4);
       
   951 		BreakpointUnlock();
       
   952 		if (!err && zombie)
       
   953 			{
       
   954 			Lock();
       
   955 			ReleaseZombieAndUnlock(zombie);
       
   956 			}
       
   957 		return err;
       
   958 		}
       
   959 
       
   960 	TInt err = MoveBreakpointToNextInstructionForThread(aThread, breakpoint); // When this gets hit it will take care of restoring the breakpoint back to what it should be
       
   961 	if (err)
       
   962 		{
       
   963 		Kern::Printf("fdbk: Error returned from MoveBreakpointToNextInstructionForThread %d", err);
       
   964 		}
       
   965 
       
   966 	BreakpointUnlock();
       
   967 	if (!err && zombie)
       
   968 		{
       
   969 		Lock();
       
   970 		ReleaseZombieAndUnlock(zombie);
       
   971 		}
       
   972 	return err;
       
   973 	}
       
   974 
       
   975 HBuf* DDebuggerEventHandler::GetBreakpoints()
       
   976 	{
       
   977 	TInt count = 0;
       
   978 	BreakpointLock();
       
   979 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
   980 		{
       
   981 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   982 		if (b->iFlags & SBreakpoint::EPersistant) continue;
       
   983 		count++;
       
   984 		}
       
   985 	TInt size = count*sizeof(RMemoryAccess::TBreakpointInfo);
       
   986 	HBuf* result = HBuf::New(size);
       
   987 	if (!result)
       
   988 		{
       
   989 		BreakpointUnlock();
       
   990 		return NULL;
       
   991 		}
       
   992 	result->SetLength(size);
       
   993 	RMemoryAccess::TBreakpointInfo* ptr = (RMemoryAccess::TBreakpointInfo*)result->Ptr();
       
   994 	RMemoryAccess::TBreakpointInfo* end = ptr + count;
       
   995 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA && ptr < end; link=link->iNext)
       
   996 		{
       
   997 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
   998 		if (b->iFlags & SBreakpoint::EPersistant) continue; // We don't talk about persistant breakpoints, since they're an implementation detail of LtkUtils::Breakpoint() really
       
   999 		ptr->iThreadId = b->iThread->iId;
       
  1000 		ptr->iBreakpointId = b->iBreakpointId;
       
  1001 		ptr->iAddress = b->iAddress;
       
  1002 		ptr->iFlags = 0;
       
  1003 		if (b->iFlags & SBreakpoint::EDisabledPendingCodesegLoad) ptr->iFlags |= RMemoryAccess::TBreakpointInfo::EPending;
       
  1004 		if (!(b->iFlags & SBreakpoint::EDisabledByUser)) ptr->iFlags |= RMemoryAccess::TBreakpointInfo::EEnabled;
       
  1005 		if (b->IsHardware()) ptr->iFlags |= RMemoryAccess::TBreakpointInfo::EHardware;
       
  1006 		ptr->iCondition = b->iCondition;
       
  1007 		ptr++;
       
  1008 		}
       
  1009 	BreakpointUnlock();
       
  1010 	return result;
       
  1011 	}
       
  1012 
       
  1013 TInt DDebuggerEventHandler::RegisterPersistantBreakpoint(DThread* /*aThread*/, TLinAddr aAddress)
       
  1014 	{
       
  1015 	RMemoryAccess::TPredicate condition; // Default args means 'always pass'
       
  1016 	SBreakpoint* b = new SBreakpoint(NULL, iNextBreakpointId, aAddress, condition); //  The thread is null to say any thread should trigger the breakpoint (ie truly global)
       
  1017 	if (!b) return KErrNoMemory;
       
  1018 	b->iFlags |= SBreakpoint::EPersistant;
       
  1019 
       
  1020 	BreakpointLock();
       
  1021 	SBreakpoint* existingBreakpoint = FindBreakpointByAddress(b->iAddress);
       
  1022 	if (existingBreakpoint)
       
  1023 		{
       
  1024 		BreakpointUnlock();
       
  1025 		delete b;
       
  1026 		return KErrAlreadyExists;
       
  1027 		}
       
  1028 
       
  1029 	// No need to call ModifyCode because persistant breakpoints are ones that hard-code the invalid instruction
       
  1030 	iBreakpoints.Add(&b->iLink);
       
  1031 	BreakpointUnlock();
       
  1032 	iNextBreakpointId++;
       
  1033 	return KErrNone;
       
  1034 	}
       
  1035 
       
  1036 TInt DDebuggerEventHandler::SetProgramCounter(DThread* aThread, TLinAddr aAddress)
       
  1037 	{
       
  1038 	// This can hold the breakpoint lock or not, doesn't care
       
  1039 
       
  1040 #if !defined(__WINS__) && !defined(FSHELL_9_1_SUPPORT) // win32 ekern doesn't even export this API let alone implement it
       
  1041 	TUint32 regs[32];
       
  1042 	TUint32 valid = 0;
       
  1043 	NKern::ThreadGetUserContext(&aThread->iNThread, &regs[0], valid);
       
  1044 	if (!(valid & (1<<15))) return KErrNotSupported; // If we can't read it, we can't set it
       
  1045 	regs[15] = aAddress;
       
  1046 	NKern::ThreadSetUserContext(&aThread->iNThread, &regs[0]);
       
  1047 	return KErrNone;
       
  1048 #else
       
  1049 	(void)aThread;
       
  1050 	(void)aAddress;
       
  1051 	return KErrNotSupported;
       
  1052 #endif
       
  1053 	}
       
  1054 
       
  1055 void DDebuggerEventHandler::HandleRestoreCode(TLinAddr aAddress)
       
  1056 	{
       
  1057 	ASSERT_BREAKPOINT_LOCKED();
       
  1058 	// This function is to update any shadow breakpoints that were relying on this address having been modified
       
  1059 	// We can't promote any breakpoint that's marked as pending, we need to start tracking the breakpoint address
       
  1060 	// as an offset to the codeseg run address before we can do that.
       
  1061 	SBreakpoint* newRealBreakpoint = NULL;
       
  1062 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
  1063 		{
       
  1064 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
  1065 		if (b->iAddress == aAddress && !b->IsHardware() && !(b->iFlags & SBreakpoint::EDisabled) && (b->iRealBreakpoint))
       
  1066 			{
       
  1067 			if (newRealBreakpoint == NULL)
       
  1068 				{
       
  1069 				// b is the new real one
       
  1070 				b->iRealBreakpoint = NULL;
       
  1071 				TInt err = ApplyBreakpoint(b, ESoftwareOnly);
       
  1072 				if (err)
       
  1073 					{
       
  1074 					// Oh dear...
       
  1075 					b->iFlags |= SBreakpoint::EDisabledPendingCodesegLoad;
       
  1076 					b->iCodeSeg = NULL; // This saves me having to think what state to put it in - NULL means the breakpoint is dead forever
       
  1077 					}
       
  1078 				else
       
  1079 					{
       
  1080 					newRealBreakpoint = b;
       
  1081 					}
       
  1082 				}
       
  1083 			else
       
  1084 				{
       
  1085 				b->iRealBreakpoint = newRealBreakpoint;
       
  1086 				}
       
  1087 			}
       
  1088 		}
       
  1089 	}
       
  1090 
       
  1091 void DDebuggerEventHandler::BreakpointLock()
       
  1092 	{
       
  1093 	NKern::ThreadEnterCS();
       
  1094 	Kern::MutexWait(*iBreakpointMutex);
       
  1095 	}
       
  1096 
       
  1097 void DDebuggerEventHandler::BreakpointUnlock()
       
  1098 	{
       
  1099 	Kern::MutexSignal(*iBreakpointMutex);
       
  1100 	NKern::ThreadLeaveCS();
       
  1101 	}
       
  1102 
       
  1103 TBool DDebuggerEventHandler::SBreakpoint::HasModifiedCode() const
       
  1104 	{
       
  1105 	return !(iFlags & EDisabled)
       
  1106 		&& !(iFlags & EPersistant)
       
  1107 		&& !IsHardware()
       
  1108 		&& iRealBreakpoint == NULL;
       
  1109 	}
       
  1110 
       
  1111 TBool DDebuggerEventHandler::SBreakpoint::IsHardware() const
       
  1112 	{
       
  1113 	return (iFlags & EHardware);
       
  1114 	}
       
  1115 
       
  1116 void DDebuggerEventHandler::HandleCodesegRemoved(TAny* aPtr)
       
  1117 	{
       
  1118 	static_cast<DDebuggerEventHandler*>(aPtr)->DoHandleCodesegRemoved();
       
  1119 	}
       
  1120 
       
  1121 void DDebuggerEventHandler::DoHandleCodesegRemoved()
       
  1122 	{
       
  1123 	for (;;)
       
  1124 		{
       
  1125 		Lock();
       
  1126 		SDblQueLink* link = iRemovedCodesegs.GetFirst();
       
  1127 		Unlock();
       
  1128 		if (!link) break;
       
  1129 		SRemovedCodeseg* r = _LOFF(link, SRemovedCodeseg, iLink);
       
  1130 
       
  1131 		// Check for breakpoints that have been removed by the oh-so-helpful CodeModifier
       
  1132 		BreakpointLock();
       
  1133 		for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
  1134 			{
       
  1135 			SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
  1136 			if (b->iCodeSeg == r->iCodeseg && b->iThread->iOwningProcess == r->iProcess && b->HasModifiedCode())
       
  1137 				{
       
  1138 				DCodeSeg* codeSeg = static_cast<DCodeSeg*>(b->iCodeSeg);
       
  1139 				TBool hadModifiedCode = b->HasModifiedCode();
       
  1140 				b->iFlags |= SBreakpoint::EDisabledPendingCodesegLoad;
       
  1141 				HBuf* codesegName = HBuf::New(codeSeg->iRootName.Length());
       
  1142 				if (codesegName)
       
  1143 					{
       
  1144 					// If it's null, we'll just never be able to reenable the breakpoint
       
  1145 					codesegName->Copy(codeSeg->iRootName);
       
  1146 					}
       
  1147 				TInt codesegOffset = b->iAddress - codeSeg->iRunAddress;
       
  1148 				b->iCodeSeg = codesegName;
       
  1149 				if (hadModifiedCode)
       
  1150 					{
       
  1151 					HandleRestoreCode(b->iAddress);
       
  1152 					}
       
  1153 				b->iAddress = codesegOffset; // Pending breakpoints use iAddress to store the codeseg offset
       
  1154 				}
       
  1155 			}
       
  1156 		BreakpointUnlock();
       
  1157 		delete r;
       
  1158 		}
       
  1159 	}
       
  1160 
       
  1161 DDebuggerEventHandler::SBreakpoint::SBreakpoint(DThread* aThread, TInt aBreakpointId, TLinAddr aAddress, const RMemoryAccess::TPredicate& aCondition)
       
  1162 	: iThread(aThread), iBreakpointId(aBreakpointId), iAddress(aAddress&~1), iCodeSeg(NULL), iFlags(0), iRealBreakpoint(NULL), iHardwareBreakpointId(-1), iHardwareBreakpointContextReg(-1), iMatch(NULL), iCondition(aCondition)
       
  1163 	{
       
  1164 	if (aAddress & 1) iFlags |= EThumb;
       
  1165 	if (iThread)
       
  1166 		{
       
  1167 		iThread->Open();
       
  1168 		iFlags |= EThreadSpecific;
       
  1169 		}
       
  1170 	}
       
  1171 
       
  1172 DDebuggerEventHandler::SBreakpoint::~SBreakpoint()
       
  1173 	{
       
  1174 	if (iThread) iThread->Close(NULL);
       
  1175 	delete iMatch;
       
  1176 	if (iFlags & SBreakpoint::EDisabledPendingCodesegLoad) delete (HBuf*)iCodeSeg;
       
  1177 	}
       
  1178 
       
  1179 TInt DDebuggerEventHandler::ReadInstructions(DThread* aThread, TLinAddr aAddress, TInt aLength, TDes8& aData)
       
  1180 	{
       
  1181 	if (aLength > aData.MaxSize()) return KErrArgument;
       
  1182 	TInt err = Kern::ThreadRawRead(aThread, (TAny*)aAddress, (TAny*)aData.Ptr(), aLength);
       
  1183 	if (err) return err;
       
  1184 	aData.SetLength(aLength);
       
  1185 
       
  1186 	// Now check if any of that data had breakpoints in that mean we've not read the real instruction values
       
  1187 	BreakpointLock();
       
  1188 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA; link=link->iNext)
       
  1189 		{
       
  1190 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
  1191 		if (b->iAddress >= aAddress && b->iAddress < aAddress + aLength && b->iOrigInstruction.Length())
       
  1192 			{
       
  1193 			TInt size = b->iFlags & SBreakpoint::EThumb ? 2 : 4;
       
  1194 			TPtr8 instrBuf((TUint8*)aData.Ptr() + (b->iAddress - aAddress), size, size);
       
  1195 			instrBuf.Copy(b->iOrigInstruction);
       
  1196 			}
       
  1197 		}
       
  1198 	BreakpointUnlock();
       
  1199 	return KErrNone;
       
  1200 	}
       
  1201 
       
  1202 TInt DDebuggerEventHandler::ApplyHardwareBreakpoint(SBreakpoint* aBreakpoint)
       
  1203 	{
       
  1204 	ASSERT_BREAKPOINT_LOCKED();
       
  1205 
       
  1206 	// First, check the context registers and see if we have one for this thread
       
  1207 	TInt contextReg = 0;
       
  1208 	SBreakpoint* breakUsingFour = FindBreakpointUsingHardwareContextRegister(4);
       
  1209 	SBreakpoint* breakUsingFive = FindBreakpointUsingHardwareContextRegister(5);
       
  1210 	if (breakUsingFour && aBreakpoint->iThread == breakUsingFour->iThread) contextReg = 4;
       
  1211 	if (breakUsingFive && aBreakpoint->iThread == breakUsingFive->iThread) contextReg = 5;
       
  1212 
       
  1213 	if (contextReg == 0 && breakUsingFour == NULL)
       
  1214 		{
       
  1215 		// Noone is using 4
       
  1216 		contextReg = 4;
       
  1217 		}
       
  1218 
       
  1219 	if (contextReg == 0 && breakUsingFive == NULL)
       
  1220 		{
       
  1221 		contextReg = 5;
       
  1222 		}
       
  1223 
       
  1224 	LOG("fdbk: Using context reg %d", contextReg);
       
  1225 	if (contextReg == 0) return KErrOverflow; // No free context registers
       
  1226 
       
  1227 	// Now find a free breakpoint reg
       
  1228 	TInt breakreg = -1;
       
  1229 	if (iFreeHwBreakpoints & 8) breakreg = 3;
       
  1230 	if (iFreeHwBreakpoints & 4) breakreg = 2;
       
  1231 	if (iFreeHwBreakpoints & 2) breakreg = 1;
       
  1232 	if (iFreeHwBreakpoints & 1) breakreg = 0;
       
  1233 
       
  1234 	if (breakreg == -1) return KErrOverflow;
       
  1235 	aBreakpoint->iHardwareBreakpointId = breakreg;
       
  1236 
       
  1237 	TInt err = KErrNone;
       
  1238 #ifdef __SMP__
       
  1239 	// Have to apply to every CPU in turn
       
  1240 	const TInt num = NKern::NumberOfCpus();
       
  1241 	TUint32 origAffinity = 0;
       
  1242 	LOG("Applying breakpoint to all %d CPUs...", num);
       
  1243 	for (TInt i = 0; i < num; i++)
       
  1244 		{
       
  1245 		TUint32 affinity = NKern::ThreadSetCpuAffinity(&Kern::CurrentThread().iNThread, i);
       
  1246 		if (i == 0) origAffinity = affinity;
       
  1247 		err = DoApplyHardwareBreakpoint(aBreakpoint, contextReg);
       
  1248 		if (err)
       
  1249 			{
       
  1250 			// Disable the breakpoint on any CPUs we successfully applied it on
       
  1251 			for (TInt j = 0; j < i; j++)
       
  1252 				{
       
  1253 				NKern::ThreadSetCpuAffinity(&Kern::CurrentThread().iNThread, j);
       
  1254 				DoClearHardwareBreakpoint(aBreakpoint);
       
  1255 				}
       
  1256 			break;
       
  1257 			}
       
  1258 		}
       
  1259 	// Restore original affinity
       
  1260 	NKern::ThreadSetCpuAffinity(&Kern::CurrentThread().iNThread, origAffinity);
       
  1261 #else
       
  1262 	err = DoApplyHardwareBreakpoint(aBreakpoint, contextReg);
       
  1263 #endif
       
  1264 	if (err == KErrNone)
       
  1265 		{
       
  1266 		iFreeHwBreakpoints &= ~(1<<breakreg);
       
  1267 		}
       
  1268 	return err;
       
  1269 	}
       
  1270 
       
  1271 TInt DDebuggerEventHandler::DoApplyHardwareBreakpoint(SBreakpoint* aBreakpoint, TInt aContextReg)
       
  1272 	{
       
  1273 #if defined(__EABI__)
       
  1274 
       
  1275 #if defined(FSHELL_ARM_MEM_MAPPED_DEBUG)
       
  1276 	if (iDebugRegistersChunk == NULL)
       
  1277 		{
       
  1278 		// Need to setup mapping for debug registers
       
  1279 		TUint drar = GetDrar();
       
  1280 		TUint dsar = GetDsar();
       
  1281 		//Kern::Printf("drar=0x%08x dsar=0x%08x", drar, dsar);
       
  1282 		if ((dsar & 3) != 3)
       
  1283 			{
       
  1284 			Kern::Printf("fdbk: DSAR enabled bits are not set - aborting");
       
  1285 			return KErrNotSupported;
       
  1286 			}
       
  1287 		TPhysAddr physAddr = (drar & ~3) + (dsar & ~3); // We don't check validity of DRAR, TI set it incorrectly to 0x0 (invalid) on 3530
       
  1288 		if (physAddr == 0x52011000) physAddr = 0x54011000; // TI got this wrong too...
       
  1289 		const TInt KDebugRegSize = 0x10000; // 64K so we can reach DBGEN on 3530
       
  1290 		TUint attrib;
       
  1291 		new(&attrib) TMappingAttributes2(/*EMemAttNormalUncached*/ EMemAttStronglyOrdered, EFalse, ETrue);
       
  1292 		TInt err = DPlatChunkHw::New(iDebugRegistersChunk, physAddr, KDebugRegSize, attrib);
       
  1293 		if (err < 0)
       
  1294 			{
       
  1295 			Kern::Printf("fdbk: Error mapping debug registers - %d", err);
       
  1296 			return err;
       
  1297 			}
       
  1298 		LOG("debug registers from 0x%08x mapped at 0x%08x", physAddr, iDebugRegistersChunk->LinearAddress());
       
  1299 		}
       
  1300 #endif
       
  1301 
       
  1302 #if defined(FSHELL_ARM11XX_SUPPORT) || defined(FSHELL_ARM_MEM_MAPPED_DEBUG)
       
  1303 	// First. check debug status register (DSCR) to check that monitor mode is enabled (and thus that the BCRs are writeable)
       
  1304 	TUint dscr = GetDscr();
       
  1305 	//Kern::Printf("dscr=0x%08x", dscr);
       
  1306 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1307 	// Check for DBGEN (via authstatus register) too, we need it
       
  1308 	TUint authStatus = *(TUint32*)(iDebugRegistersChunk->LinearAddress() + 0xFB8);
       
  1309 	LOG("authStatus = 0x%08x", authStatus);
       
  1310 	if ((authStatus & 1) == 0)
       
  1311 		{
       
  1312 		// DBGEN not enabled - try the magic barely documented 3530 way of setting it
       
  1313 		LOG("Setting Lock Access Register");
       
  1314 		WriteRegister(ELockAccessOffset, 0xC5ACCE55);
       
  1315 
       
  1316 		Kern::Printf("Reading CONTROL_SEC_EMU from 0x48002A64...");
       
  1317 		TUint attrib;
       
  1318 		new(&attrib) TMappingAttributes2(/*EMemAttNormalUncached*/ EMemAttStronglyOrdered, EFalse, ETrue);
       
  1319 		DPlatChunkHw* crazyOmapRegs = NULL;
       
  1320 		DPlatChunkHw::New(crazyOmapRegs, 0x48002000, 0x1000, attrib);
       
  1321 		TUint32 controlsecemu = *(TUint32*)(crazyOmapRegs->LinearAddress() + 0xa64);
       
  1322 		Kern::Printf("CONTROL_SEC_EMU = 0x%08x", controlsecemu);
       
  1323 
       
  1324 		Kern::Printf("Trying 3530 approach to enabling DBGEN...");
       
  1325 		TUint32 volatile * dbgenWord = (TUint32*)(iDebugRegistersChunk->LinearAddress() + 0xc030);
       
  1326 		Kern::Printf("DBGEN word = 0x%08x", *dbgenWord);
       
  1327 		*dbgenWord |= (1 << 13); // Set bit 13 of 0x5401d030 is how you do it, apparently
       
  1328 		//*dbgenWord = 0xFFFFFFFF;
       
  1329 		// Now do as ASM says and DSB, poll for DSCR (or just wait a bit) then ISB
       
  1330 		Dsb();
       
  1331 		Kern::Printf("Wasting time waiting for dbgen....");
       
  1332 		Isb();
       
  1333 		Kern::Printf("DBGEN word is now 0x%08x", *dbgenWord);
       
  1334 		authStatus = *(TUint32*)(iDebugRegistersChunk->LinearAddress() + 0xFB8);
       
  1335 		Kern::Printf("authStatus is now 0x%08x", authStatus);
       
  1336 		}
       
  1337 #endif
       
  1338 	if ((dscr & 0xC000) != 0x8000)
       
  1339 		{
       
  1340 		// Set bits [15:14] to b10
       
  1341 		dscr = (dscr & ~0xC000) | 0x8000;
       
  1342 		//Kern::Printf("Setting monitor mode in DSCR...");
       
  1343 		SetDscr(dscr); // If there's a JTAG doing halt-mode debugging this is gonna crash. Oh well.
       
  1344 		}
       
  1345 	dscr = GetDscr();
       
  1346 	//Kern::Printf("dscr from MCR=0x%08x", dscr);		
       
  1347 
       
  1348 #else
       
  1349 	// Is ARM, but not ARM11 or A8
       
  1350 	(void)aBreakpoint;
       
  1351 	(void)aContextReg;
       
  1352 	return KErrNotSupported;
       
  1353 #endif
       
  1354 	
       
  1355 	TUint32 contextId = GetArmContextIdForThread(aBreakpoint->iThread);
       
  1356 	
       
  1357 	//Kern::Printf("fdbk: fdb thinks contextId is 0x%08x", contextId);
       
  1358 	//return KErrNotSupported; //DEBUG
       
  1359 
       
  1360 	SetContextIdBrp(aContextReg, contextId);
       
  1361 
       
  1362 	// Now need to construct the BCR register value
       
  1363 	const TUint32 KArmBcr = 0x001001E5;
       
  1364 	//const TUint32 KArmBcr = 0x000001E5; // DEBUG disable context match
       
  1365 	//TUint32 bcr = ReadBcr(aBreakReg);
       
  1366 	TUint32 bcr = KArmBcr;
       
  1367 	bcr |= aContextReg << 16;
       
  1368 	if (aBreakpoint->iFlags & SBreakpoint::EThumb)
       
  1369 		{
       
  1370 		const TUint32 KByteSelectMask = 0x1E0;
       
  1371 		// These assume a little-endian world
       
  1372 		const TUint32 KMiddleOfWordThumbByteSelect = 0x180; // [8:5] = b1100
       
  1373 		const TUint32 KWordAlignedThumbByteSelect = 0x060; // [8:5] = b0011
       
  1374 		bcr = bcr & ~KByteSelectMask;
       
  1375 		if (aBreakpoint->iAddress & 2)
       
  1376 			{
       
  1377 			bcr |= KMiddleOfWordThumbByteSelect;
       
  1378 			}
       
  1379 		else
       
  1380 			{
       
  1381 			bcr |= KWordAlignedThumbByteSelect;
       
  1382 			}
       
  1383 		}
       
  1384 
       
  1385 	SetBreakpointPair(aBreakpoint->iHardwareBreakpointId, aBreakpoint->iAddress & ~3, bcr);
       
  1386 	return KErrNone;
       
  1387 	
       
  1388 #else
       
  1389 	(void)aBreakpoint;
       
  1390 	(void)aContextReg;
       
  1391 	return KErrNotSupported;
       
  1392 #endif
       
  1393 	}
       
  1394 
       
  1395 TUint32 DDebuggerEventHandler::GetArmContextIdForThread(DThread* aThread)
       
  1396 	{
       
  1397 #if (defined(FSHELL_ARM11XX_SUPPORT) || defined(FSHELL_ARM_MEM_MAPPED_DEBUG)) && defined(__MARM__)
       
  1398 	// This is according to TScheduler::Reschedule (gulp)
       
  1399 	TUint asid = static_cast<DMemModelProcess*>(aThread->iOwningProcess)->iOsAsid;
       
  1400 	//TUint32 result = (((TUint32)&aThread->iNThread >> 6) << 8) | asid;
       
  1401 	TUint32 result = (TUint32)&aThread->iNThread;
       
  1402 	result = (result << 2) & ~0xFF;
       
  1403 	result |= (asid & 0xFF);
       
  1404 	return result;
       
  1405 #else
       
  1406 	(void)aThread;
       
  1407 	return 0;
       
  1408 #endif
       
  1409 	}
       
  1410 
       
  1411 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1412 
       
  1413 TUint32 DDebuggerEventHandler::ReadRegister(TInt aRegisterOffset)
       
  1414 	{
       
  1415 	return *(TUint32*)(iDebugRegistersChunk->LinearAddress() + aRegisterOffset);
       
  1416 	}
       
  1417 
       
  1418 void DDebuggerEventHandler::WriteRegister(TInt aRegisterOffset, TUint32 aValue)
       
  1419 	{
       
  1420 	TUint32* reg = (TUint32*)(iDebugRegistersChunk->LinearAddress() + aRegisterOffset);
       
  1421 	*reg = aValue;
       
  1422 	}
       
  1423 
       
  1424 #endif // FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1425 
       
  1426 #ifdef __EABI__
       
  1427 
       
  1428 void DDebuggerEventHandler::SetDscr(TUint32 aVal)
       
  1429 	{
       
  1430 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1431 	TUint32* dscrAddr = (TUint32*)(iDebugRegistersChunk->LinearAddress() + EDscrOffset);
       
  1432 	*dscrAddr = aVal;
       
  1433 #else
       
  1434 	MCR_SetDscr(aVal);
       
  1435 #endif
       
  1436 	}
       
  1437 
       
  1438 void DDebuggerEventHandler::SetBreakpointPair(TInt aRegister, TUint aBvrValue, TUint aBcrValue)
       
  1439 	{
       
  1440 	LOG("fdbk: SetBreakpointPair(reg=%d, bvr=0x%08x, bcr=0x%08x)", aRegister, aBvrValue, aBcrValue);
       
  1441 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1442 	// This is the sequence the ARM ARM recommends
       
  1443 	TUint32* bcrAddr = (TUint32*)(iDebugRegistersChunk->LinearAddress() + EBcrOffset + aRegister*4);
       
  1444 	TUint32* bvrAddr = (TUint32*)(iDebugRegistersChunk->LinearAddress() + EBvrOffset + aRegister*4);
       
  1445 
       
  1446 	// Disable the breakpoint
       
  1447 	//*bcrAddr = 0;
       
  1448 	//Imb();
       
  1449 	*bvrAddr = aBvrValue;
       
  1450 	*bcrAddr = aBcrValue;
       
  1451 #else
       
  1452 	MCR_SetBreakpointPair(aRegister, aBvrValue, aBcrValue);
       
  1453 #endif
       
  1454 	Imb();
       
  1455 	}
       
  1456 
       
  1457 TUint DDebuggerEventHandler::ReadBcr(TInt aRegister)
       
  1458 	{
       
  1459 //#ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1460 //	TUint32* bcrAddr = (TUint32*)(iDebugRegistersChunk->LinearAddress() + EBcrOffset + aRegister*4);
       
  1461 //	return *bcrAddr;
       
  1462 //#else
       
  1463 	return MRC_ReadBcr(aRegister);
       
  1464 //#endif
       
  1465 	}
       
  1466 
       
  1467 void DDebuggerEventHandler::SetContextIdBrp(TInt aRegister, TUint aContextId)
       
  1468 	{
       
  1469 #ifdef FSHELL_ARM_MEM_MAPPED_DEBUG
       
  1470 	// This is according to "ARM 13.3.9. CP14 c80-c85, Breakpoint Control Registers (BCR)"
       
  1471 	const TUint KContextIdBCR = 0x003001E7;
       
  1472 	SetBreakpointPair(aRegister, aContextId, KContextIdBCR);
       
  1473 #else
       
  1474 	LOG("SetContextIdBrp %d 0x%08x", aRegister, aContextId);
       
  1475 	MCR_SetContextIdBrp(aRegister, aContextId);
       
  1476 	Imb();
       
  1477 #endif
       
  1478 	}
       
  1479 
       
  1480 #endif
       
  1481 
       
  1482 void DDebuggerEventHandler::RemoveAllHardwareBreakpointsForThread(DThread* aThread)
       
  1483 	{
       
  1484 	BreakpointLock();
       
  1485 	for (SDblQueLink* link = iBreakpoints.First(); link != NULL && link != &iBreakpoints.iA;)
       
  1486 		{
       
  1487 		SBreakpoint* b = _LOFF(link, SBreakpoint, iLink);
       
  1488 		link=link->iNext; // Do this before potentially calling ClearBreakpoint, because that will delete the breakpoint, invalidating link
       
  1489 		if (b->IsHardware() && b->MatchesThread(aThread))
       
  1490 			{
       
  1491 			ClearBreakpoint(b);
       
  1492 			}
       
  1493 		}
       
  1494 	BreakpointUnlock();
       
  1495 	}
       
  1496 
       
  1497 TInt DDebuggerEventHandler::MoveBreakpointToNextInstructionForThread(DThread* aThread, SBreakpoint* aBreakpoint)
       
  1498 	{
       
  1499 #ifdef __EABI__
       
  1500 	ASSERT_BREAKPOINT_LOCKED();
       
  1501 	TUint32 notUsed = 0;
       
  1502 	TBool aModeChange = EFalse;
       
  1503 	TLinAddr nextAddr = PCAfterInstructionExecutes(aThread, aBreakpoint->iAddress, notUsed, aBreakpoint->iFlags & SBreakpoint::EThumb ? 2 : 4, notUsed, aModeChange);
       
  1504 	LOG("fdbk: Next instruction after %x is %x", aBreakpoint->iAddress, nextAddr);
       
  1505 
       
  1506 	RMemoryAccess::TPredicate alwaysPass;
       
  1507 	SBreakpoint* temp = new SBreakpoint(aThread, iNextBreakpointId, nextAddr, alwaysPass);
       
  1508 	if (!temp) return KErrNoMemory;
       
  1509 	iBreakpoints.Add(&temp->iLink);
       
  1510 
       
  1511 	const TBool hw = aBreakpoint->IsHardware();
       
  1512 	if (hw) UnapplyBreakpoint(aBreakpoint); // If it's hardware, it's ok to unapply it before adding the temp one because hw breakpoints are thread-specific. For software, we want the new one in place before we remove this one to make sure we don't miss stuff
       
  1513 
       
  1514 	TInt err = ApplyBreakpoint(temp, hw ? EHardwareOnly : ESoftwareOnly);
       
  1515 	if (err)
       
  1516 		{
       
  1517 		// This really shouldn't fail if hw - we still have the lock and we know there's a free BRP cos we just unapplied aBreakpoint
       
  1518 		temp->iLink.Deque();
       
  1519 		delete temp;
       
  1520 		return err;
       
  1521 		}
       
  1522 
       
  1523 	if (!hw) UnapplyBreakpoint(aBreakpoint);
       
  1524 
       
  1525 	aBreakpoint->iFlags |= SBreakpoint::EDisabledDuringContinue;
       
  1526 	temp->iFlags |= SBreakpoint::ETempContinue;
       
  1527 	temp->iRealBreakpoint = aBreakpoint;
       
  1528 	iNextBreakpointId++;
       
  1529 
       
  1530 	return KErrNone;
       
  1531 #else
       
  1532 	(void)aThread;
       
  1533 	(void)aBreakpoint;
       
  1534 	return KErrNotSupported;
       
  1535 #endif
       
  1536 	}
       
  1537 
       
  1538 
       
  1539 void DDebuggerEventHandler::SBreakpoint::SetThreadMatchPattern(HBuf* aMatch)
       
  1540 	{
       
  1541 	ASSERT(iMatch == NULL);
       
  1542 	ASSERT(iThread == NULL);
       
  1543 	ASSERT((iFlags & EThreadSpecific) == 0);
       
  1544 	iMatch = aMatch;
       
  1545 	}
       
  1546 
       
  1547 TBool DDebuggerEventHandler::SBreakpoint::MatchesThread(DThread* aThread) const
       
  1548 	{
       
  1549 	TBool match = EFalse;
       
  1550 
       
  1551 	if (iFlags & EThreadSpecific)
       
  1552 		{
       
  1553 		match = (aThread == iThread);
       
  1554 		}
       
  1555 	else if (iMatch == NULL)
       
  1556 		{
       
  1557 		match = ETrue;
       
  1558 		}
       
  1559 	else
       
  1560 		{
       
  1561 		TFullName threadName;
       
  1562 		aThread->FullName(threadName);
       
  1563 		match = threadName.MatchF(*iMatch);
       
  1564 		}
       
  1565 
       
  1566 	if (match && iCondition.HasConditions())
       
  1567 		{
       
  1568 #ifdef __MARM__
       
  1569 		TUint32 regs[32];
       
  1570 		TUint32 valid = 0;
       
  1571 		NKern::ThreadGetUserContext(&aThread->iNThread, &regs[0], valid);
       
  1572 		match = iCondition.SatisfiesConditions(regs);
       
  1573 #endif
       
  1574 		}
       
  1575 	return match;
       
  1576 	}
       
  1577 
       
  1578 //
       
  1579 
       
  1580 const TUint32 KOpMask = 0xF;
       
  1581 
       
  1582 TBool RMemoryAccess::TPredicate::SatisfiesConditions(TUint32* aRegisterSet) const
       
  1583 	{
       
  1584 	for (TInt slot = 0; slot < KNumSlots; slot++)
       
  1585 		{
       
  1586 		TInt slotShift = slot * 8;
       
  1587 		TUint32 opAndReg = (iOp >> slotShift) & 0xFF;
       
  1588 		TOp op = (TOp)(opAndReg & KOpMask);
       
  1589 		TInt reg = opAndReg >> 4;
       
  1590 		TBool match = Test(op, aRegisterSet[reg], iVals[slot]);
       
  1591 		if (!match) return EFalse;
       
  1592 		}
       
  1593 	return ETrue;
       
  1594 	}
       
  1595 
       
  1596 TBool RMemoryAccess::TPredicate::Test(TOp aOperation, TUint32 aCurrentValue, TUint32 aStoredValue)
       
  1597 	{
       
  1598 	LOG("Testing op %d %u against %u", aOperation, aCurrentValue, aStoredValue);
       
  1599 
       
  1600 	switch (aOperation)
       
  1601 		{
       
  1602 		case ENothing:
       
  1603 			return ETrue;
       
  1604 		case EEq:
       
  1605 		case ESignedEq:
       
  1606 			return (aCurrentValue == aStoredValue);
       
  1607 		case ENe:
       
  1608 		case ESignedNe:
       
  1609 			return (aCurrentValue != aStoredValue);
       
  1610 		case ELt:
       
  1611 			return (aCurrentValue < aStoredValue);
       
  1612 		case ELe:
       
  1613 			return (aCurrentValue <= aStoredValue);
       
  1614 		case EGt:
       
  1615 			return (aCurrentValue > aStoredValue);
       
  1616 		case EGe:
       
  1617 			return (aCurrentValue >= aStoredValue);
       
  1618 		case ESignedLt:
       
  1619 			return ((TInt32)aCurrentValue < (TInt32)aStoredValue);
       
  1620 		case ESignedLe:
       
  1621 			return ((TInt32)aCurrentValue <= (TInt32)aStoredValue);
       
  1622 		case ESignedGt:
       
  1623 			return ((TInt32)aCurrentValue > (TInt32)aStoredValue);
       
  1624 		case ESignedGe:
       
  1625 			return ((TInt32)aCurrentValue >= (TInt32)aStoredValue);
       
  1626 		}
       
  1627 	return EFalse; // Compiler shutter-upper
       
  1628 	}
       
  1629 
       
  1630 TUint DDebuggerEventHandler::GetCreatorThread(TUint aThreadId)
       
  1631 	{
       
  1632 	TCreatorInfo dummy(aThreadId, 0);
       
  1633 	TUint result = 0;
       
  1634 	BreakpointLock();
       
  1635 	TInt found = iCreatorInfo.FindInUnsignedKeyOrder(dummy);
       
  1636 	if (found != KErrNotFound)
       
  1637 		{
       
  1638 		result = iCreatorInfo[found].iCreatorThreadId;
       
  1639 		}
       
  1640 	BreakpointUnlock();
       
  1641 	return result;
       
  1642 	}