1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_rmd_breakpoints.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1741 @@
1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +
1.20 +#include <e32def.h>
1.21 +#include <e32def_private.h>
1.22 +#include <e32cmn.h>
1.23 +#include <e32cmn_private.h>
1.24 +#include <u32std.h>
1.25 +#include <kernel/kernel.h>
1.26 +#include <kernel/kern_priv.h>
1.27 +#include <nk_trace.h>
1.28 +#include <arm.h>
1.29 +#include <kernel/cache.h>
1.30 +#include <platform.h>
1.31 +#include <nkern.h>
1.32 +#include <u32hal.h>
1.33 +
1.34 +#include <rm_debug_api.h>
1.35 +#include <sm_debug_api.h>
1.36 +#include "d_rmd_breakpoints.h"
1.37 +#include "d_process_tracker.h"
1.38 +#include "d_rmd_stepping.h"
1.39 +#include "rm_debug_kerneldriver.h" // needed to access DRM_DebugChannel
1.40 +#include "rm_debug_driver.h"
1.41 +#include "debug_utils.h"
1.42 +#include "debug_logging.h"
1.43 +
1.44 +using namespace Debug;
1.45 +
1.46 +/* @internalTechnology
1.47 + *
1.48 + * Checks whether aAddress is correctly aligned for placing a breakpoint of
1.49 + * cpu architecture aMode.
1.50 + *
1.51 + * @param aAddress - Virtual memory address to check
1.52 + * @param aMode - The CPU architecture mode of the breakpoint to be placed at aAddress
1.53 + * @return ETrue if aAddress is suitably aligned, EFalse otherwise.
1.54 + */
1.55 +TBool D_RMD_Breakpoints::Aligned(TUint32 aAddress, Debug::TArchitectureMode aMode)
1.56 + {
1.57 + switch(aMode)
1.58 + {
1.59 + case Debug::EArmMode:
1.60 + // ARM breakpoints must be 32-bit aligned (lower two bits must be zero)
1.61 + if (aAddress & 0x3)
1.62 + {
1.63 + // Not 32-bit aligned.
1.64 + return EFalse;
1.65 + }
1.66 + break;
1.67 + case Debug::EThumbMode:
1.68 + // Thumb breakpoints must be 16-bit aligned (low bit must be zero)
1.69 + if (aAddress & 0x1)
1.70 + {
1.71 + // Not 16-bit aligned
1.72 + return EFalse;
1.73 + }
1.74 + break;
1.75 + case Debug::EThumb2EEMode:
1.76 + // Thumb-EE instructions are half-word aligned. See ARM ARM DDI0406A, section A3.2 Alignment Support
1.77 + // Note that some instructions need to be word-aligned, but this function does not know which ones.
1.78 + // It may also depend on the System Control register U bit.
1.79 + if (aAddress & 0x1)
1.80 + {
1.81 + // Not 16-bit aligned
1.82 + return EFalse;
1.83 + }
1.84 + break;
1.85 + default:
1.86 + {
1.87 + // No idea
1.88 + return EFalse;
1.89 + }
1.90 + }
1.91 +
1.92 + // Must be OK
1.93 + return ETrue;
1.94 + };
1.95 +
1.96 +/* @internalTechnology
1.97 + *
1.98 + * Returns the size of a breakpoint of architecture aMode in bytes
1.99 + *
1.100 + * @param aMode - The architure of the breakpoint
1.101 + * @return The size of the breakpoints in bytes. 0 if un-recognised architecture.
1.102 + */
1.103 +TInt D_RMD_Breakpoints::BreakSize(Debug::TArchitectureMode aMode)
1.104 + {
1.105 + switch(aMode)
1.106 + {
1.107 + case Debug::EArmMode:
1.108 + {
1.109 + return 4;
1.110 + }
1.111 + case Debug::EThumbMode:
1.112 + {
1.113 + return 2;
1.114 + }
1.115 + case Debug::EThumb2EEMode:
1.116 + {
1.117 + // Only needs to be two bytes in size.
1.118 + return 2;
1.119 + }
1.120 + default:
1.121 + {
1.122 + // No idea
1.123 + return 0;
1.124 + }
1.125 + }
1.126 + };
1.127 +
1.128 +/* @internalTechnology
1.129 + *
1.130 + * Checks whether two TBreakEntrys overlap
1.131 + *
1.132 + * @param aFirst - A TBreakEntry with valid iAddress and iMode fields.
1.133 + * @param aSecond - A TBreakEntry with valid iAddress and iMode fields.
1.134 + * @return ETrue if the aFirst and aSecond overlap or the overlap cannot be determined
1.135 + * , EFalse otherwise
1.136 + */
1.137 +TBool D_RMD_Breakpoints::BreakpointsOverlap(TBreakEntry& aFirst, TBreakEntry& aSecond)
1.138 + {
1.139 + TInt firstSize = BreakSize(aFirst.iMode);
1.140 + TInt secondSize = BreakSize(aSecond.iMode);
1.141 +
1.142 + // Do we know the size of each breakpoint?
1.143 + if ((firstSize <= 0) || (secondSize <= 0))
1.144 + {
1.145 + // We don't know the size of the breakpoint, so assume they overlap
1.146 + return ETrue;
1.147 + }
1.148 +
1.149 + TInt firstStartAddress = aFirst.iAddress;
1.150 + TInt secondStartAddress = aSecond.iAddress;
1.151 + TInt firstEndAddress = firstStartAddress + firstSize - 1;
1.152 + TInt secondEndAddress = secondStartAddress + secondSize - 1;
1.153 +
1.154 + // If second breakpoint is past the end of the first then we're ok
1.155 + if(firstEndAddress < secondStartAddress)
1.156 + {
1.157 + return EFalse;
1.158 + }
1.159 +
1.160 + // If first breakpoint is past the end of the second then we're ok
1.161 + if(secondEndAddress < firstStartAddress)
1.162 + {
1.163 + return EFalse;
1.164 + }
1.165 +
1.166 + // The breakpoints overlap
1.167 + return ETrue;
1.168 + }
1.169 +
1.170 +/* @internalTechnology
1.171 + *
1.172 + * Returns the breakpoint bitpattern to use for each architecture type
1.173 + *
1.174 + * @param aMode - the cpu architecture type
1.175 + * @return The bit-pattern to use for the specified architecture, or 0 if unsupported.
1.176 + */
1.177 +TUint32 D_RMD_Breakpoints::BreakInst(Debug::TArchitectureMode aMode)
1.178 + {
1.179 + switch(aMode)
1.180 + {
1.181 + case Debug::EArmMode:
1.182 + {
1.183 + return KArmBreakPoint;
1.184 + }
1.185 + case Debug::EThumbMode:
1.186 + {
1.187 + return KThumbBreakPoint;
1.188 + }
1.189 + case Debug::EThumb2EEMode:
1.190 + {
1.191 + return KT2EEBreakPoint;
1.192 + }
1.193 + default:
1.194 + {
1.195 + // No idea what the breakpoint should be
1.196 + return 0;
1.197 + }
1.198 + }
1.199 + };
1.200 +
1.201 +/**
1.202 +Constructor. Initialises its internal list of empty breakpoints.
1.203 +*/
1.204 +D_RMD_Breakpoints::D_RMD_Breakpoints(DRM_DebugChannel* aChannel)
1.205 +: iBreakPointList(NUMBER_OF_TEMP_BREAKPOINTS, 0),
1.206 + iNextBreakId(NUMBER_OF_TEMP_BREAKPOINTS),
1.207 + iChannel(aChannel),
1.208 + iInitialised(EFalse)
1.209 + {
1.210 + iBreakPointList.Reset();
1.211 + TBreakEntry emptyTempBreak;
1.212 +
1.213 + for (TInt i = 0; i < NUMBER_OF_TEMP_BREAKPOINTS; i++)
1.214 + {
1.215 + emptyTempBreak.iBreakId = i;
1.216 +
1.217 + if (KErrNone != iBreakPointList.Append(emptyTempBreak))
1.218 + {
1.219 + LOG_MSG("D_RMD_Breakpoints::D_RMD_Breakpoints() - Error appending blank temp break entry");
1.220 + }
1.221 + }
1.222 + }
1.223 +
1.224 +/**
1.225 +Destructor. Clears all the breakpoints in the system, deletes its internal list of breakpoints,
1.226 +and closes the exclusivity semaphore.
1.227 +*/
1.228 +D_RMD_Breakpoints::~D_RMD_Breakpoints()
1.229 + {
1.230 + ClearAllBreakPoints();
1.231 +
1.232 + // close the breakpoint list and free the memory associated with it
1.233 + iBreakPointList.Close();
1.234 +
1.235 + if (iLock)
1.236 + iLock->Close(NULL);
1.237 + }
1.238 +
1.239 +/**
1.240 +Initialises the breakpoint list exclusion semaphore. This should be called once immediately after
1.241 +the constructor.
1.242 +
1.243 +@return KErrNone if successful, one of the other system wide error codes otherwise.
1.244 +*/
1.245 +TInt D_RMD_Breakpoints::Init()
1.246 + {
1.247 + TInt err = KErrNone;
1.248 +
1.249 + // Only create a semaphore if we are not initialised
1.250 + if(!iInitialised)
1.251 + {
1.252 + // Initialise the semaphore ensuring exclusive access to the breakpoint list
1.253 + err = Kern::SemaphoreCreate(iLock, _L("RM_DebugBreakpointLock"), 1 /* Initial count */);
1.254 + if (err == KErrNone)
1.255 + {
1.256 + iInitialised = ETrue;
1.257 + }
1.258 + }
1.259 + else
1.260 + {
1.261 + err = KErrNone;
1.262 + }
1.263 +
1.264 + return err;
1.265 + }
1.266 +
1.267 +/**
1.268 +Public member function which sets a thread-specific breakpoint in the specified thread
1.269 +and returns an opaque handle to the caller.
1.270 +
1.271 +Note 1:
1.272 +This function ensures exclusive access to the breakpoint data structures
1.273 +by using a semaphore to serialise access.
1.274 +
1.275 +@see priv_DoSetBreak
1.276 +
1.277 +Note 2:
1.278 +As implied by Note 1, the caller must have previously called Init() or this
1.279 +function will return KErrNotReady;
1.280 +
1.281 +@param aBreakId - Reference to a TUint32 into which the function will return a unique breakpoint Id.
1.282 +@param aThreadId - The thread Id in which to place the breakpoint
1.283 +@param aAddress - Address to place the breakpoint
1.284 +@param aMode - The cpu instruction set architecture type breakpoint (e.g. EArmMode or EThumbMode)
1.285 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.286 +*/
1.287 +TInt D_RMD_Breakpoints::DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const TArchitectureMode aMode)
1.288 + {
1.289 + // Ensure we have a valid semaphore
1.290 + if (!iInitialised || !iLock)
1.291 + {
1.292 + return KErrNotReady;
1.293 + }
1.294 +
1.295 + // Acquire the lock
1.296 + NKern::ThreadEnterCS();
1.297 + Kern::SemaphoreWait(*iLock);
1.298 +
1.299 + // Really do the work
1.300 + TInt err = priv_DoSetBreak(aBreakId, aId, aThreadSpecific, aAddress,aMode);
1.301 +
1.302 + // Release the lock
1.303 + Kern::SemaphoreSignal(*iLock);
1.304 + NKern::ThreadLeaveCS();
1.305 +
1.306 + return err;
1.307 + }
1.308 +/**
1.309 +Private member function which sets a thread-specific breakpoint in the specified thread
1.310 +and returns an opaque handle to the caller.
1.311 +
1.312 +@see DoSetBreak
1.313 +
1.314 +@param aBreakId - Reference to a TUint32 into which the function will return a unique breakpoint Id.
1.315 +@param aThreadId - The thread Id in which to place the breakpoint
1.316 +@param aAddress - Address to place the breakpoint
1.317 +@param aMode - The cpu instruction set architecture type breakpoint (e.g. EArmMode or EThumbMode)
1.318 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.319 +*/
1.320 +TInt D_RMD_Breakpoints::priv_DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const TArchitectureMode aMode)
1.321 + {
1.322 + LOG_MSG4("D_RMD_Breakpoints::priv_DoSetBreak(aThreadId = 0x%016lx, aAddress = 0x%08x, aMode = %d)",aId,aAddress,aMode);
1.323 +
1.324 + // EThumb2EEMode breakpoints are not supported
1.325 + if (EThumb2EEMode == aMode)
1.326 + {
1.327 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - EThumb2EEMode breakpoints are not supported");
1.328 + return KErrNotSupported;
1.329 + }
1.330 +
1.331 + // Check how many breakpoints we have in existence
1.332 + if ((iBreakPointList.Count()+1) >= NUMBER_OF_MAX_BREAKPOINTS)
1.333 + {
1.334 + // Too many breakpoints are set!
1.335 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Too many breakpoints set");
1.336 + return KErrOverflow;
1.337 + }
1.338 +
1.339 + // check the alignment of the breakpoint
1.340 + if (!Aligned(aAddress,aMode))
1.341 + {
1.342 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Unaligned address");
1.343 + return KErrArgument;
1.344 + }
1.345 +
1.346 + // make sure there is not already a breakpoint at this address
1.347 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.348 + {
1.349 + /* We need to check if the breakpoint overlaps the address at all,
1.350 + * and this depends upon the size of the two breakpoints as well as
1.351 + * their address.
1.352 + */
1.353 +
1.354 + // newInstSize = size in bytes of new breakpoint
1.355 + TInt newInstSize = BreakSize(aMode);
1.356 + if (newInstSize == 0)
1.357 + {
1.358 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Unknown architecture type for new breakpoint");
1.359 + return KErrNotSupported;
1.360 + }
1.361 +
1.362 + // oldInstSize = size in bytes of the existing breakpoint
1.363 + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode);
1.364 + if (oldInstSize == 0)
1.365 + {
1.366 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - : Unknown architecture type of existing breakpoint");
1.367 + return KErrNotSupported;
1.368 + }
1.369 +
1.370 + // Overlap checking - temp is used as the new breakpoint description for checking purposes only
1.371 + TBreakEntry temp;
1.372 +
1.373 + temp.iAddress = aAddress;
1.374 + temp.iMode = aMode;
1.375 +
1.376 + // do they overlap?
1.377 + if ( BreakpointsOverlap(temp,iBreakPointList[i]) )
1.378 + {
1.379 + // Yes
1.380 + if(iBreakPointList[i].iThreadSpecific && aThreadSpecific)
1.381 + {
1.382 + if(aId == iBreakPointList[i].iId)
1.383 + {
1.384 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New thread specific breakpoint overlaps an existing thread specific breakpoint");
1.385 + return KErrAlreadyExists;
1.386 + }
1.387 + }
1.388 + else if(!iBreakPointList[i].iThreadSpecific && aThreadSpecific)
1.389 + {
1.390 + DThread* thread = DebugUtils::OpenThreadHandle(aId);
1.391 + if(!thread)
1.392 + {
1.393 + return KErrNotFound;
1.394 + }
1.395 + if(thread->iOwningProcess->iId == iBreakPointList[i].iId)
1.396 + {
1.397 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New thread specific breakpoint overlaps an existing breakpoint");
1.398 + thread->Close(NULL);
1.399 + return KErrAlreadyExists;
1.400 + }
1.401 + thread->Close(NULL);
1.402 + }
1.403 + else if(iBreakPointList[i].iThreadSpecific && !aThreadSpecific)
1.404 + {
1.405 + DThread* thread = DebugUtils::OpenThreadHandle(iBreakPointList[i].iId);
1.406 + if(!thread)
1.407 + {
1.408 + return KErrNotFound;
1.409 + }
1.410 + if(thread->iOwningProcess->iId == aId)
1.411 + {
1.412 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New breakpoint overlaps an existing thread specific breakpoint");
1.413 + thread->Close(NULL);
1.414 + return KErrAlreadyExists;
1.415 + }
1.416 + thread->Close(NULL);
1.417 + }
1.418 + else // !iBreakPointList[i].iThreadSpecific && !aThreadSpecific
1.419 + {
1.420 + if(iBreakPointList[i].iId == aId)
1.421 + {
1.422 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New breakpoint overlaps an existing breakpoint");
1.423 + return KErrAlreadyExists;
1.424 + }
1.425 + }
1.426 + }
1.427 + }
1.428 +
1.429 + // increment the break id
1.430 + aBreakId = iNextBreakId++;
1.431 +
1.432 + // create the new breakpoint entry
1.433 + TBreakEntry breakEntry(aBreakId, aId, aThreadSpecific, aAddress, aMode);
1.434 +
1.435 + TInt err = priv_DoEnableBreak(breakEntry, ETrue);
1.436 + if (KErrNone != err)
1.437 + {
1.438 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Could not enable the breakpoint");
1.439 +
1.440 + return err;
1.441 + }
1.442 +
1.443 + err = iBreakPointList.Append(breakEntry);
1.444 + if (err != KErrNone)
1.445 + {
1.446 + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Failed to append breakpoint");
1.447 + }
1.448 +
1.449 + LOG_MSG2("D_RMD_Breakpoints::priv_DoSetBreak(breakId = 0x%08x) done",aBreakId);
1.450 +
1.451 + return err;
1.452 + }
1.453 +
1.454 +/**
1.455 +Public member function which enables a previously set breakpoint.
1.456 +
1.457 +Note 1:
1.458 +This function ensures exclusive access to the breakpoint data structures
1.459 +by using a semaphore to serialise access.
1.460 +
1.461 +@see priv_DoEnableBreak
1.462 +
1.463 +Note 2:
1.464 +As implied by Note 1, the caller must have previously called Init() or this
1.465 +function will return KErrNotReady;
1.466 +
1.467 +Note 3
1.468 +Historically, this function accepted a reference to a TBreakEntry in the class' own
1.469 +iBreakPointList. It now checks whether the reference is to an element of its own list,
1.470 +or one invented by the caller.
1.471 +
1.472 +@param aEntry reference to a TBreakEntry datastructure describing the breakpoint to be re-enabled.
1.473 +@param aSaveOldInstruction ETrue preserves the instruction at the breakpoint address, EFalse otherwise.
1.474 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.475 +*/
1.476 +TInt D_RMD_Breakpoints::DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction)
1.477 + {
1.478 + // Ensure we have a valid semaphore
1.479 + if (!iInitialised || !iLock)
1.480 + {
1.481 + return KErrNotReady;
1.482 + }
1.483 +
1.484 + // Acquire the lock
1.485 + NKern::ThreadEnterCS();
1.486 + Kern::SemaphoreWait(*iLock);
1.487 +
1.488 + // Really do the work
1.489 + TInt err = priv_DoEnableBreak(aEntry,aSaveOldInstruction);
1.490 +
1.491 + // Release the lock
1.492 + Kern::SemaphoreSignal(*iLock);
1.493 + NKern::ThreadLeaveCS();
1.494 +
1.495 + return err;
1.496 + }
1.497 +
1.498 +/**
1.499 +Private member function which enables a previously set breakpoint, as per DoEnableBreak, but
1.500 +does not serialise access.
1.501 +
1.502 +@see DoEnableBreak
1.503 +
1.504 +@param aEntry reference to a TBreakEntry datastructure describing the breakpoint to be re-enabled.
1.505 +@param aSaveOldInstruction ETrue preserves the instruction at the breakpoint address, EFalse otherwise.
1.506 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.507 +*/
1.508 +TInt D_RMD_Breakpoints::priv_DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction)
1.509 + {
1.510 + LOG_MSG("D_RMD_Breakpoints::DoEnableBreak()");
1.511 +
1.512 + TUint32 inst = BreakInst(aEntry.iMode);
1.513 + TInt instSize = BreakSize(aEntry.iMode);
1.514 + if (instSize == 0 || inst == 0)
1.515 + {
1.516 + // not supported
1.517 + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak - unsupported breakpoint architecture");
1.518 + return KErrNotSupported;
1.519 + }
1.520 +
1.521 + TInt err = KErrNone;
1.522 +
1.523 + // Get thread id
1.524 + TUint64 threadId = aEntry.iId + (aEntry.iThreadSpecific ? 0 : 1);
1.525 +
1.526 + DThread* threadObj = DebugUtils::OpenThreadHandle(threadId);
1.527 + if (!threadObj)
1.528 + {
1.529 + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak - bad handle. Could not identify a threadObj");
1.530 + return KErrBadHandle;
1.531 + }
1.532 +
1.533 + if (aSaveOldInstruction)
1.534 + {
1.535 + TUint32 instruction;
1.536 +
1.537 + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint
1.538 + // trap exceptions in case the address is invalid
1.539 + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)aEntry.iAddress, (TAny *)&instruction, instSize));
1.540 +
1.541 + //consider the leave as more important than the error code so store the leave if it's not KErrNone
1.542 + if(KErrNone != r)
1.543 + {
1.544 + err = r;
1.545 + }
1.546 +
1.547 + if(KErrNone != err)
1.548 + {
1.549 + threadObj->Close(NULL);
1.550 + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak() - failed to read memory");
1.551 + return err;
1.552 + }
1.553 +
1.554 + aEntry.iInstruction.Copy((TUint8 *)&instruction, instSize);
1.555 + }
1.556 +
1.557 + TBool breakpointAlredySet = EFalse;
1.558 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.559 + {
1.560 + if(iBreakPointList[i].iAddress == aEntry.iAddress && !iBreakPointList[i].iDisabledForStep )
1.561 + {
1.562 + breakpointAlredySet = ETrue;
1.563 + break;
1.564 + }
1.565 + }
1.566 + if(!breakpointAlredySet)
1.567 + {
1.568 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, aEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal));
1.569 + if(r != DebugSupport::EBreakpointGlobal)
1.570 + {
1.571 + err = r;
1.572 + }
1.573 + }
1.574 +
1.575 + // Close the thread handle which has been opened by OpenThreadHandle
1.576 + threadObj->Close(NULL);
1.577 +
1.578 + return err;
1.579 + }
1.580 +
1.581 +/**
1.582 +Public member function which clears a previously set breakpoint.
1.583 +
1.584 +Note 1:
1.585 +This function ensures exclusive access to the breakpoint data structures
1.586 +by using a semaphore to serialise access.
1.587 +
1.588 +@see priv_DoClearBreak
1.589 +
1.590 +Note 2:
1.591 +As implied by Note 1, the caller must have previously called Init() or this
1.592 +function will return KErrNotReady;
1.593 +
1.594 +@param aBreakId A breakpoint Id as previously returned by DoSetBreak.
1.595 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.596 +*/
1.597 +TInt D_RMD_Breakpoints::DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads)
1.598 + {
1.599 + // Ensure we have a valid semaphore
1.600 + if (!iInitialised || !iLock)
1.601 + {
1.602 + return KErrNotReady;
1.603 + }
1.604 +
1.605 + // Acquire the lock
1.606 + NKern::ThreadEnterCS();
1.607 + Kern::SemaphoreWait(*iLock);
1.608 +
1.609 + // Really do the work
1.610 + TInt err = priv_DoClearBreak(aBreakId, aIgnoreTerminatedThreads);
1.611 +
1.612 + // Release the lock
1.613 + Kern::SemaphoreSignal(*iLock);
1.614 + NKern::ThreadLeaveCS();
1.615 +
1.616 + return err;
1.617 + }
1.618 +
1.619 +/**
1.620 +Private member function which clears a previously set breakpoint, as per DoClearBreak, but
1.621 +does not serialise access.
1.622 +
1.623 +@see DoClearBreak
1.624 +
1.625 +@param aBreakId A breakpoint Id as previously returned by DoSetBreak.
1.626 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.627 +*/
1.628 +TInt D_RMD_Breakpoints::priv_DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads)
1.629 + {
1.630 + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak(0x%08x)",aBreakId);
1.631 +
1.632 + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id
1.633 + TBreakEntry entry;
1.634 + entry.iBreakId = aBreakId;
1.635 + TInt index = iBreakPointList.FindInSignedKeyOrder(entry);
1.636 +
1.637 + TInt err = KErrNone;
1.638 + if (index >= 0)
1.639 + {
1.640 + //only let the agent clear the break if they have previously suspended the thread
1.641 + //iThreadSpecific value decides whether the the iBreakPointList.Id has a thread id(TID) or the process id(PID)
1.642 + //the assumption here that TID = PID + 1
1.643 + if(!TheDProcessTracker.CheckSuspended((iBreakPointList[index].iId + (iBreakPointList[index].iThreadSpecific ? 0 : 1))))
1.644 + {
1.645 + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - Thread with id 0x%08x not suspended", iBreakPointList[index].iId);
1.646 + // should be "return KErrInUse;" but not always possible, e.g. cleaning up threads which die after debugger disconnects
1.647 + }
1.648 + // if this breakpoint was set in a library and that library has already been unloaded, don't try to clear it
1.649 + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint)
1.650 + {
1.651 + DThread* threadObj = DebugUtils::OpenThreadHandle(iBreakPointList[index].iId + (iBreakPointList[index].iThreadSpecific ? 0 : 1));
1.652 + if (threadObj)
1.653 + {
1.654 + TBool needToCallCodeModifier = ETrue;
1.655 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.656 + {
1.657 + if (i != index)
1.658 + {
1.659 + if ( BreakpointsOverlap(iBreakPointList[index],iBreakPointList[i]) )
1.660 + {
1.661 + needToCallCodeModifier = EFalse;
1.662 + break;
1.663 + }
1.664 + }
1.665 + }
1.666 + if(needToCallCodeModifier)
1.667 + {
1.668 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress));
1.669 + if (r != KErrNone)
1.670 + {
1.671 + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - restore code trap harness returned error %d",r);
1.672 + }
1.673 +
1.674 + if (err != KErrNone)
1.675 + {
1.676 + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - restore code returned error %d",err);
1.677 + }
1.678 + err = (KErrNone == r) ? err : r;
1.679 + }
1.680 +
1.681 + // Close the thread handle opened by OpenThreadHandle
1.682 + threadObj->Close(NULL);
1.683 + }
1.684 + else
1.685 + {
1.686 + err = KErrBadHandle;
1.687 + }
1.688 + }
1.689 +
1.690 + LOG_MSG4("D_RMD_Breakpoints::priv_DoClearBreak() - Clearing breakpoint at address: %x, err: %d, ignore terminated: %d", iBreakPointList[index].iAddress, err, aIgnoreTerminatedThreads?1:0);
1.691 + if ((aIgnoreTerminatedThreads && KErrBadHandle == err) || KErrNone == err)
1.692 + {
1.693 + // if this is a temp breakpoint, just clear out the values, otherwise remove it from the list
1.694 + err = KErrNone;
1.695 + if (index < NUMBER_OF_TEMP_BREAKPOINTS)
1.696 + {
1.697 + iBreakPointList[index].Reset();
1.698 + }
1.699 + else
1.700 + {
1.701 + LOG_MSG3("D_RMD_Breakpoints::priv_DoClearBreak() - Removing breakpoint 0x%08x as breakid 0x%08x\n",index, entry.iBreakId);
1.702 + iBreakPointList.Remove(index);
1.703 + }
1.704 + }
1.705 +
1.706 + return err;
1.707 + }
1.708 +
1.709 + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - Break Id %d not found", aBreakId);
1.710 +
1.711 + return KErrNotFound;
1.712 + }
1.713 +
1.714 +/**
1.715 +Public member function which modifies a previously set breakpoint.
1.716 +
1.717 +Note 1:
1.718 +This function ensures exclusive access to the breakpoint data structures
1.719 +by using a semaphore to serialise access.
1.720 +
1.721 +@see priv_DoModifyBreak
1.722 +
1.723 +Note 2:
1.724 +As implied by Note 1, the caller must have previously called Init() or this
1.725 +function will return KErrNotReady;
1.726 +
1.727 +@param aBreakInfo A TModifyBreakInfo describing the breakpoint properties that are wanted.
1.728 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.729 +*/
1.730 +TInt D_RMD_Breakpoints::DoModifyBreak(TModifyBreakInfo* aBreakInfo)
1.731 + {
1.732 + // Ensure we have a valid semaphore
1.733 + if (!iInitialised || !iLock)
1.734 + {
1.735 + return KErrNotReady;
1.736 + }
1.737 +
1.738 + // Acquire the lock
1.739 + NKern::ThreadEnterCS();
1.740 + Kern::SemaphoreWait(*iLock);
1.741 +
1.742 + // Really do the work
1.743 + TInt err = priv_DoModifyBreak(aBreakInfo);
1.744 +
1.745 + // Release the lock
1.746 + Kern::SemaphoreSignal(*iLock);
1.747 + NKern::ThreadLeaveCS();
1.748 +
1.749 + return err;
1.750 + }
1.751 +
1.752 +/**
1.753 +Private member function which modifies a previously set breakpoint, as per DoModifyBreak, but
1.754 +does not serialise access.
1.755 +
1.756 +@see DoModifyBreak
1.757 +
1.758 +@param aBreakInfo A TModifyBreakInfo describing the breakpoint properties that are wanted.
1.759 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.760 +*/
1.761 +TInt D_RMD_Breakpoints::priv_DoModifyBreak(TModifyBreakInfo* aBreakInfo)
1.762 + {
1.763 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak()");
1.764 +
1.765 + // Check arguments
1.766 + if (!aBreakInfo)
1.767 + {
1.768 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() was passed a NULL argument");
1.769 + return KErrArgument;
1.770 + }
1.771 +
1.772 + //User side memory is not accessible directly
1.773 + TSetBreakInfo info;
1.774 + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TSetBreakInfo));
1.775 + if (err != KErrNone)
1.776 + {
1.777 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() was passed a bad argument");
1.778 + return err;
1.779 + }
1.780 +
1.781 + // EThumb2EEMode breakpoints are not supported
1.782 + if (EThumb2EEMode == info.iMode)
1.783 + {
1.784 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - EThumb2EEMode breakpoints are not supported");
1.785 + return KErrNotSupported;
1.786 + }
1.787 +
1.788 + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id
1.789 + TBreakEntry entry;
1.790 + entry.iBreakId = (TUint32)info.iBreakId;
1.791 + TInt index = iBreakPointList.FindInSignedKeyOrder(entry);
1.792 + if (index < 0)
1.793 + {
1.794 + // Could not find the breakpoint
1.795 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak() - Could not find the breakpoint id 0x%08x",(TUint32)info.iBreakId);
1.796 + return KErrNotFound;
1.797 + }
1.798 +
1.799 + //assert that the thread we're moving the break from is suspended
1.800 + if(!TheDProcessTracker.CheckSuspended(iBreakPointList[index].iId))
1.801 + {
1.802 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak() - Thread with id 0x%08x not suspended", iBreakPointList[index].iId);
1.803 + return KErrInUse;
1.804 + }
1.805 +
1.806 + //assert that the thread we're moving the break to is suspended
1.807 + if(!TheDProcessTracker.CheckSuspended(info.iId))
1.808 + {
1.809 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak() - Thread with id 0x%08x not suspended", info.iId);
1.810 + return KErrInUse;
1.811 + }
1.812 +
1.813 + // first check its not obsolete
1.814 + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint)
1.815 + {
1.816 + // its still a valid breakpoint
1.817 +
1.818 + // remove the old breakpoint
1.819 + DThread* threadObj = DebugUtils::OpenThreadHandle(iBreakPointList[index].iId);
1.820 + if (threadObj)
1.821 + {
1.822 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak - Unsetting breakpoint at address 0x%08x",iBreakPointList[index].iAddress);
1.823 +
1.824 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress));
1.825 + if (r != 0)
1.826 + {
1.827 + LOG_MSG("Failed to construct trap handler for DebugSupport::RestoreCode");
1.828 + }
1.829 +
1.830 + // Close the thread handle which has been opened by OpenThreadHandle
1.831 + threadObj->Close(NULL);
1.832 + }
1.833 + else
1.834 + {
1.835 + // Bad handle
1.836 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Could not identify the breakpoint thread id");
1.837 + return KErrBadHandle;
1.838 + }
1.839 + }
1.840 +
1.841 + // make sure there is not already a breakpoint at the new address
1.842 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.843 + {
1.844 + // Ignore data for the breakpoint entry being modified.
1.845 + if (i != index)
1.846 + {
1.847 + /* We need to check if the breakpoint overlaps the address at all,
1.848 + * and this depends upon the size of the two breakpoints as well as
1.849 + * their address.
1.850 + */
1.851 +
1.852 + // newInstSize = size in bytes of new breakpoint
1.853 + TInt newInstSize = BreakSize(info.iMode);
1.854 + if (newInstSize == 0)
1.855 + {
1.856 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Unknown architecture type for new breakpoint");
1.857 + return KErrNotSupported;
1.858 + }
1.859 +
1.860 + // oldInstSize = size in bytes of the existing breakpoint
1.861 + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode);
1.862 + if (oldInstSize == 0)
1.863 + {
1.864 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Unknown architecture type of existing breakpoint");
1.865 + return KErrNotSupported;
1.866 + }
1.867 +
1.868 + // Overlap checking - temp is used as the new breakpoint description for checking purposes only
1.869 + TBreakEntry temp;
1.870 +
1.871 + temp.iAddress = info.iAddress;
1.872 + temp.iMode = info.iMode;
1.873 +
1.874 + // do they overlap?
1.875 + if ( BreakpointsOverlap(temp,iBreakPointList[i]) )
1.876 + {
1.877 + // Yes
1.878 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - New breakpoint overlaps an existing breakpoint");
1.879 + return KErrAlreadyExists;
1.880 + }
1.881 + }
1.882 + }
1.883 +
1.884 + // Prepare iBreakPointList[index] with the new information, then set the breakpoint
1.885 + iBreakPointList[index].iId = info.iId;
1.886 + iBreakPointList[index].iAddress = info.iAddress;
1.887 + iBreakPointList[index].iMode = info.iMode;
1.888 +
1.889 + TBreakEntry& newBreakEntry = iBreakPointList[index];
1.890 +
1.891 + // Decide the size of the breakpoint instruction
1.892 + TUint32 inst = BreakInst(newBreakEntry.iMode);
1.893 + TInt instSize = BreakSize(newBreakEntry.iMode);
1.894 +
1.895 + if (inst == 0 || instSize == 0)
1.896 + {
1.897 + // Unsupported architecture
1.898 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - unsupported breakpoint architecture");
1.899 + return KErrNotSupported;
1.900 + }
1.901 +
1.902 +
1.903 + //if thread id is 0xFFFFFFFF, then the breakpoint is not thread specific
1.904 + if (newBreakEntry.iId != 0xFFFFFFFF)
1.905 + {
1.906 + newBreakEntry.iThreadSpecific = ETrue;
1.907 + }
1.908 +
1.909 + // Get thread id from the process that we are debugging
1.910 + TProcessInfo * proc = NULL;
1.911 + TUint64 threadId = NULL;
1.912 +
1.913 + threadId = newBreakEntry.iId;
1.914 +
1.915 + DThread* threadObj = DebugUtils::OpenThreadHandle(threadId);
1.916 + //if we don't have the right thread id for the address,
1.917 + //then try with the thread id of the process that we are debugging
1.918 + if (!threadObj && iChannel->iDebugProcessList.Count())
1.919 + {
1.920 + proc = &iChannel->iDebugProcessList[0];
1.921 + if (proc)
1.922 + {
1.923 + threadId = proc->iId+1;
1.924 + }
1.925 + threadObj = DebugUtils::OpenThreadHandle(threadId);
1.926 + }
1.927 +
1.928 + if(!threadObj)
1.929 + {
1.930 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - bad handle. Could not identify a threadObj");
1.931 + return KErrBadHandle;
1.932 + }
1.933 +
1.934 + // save the old instruction
1.935 + TUint32 instruction;
1.936 +
1.937 + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint
1.938 + // trap exceptions in case the address is invalid
1.939 + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)newBreakEntry.iAddress, (TAny *)&instruction, instSize));
1.940 +
1.941 + //consider the leave as more important than the error code so store the leave if it's not KErrNone
1.942 + if(KErrNone != r)
1.943 + {
1.944 + err = r;
1.945 + }
1.946 + if(KErrNone != err)
1.947 + {
1.948 + threadObj->Close(NULL);
1.949 + return err;
1.950 + }
1.951 +
1.952 + newBreakEntry.iInstruction.Copy((TUint8 *)&instruction, instSize);
1.953 +
1.954 + newBreakEntry.iId = threadId; //set the thread ID here
1.955 + LOG_MSG3("ModifyCode2 instSize:%d, inst: 0x%08x", instSize, inst);
1.956 + XTRAPD(s, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, newBreakEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal));
1.957 + if(s != DebugSupport::EBreakpointGlobal)
1.958 + {
1.959 + err = s;
1.960 + }
1.961 +
1.962 + // Close the thread handle which has been opened by OpenThreadHandle
1.963 + threadObj->Close(NULL);
1.964 +
1.965 + return err;
1.966 + }
1.967 +
1.968 +//
1.969 +// D_RMD_Breakpoints::DoModifyProcessBreak
1.970 +//
1.971 +TInt D_RMD_Breakpoints::DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo)
1.972 + {
1.973 + // Ensure we have a valid semaphore
1.974 + if (!iInitialised || !iLock)
1.975 + {
1.976 + return KErrNotReady;
1.977 + }
1.978 +
1.979 + // Acquire the lock
1.980 + NKern::ThreadEnterCS();
1.981 + Kern::SemaphoreWait(*iLock);
1.982 +
1.983 + // Really do the work
1.984 + TInt err = priv_DoModifyProcessBreak(aBreakInfo);
1.985 +
1.986 + // Release the lock
1.987 + Kern::SemaphoreSignal(*iLock);
1.988 + NKern::ThreadLeaveCS();
1.989 +
1.990 + return err;
1.991 + }
1.992 +
1.993 +TInt D_RMD_Breakpoints::priv_DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo)
1.994 + {
1.995 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak()");
1.996 +
1.997 + // Check arguments
1.998 + if (!aBreakInfo)
1.999 + {
1.1000 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() was passed a NULL argument");
1.1001 + return KErrArgument;
1.1002 + }
1.1003 +
1.1004 + //User side memory is not accessible directly
1.1005 + TSetBreakInfo info;
1.1006 + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TModifyProcessBreakInfo));
1.1007 + if (err != KErrNone)
1.1008 + {
1.1009 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() was passed a bad argument");
1.1010 + return err;
1.1011 + }
1.1012 +
1.1013 + // EThumb2EEMode breakpoints are not supported
1.1014 + if (EThumb2EEMode == info.iMode)
1.1015 + {
1.1016 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - EThumb2EEMode breakpoints are not supported");
1.1017 + return KErrNotSupported;
1.1018 + }
1.1019 +
1.1020 + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id
1.1021 + TBreakEntry entry;
1.1022 + entry.iBreakId = (TUint32)info.iBreakId;
1.1023 + TInt index = iBreakPointList.FindInSignedKeyOrder(entry);
1.1024 + if (index < 0)
1.1025 + {
1.1026 + // Could not find the breakpoint
1.1027 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Could not find the breakpoint id 0x%08x",(TUint32)info.iBreakId);
1.1028 + return KErrNotFound;
1.1029 + }
1.1030 +
1.1031 + // first check its not obsolete
1.1032 + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint)
1.1033 + {
1.1034 + // its still a valid breakpoint
1.1035 +
1.1036 + // remove the old breakpoint
1.1037 + DProcess *process = DebugUtils::OpenProcessHandle(iBreakPointList[index].iId);
1.1038 + DThread* threadObj = NULL;
1.1039 + if(process)
1.1040 + {
1.1041 + threadObj = process->FirstThread();
1.1042 + if(threadObj)
1.1043 + {
1.1044 + threadObj = DebugUtils::OpenThreadHandle(threadObj->iId);
1.1045 + }
1.1046 + process->Close(NULL);
1.1047 + }
1.1048 +
1.1049 + if (threadObj)
1.1050 + {
1.1051 + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Unsetting breakpoint at address 0x%08x",iBreakPointList[index].iAddress);
1.1052 +
1.1053 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress));
1.1054 + if (r != 0)
1.1055 + {
1.1056 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Failed to construct trap handler for DebugSupport::RestoreCode");
1.1057 + }
1.1058 +
1.1059 + // Close the thread handle which has been opened by OpenThreadHandle
1.1060 + threadObj->Close(NULL);
1.1061 + }
1.1062 + else
1.1063 + {
1.1064 + // Bad handle
1.1065 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Could not identify the breakpoint process id");
1.1066 + return KErrBadHandle;
1.1067 + }
1.1068 + }
1.1069 +
1.1070 + // make sure there is not already a breakpoint at the new address
1.1071 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.1072 + {
1.1073 + // Ignore data for the breakpoint entry being modified.
1.1074 + if (i != index)
1.1075 + {
1.1076 + /* We need to check if the breakpoint overlaps the address at all,
1.1077 + * and this depends upon the size of the two breakpoints as well as
1.1078 + * their address.
1.1079 + */
1.1080 +
1.1081 + // newInstSize = size in bytes of new breakpoint
1.1082 + TInt newInstSize = BreakSize(info.iMode);
1.1083 + if (newInstSize == 0)
1.1084 + {
1.1085 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Unknown architecture type for new breakpoint");
1.1086 + return KErrNotSupported;
1.1087 + }
1.1088 +
1.1089 + // oldInstSize = size in bytes of the existing breakpoint
1.1090 + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode);
1.1091 + if (oldInstSize == 0)
1.1092 + {
1.1093 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - : Unknown architecture type of existing breakpoint");
1.1094 + return KErrNotSupported;
1.1095 + }
1.1096 +
1.1097 + // Overlap checking - temp is used as the new breakpoint description for checking purposes only
1.1098 + TBreakEntry temp;
1.1099 +
1.1100 + temp.iAddress = info.iAddress;
1.1101 + temp.iMode = info.iMode;
1.1102 +
1.1103 + // do they overlap?
1.1104 + if ( BreakpointsOverlap(temp,iBreakPointList[i]) )
1.1105 + {
1.1106 + // Yes
1.1107 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - New breakpoint overlaps an existing breakpoint");
1.1108 + return KErrAlreadyExists;
1.1109 + }
1.1110 + }
1.1111 + }
1.1112 +
1.1113 + // Prepare iBreakPointList[index] with the new information, then set the breakpoint
1.1114 + iBreakPointList[index].iId = info.iId;
1.1115 + iBreakPointList[index].iAddress = info.iAddress;
1.1116 + iBreakPointList[index].iMode = info.iMode;
1.1117 +
1.1118 + TBreakEntry& newBreakEntry = iBreakPointList[index];
1.1119 +
1.1120 + // Decide the size of the breakpoint instruction
1.1121 + TUint32 inst = BreakInst(newBreakEntry.iMode);
1.1122 + TInt instSize = BreakSize(newBreakEntry.iMode);
1.1123 +
1.1124 + if (inst == 0 || instSize == 0)
1.1125 + {
1.1126 + // Unsupported architecture
1.1127 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - unsupported breakpoint architecture");
1.1128 + return KErrNotSupported;
1.1129 + }
1.1130 +
1.1131 + newBreakEntry.iThreadSpecific = EFalse;
1.1132 +
1.1133 + DProcess* process = DebugUtils::OpenProcessHandle(newBreakEntry.iId);
1.1134 + if(!process)
1.1135 + {
1.1136 + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - bad handle. Could not identify a process");
1.1137 + return KErrBadHandle;
1.1138 + }
1.1139 +
1.1140 + DThread* threadObj = process->FirstThread();
1.1141 + if(threadObj)
1.1142 + {
1.1143 + threadObj = DebugUtils::OpenThreadHandle(threadObj->iId);
1.1144 + }
1.1145 + process->Close(NULL);
1.1146 + if(!threadObj)
1.1147 + {
1.1148 + return KErrNotFound;
1.1149 + }
1.1150 + // save the old instruction
1.1151 + TUint32 instruction;
1.1152 +
1.1153 + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint
1.1154 + // trap exceptions in case the address is invalid
1.1155 + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)newBreakEntry.iAddress, (TAny *)&instruction, instSize));
1.1156 +
1.1157 + //consider the leave as more important than the error code so store the leave if it's not KErrNone
1.1158 + if(KErrNone != r)
1.1159 + {
1.1160 + err = r;
1.1161 + }
1.1162 + if(KErrNone != err)
1.1163 + {
1.1164 + threadObj->Close(NULL);
1.1165 + return err;
1.1166 + }
1.1167 +
1.1168 + newBreakEntry.iInstruction.Copy((TUint8 *)&instruction, instSize);
1.1169 +
1.1170 + XTRAPD(s, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, newBreakEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal));
1.1171 + if(s != DebugSupport::EBreakpointGlobal)
1.1172 + {
1.1173 + err = s;
1.1174 + }
1.1175 +
1.1176 + // Close the thread handle which has been opened by OpenThreadHandle
1.1177 + threadObj->Close(NULL);
1.1178 +
1.1179 + return err;
1.1180 + }
1.1181 +
1.1182 +/**
1.1183 +Public member function which returns information about a previously set breakpoint.
1.1184 +
1.1185 +Note 1:
1.1186 +This function ensures exclusive access to the breakpoint data structures
1.1187 +by using a semaphore to serialise access.
1.1188 +
1.1189 +@see priv_DoBreakInfo
1.1190 +
1.1191 +Note 2:
1.1192 +As implied by Note 1, the caller must have previously called Init() or this
1.1193 +function will return KErrNotReady;
1.1194 +
1.1195 +@param aBreakInfo Address of aBreakInfo structure in user-side memory within the DSS client thread. CAN ONLY BE ACCESSED VIA Kern::ThreadRawRead()
1.1196 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.1197 +*/
1.1198 +TInt D_RMD_Breakpoints::DoBreakInfo(TGetBreakInfo* aBreakInfo)
1.1199 + {
1.1200 + // Ensure we have a valid semaphore
1.1201 + if (!iInitialised || !iLock)
1.1202 + {
1.1203 + return KErrNotReady;
1.1204 + }
1.1205 +
1.1206 + // Acquire the lock
1.1207 + NKern::ThreadEnterCS();
1.1208 + Kern::SemaphoreWait(*iLock);
1.1209 +
1.1210 + // Really do the work
1.1211 + TInt err = priv_DoBreakInfo(aBreakInfo);
1.1212 +
1.1213 + // Release the lock
1.1214 + Kern::SemaphoreSignal(*iLock);
1.1215 + NKern::ThreadLeaveCS();
1.1216 +
1.1217 + return err;
1.1218 + }
1.1219 +
1.1220 +/**
1.1221 +Private member function function which returns information about a previously set breakpoint..
1.1222 +
1.1223 +@see DoBreakInfo
1.1224 +
1.1225 +@param aBreakInfo Address of aBreakInfo structure in user-side memory within the DSS client thread. CAN ONLY BE ACCESSED VIA Kern::ThreadRawRead()
1.1226 +@return KErrNone if successful, otherwise one of the other system wide error codes.
1.1227 +*/
1.1228 +TInt D_RMD_Breakpoints::priv_DoBreakInfo(TGetBreakInfo* aBreakInfo)
1.1229 + {
1.1230 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo()");
1.1231 +
1.1232 + if (!aBreakInfo)
1.1233 + {
1.1234 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() was passed a NULL argument");
1.1235 +
1.1236 + return KErrArgument;
1.1237 + }
1.1238 +
1.1239 + //User side memory is not accessible directly
1.1240 + TGetBreakInfo info;
1.1241 + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TGetBreakInfo));
1.1242 + if (err != KErrNone)
1.1243 + {
1.1244 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() was passed a bad argument");
1.1245 +
1.1246 + return err;
1.1247 + }
1.1248 +
1.1249 + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id
1.1250 + TBreakEntry entry;
1.1251 + entry.iBreakId = (TUint32)info.iBreakId;
1.1252 + TInt index = iBreakPointList.FindInSignedKeyOrder(entry);
1.1253 +
1.1254 + if (index >=0)
1.1255 + {
1.1256 + // get the thread id for this breakpoint
1.1257 + TUint64 threadId = iBreakPointList[index].iId;
1.1258 +
1.1259 + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iId,&threadId,sizeof(TUint64));
1.1260 + if (err != KErrNone)
1.1261 + {
1.1262 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iThreadId information");
1.1263 + return err;
1.1264 + }
1.1265 +
1.1266 + // get the threadSpecific-ness
1.1267 + TBool threadSpecific = iBreakPointList[index].iThreadSpecific;
1.1268 +
1.1269 + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iThreadSpecific,&threadSpecific,sizeof(TBool));
1.1270 + if (err != KErrNone)
1.1271 + {
1.1272 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return thread specific information");
1.1273 + return err;
1.1274 + }
1.1275 +
1.1276 +
1.1277 + // get the address
1.1278 + TUint32 address = iBreakPointList[index].iAddress;
1.1279 +
1.1280 + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iAddress,&address,sizeof(TUint32));
1.1281 + if (err != KErrNone)
1.1282 + {
1.1283 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iAddress information");
1.1284 + return err;
1.1285 + }
1.1286 +
1.1287 +
1.1288 + // get the architecture
1.1289 + TArchitectureMode mode = iBreakPointList[index].iMode;
1.1290 +
1.1291 + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iMode,&mode,sizeof(TUint32));
1.1292 + if (err != KErrNone)
1.1293 + {
1.1294 + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iMode information");
1.1295 + return err;
1.1296 + }
1.1297 +
1.1298 + return err;
1.1299 + }
1.1300 +
1.1301 + LOG_MSG2("D_RMD_Breakpoints::priv_DoBreakInfo - Could not find the breakpoint id specified 0x%08x", entry.iBreakId);
1.1302 + return KErrNotFound;
1.1303 + }
1.1304 +
1.1305 +/**
1.1306 +Public member function which clears all the breakpoints in the system. Generally used for shutting down
1.1307 +the debug device driver.
1.1308 +
1.1309 +Note 1:
1.1310 +This function ensures exclusive access to the breakpoint data structures
1.1311 +by using a semaphore to serialise access.
1.1312 +
1.1313 +@see priv_ClearAllBreakPoints
1.1314 +
1.1315 +Note 2:
1.1316 +As implied by Note 1, the caller must have previously called Init() or this
1.1317 +function will return KErrNotReady;
1.1318 +*/
1.1319 +void D_RMD_Breakpoints::ClearAllBreakPoints()
1.1320 + {
1.1321 + // Ensure we have a valid semaphore
1.1322 + if (!iInitialised || !iLock)
1.1323 + {
1.1324 + return;
1.1325 + }
1.1326 +
1.1327 + // Acquire the lock
1.1328 + NKern::ThreadEnterCS();
1.1329 + Kern::SemaphoreWait(*iLock);
1.1330 +
1.1331 + // Really do the work
1.1332 + priv_ClearAllBreakPoints();
1.1333 +
1.1334 + // Release the lock
1.1335 + Kern::SemaphoreSignal(*iLock);
1.1336 + NKern::ThreadLeaveCS();
1.1337 + }
1.1338 +
1.1339 +/**
1.1340 +Private member function which clears all the breakpoints in the system. Generally used for shutting down
1.1341 +the debug device driver.
1.1342 +
1.1343 +@see DoClearAllBreakPoints
1.1344 +*/
1.1345 +void D_RMD_Breakpoints::priv_ClearAllBreakPoints()
1.1346 + {
1.1347 + LOG_MSG("D_RMD_Breakpoints::priv_ClearAllBreakPoints()");
1.1348 +
1.1349 + TInt err = KErrNone;
1.1350 +
1.1351 + for (TInt i=0; i<iBreakPointList.Count(); i++)
1.1352 + {
1.1353 + if ((iBreakPointList[i].iAddress != 0) && !iBreakPointList[i].iObsoleteLibraryBreakpoint)
1.1354 + {
1.1355 + LOG_MSG2("D_RMD_Breakpoints::priv_ClearAllBreakPoints() - Clearing breakpoint at address %x", iBreakPointList[i].iAddress);
1.1356 + TUint32 id = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1);
1.1357 + DThread *threadObj = DebugUtils::OpenThreadHandle(id);
1.1358 + if (threadObj)
1.1359 + {
1.1360 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[i].iAddress));
1.1361 + err = (KErrNone == r) ? err : r;
1.1362 + threadObj->Close(NULL);
1.1363 + }
1.1364 + else
1.1365 + {
1.1366 + err = KErrBadHandle;
1.1367 + }
1.1368 +
1.1369 + if (KErrNone != err)
1.1370 + {
1.1371 + LOG_MSG2("D_RMD_Breakpoints::priv_ClearAllBreakPoints() - Error 0x%08x while clearing breakpoint", err);
1.1372 + }
1.1373 + }
1.1374 + }
1.1375 +
1.1376 + iBreakPointList.Reset();
1.1377 + }
1.1378 +
1.1379 +/**
1.1380 +Public member function which disables the breakpoint at the specified address.
1.1381 +
1.1382 +Note 1:
1.1383 +This function ensures exclusive access to the breakpoint data structures
1.1384 +by using a semaphore to serialise access.
1.1385 +
1.1386 +@see priv_DisableBreakAtAddress
1.1387 +
1.1388 +Note 2:
1.1389 +As implied by Note 1, the caller must have previously called Init() or this
1.1390 +function will return KErrNotReady;
1.1391 +
1.1392 +@param aAddress Address at which to disable breakpoints (all threads)
1.1393 +@return KErrNone if successful, one of the other system wide error codes otherwise.
1.1394 +*/
1.1395 +TInt D_RMD_Breakpoints::DisableBreakAtAddress(TUint32 aAddress)
1.1396 + {
1.1397 + // Ensure we have a valid semaphore
1.1398 + if (!iInitialised || !iLock)
1.1399 + {
1.1400 + return KErrNotReady;
1.1401 + }
1.1402 +
1.1403 + // Acquire the lock
1.1404 + NKern::ThreadEnterCS();
1.1405 + Kern::SemaphoreWait(*iLock);
1.1406 +
1.1407 + // Really do the work
1.1408 + TInt err = priv_DisableBreakAtAddress(aAddress);
1.1409 +
1.1410 + // Release the lock
1.1411 + Kern::SemaphoreSignal(*iLock);
1.1412 + NKern::ThreadLeaveCS();
1.1413 +
1.1414 + return err;
1.1415 + }
1.1416 +
1.1417 +/**
1.1418 +Private member function which clears all the breakpoints in the system. Generally used for shutting down
1.1419 +the debug device driver.
1.1420 +
1.1421 +@see DisableBreakAtAddress
1.1422 +
1.1423 +@param aAddress clears the breakpoint at the specified address
1.1424 +@return KErrNone if successful, one of the other system wide error codes otherwise.
1.1425 +*/
1.1426 +TInt D_RMD_Breakpoints::priv_DisableBreakAtAddress(TUint32 aAddress)
1.1427 + {
1.1428 + LOG_MSG("D_RMD_Breakpoints::priv_DisableBreakAtAddress()");
1.1429 +
1.1430 + TInt err = KErrNone;
1.1431 +
1.1432 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.1433 + {
1.1434 + if (iBreakPointList[i].iAddress == aAddress)
1.1435 + {
1.1436 + iBreakPointList[i].iDisabledForStep = ETrue;
1.1437 + LOG_MSG2("D_RMD_Breakpoints::priv_DisableBreakAtAddress - Disabling breakpoint at address 0x%x", iBreakPointList[i].iAddress);
1.1438 +
1.1439 + //clear the breakpoint with code modifier
1.1440 + //code modifier will restore the org instruction and also frees the shadow page if necessary
1.1441 + TUint64 id = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1);
1.1442 + DThread* threadObj = NULL;
1.1443 + if(iBreakPointList[i].iThreadSpecific)
1.1444 + {
1.1445 + threadObj = DebugUtils::OpenThreadHandle(id);
1.1446 + }
1.1447 + else
1.1448 + {
1.1449 + DProcess *process = DebugUtils::OpenProcessHandle(iBreakPointList[i].iId);
1.1450 + if(process)
1.1451 + {
1.1452 + threadObj = process->FirstThread();
1.1453 + if(threadObj)
1.1454 + {
1.1455 + if(KErrNone != threadObj->Open())
1.1456 + {
1.1457 + LOG_MSG("Couldn't open threadObj");
1.1458 + threadObj = NULL;
1.1459 + }
1.1460 + }
1.1461 + else
1.1462 + {
1.1463 + LOG_MSG("threadObj is NULL");
1.1464 + }
1.1465 + }
1.1466 + else
1.1467 + {
1.1468 + LOG_MSG("Process is NULL");
1.1469 + }
1.1470 + }
1.1471 + if (threadObj)
1.1472 + {
1.1473 + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, aAddress));
1.1474 + if(KErrNone != err || KErrNone != r)
1.1475 + {
1.1476 + LOG_MSG3("Error from DebugSupport::RestoreCode: r: %d, err: %d", r, err);
1.1477 + }
1.1478 + err = (KErrNone == r) ? err : r;
1.1479 + threadObj->Close(NULL);
1.1480 + }
1.1481 + else
1.1482 + {
1.1483 + err = KErrBadHandle;
1.1484 + break;
1.1485 + }
1.1486 + }
1.1487 + }
1.1488 +
1.1489 + return err;
1.1490 + }
1.1491 +
1.1492 +/**
1.1493 +Public member function which enables previously disabled breakpoints within a given thread.
1.1494 +
1.1495 +Note 1:
1.1496 +This function ensures exclusive access to the breakpoint data structures
1.1497 +by using a semaphore to serialise access.
1.1498 +
1.1499 +@see priv_DoEnableDisabledBreak
1.1500 +
1.1501 +Note 2:
1.1502 +As implied by Note 1, the caller must have previously called Init() or this
1.1503 +function will return KErrNotReady;
1.1504 +
1.1505 +@param aThreadId Thread in which to enable all previously disabled breakpoints
1.1506 +@return KErrNone if successful, one of the system wide error codes otherwise.
1.1507 +*/
1.1508 +TInt D_RMD_Breakpoints::DoEnableDisabledBreak(TUint64 aThreadId)
1.1509 + {
1.1510 + // Ensure we have a valid semaphore
1.1511 + if (!iInitialised || !iLock)
1.1512 + {
1.1513 + return KErrNotReady;
1.1514 + }
1.1515 +
1.1516 + // Acquire the lock
1.1517 + NKern::ThreadEnterCS();
1.1518 + Kern::SemaphoreWait(*iLock);
1.1519 +
1.1520 + // Really do the work
1.1521 + TInt err = priv_DoEnableDisabledBreak(aThreadId);
1.1522 +
1.1523 + // Release the lock
1.1524 + Kern::SemaphoreSignal(*iLock);
1.1525 + NKern::ThreadLeaveCS();
1.1526 +
1.1527 + return err;
1.1528 + }
1.1529 +
1.1530 +/**
1.1531 +Private member function which enables previously disabled breakpoints within a given thread.
1.1532 +
1.1533 +@see DoEnableDisabledBreak
1.1534 +
1.1535 +@param aThreadId Thread in which to enable all previously disabled breakpoints
1.1536 +@return KErrNone if successful, one of the system wide error codes otherwise.
1.1537 +*/
1.1538 +TInt D_RMD_Breakpoints::priv_DoEnableDisabledBreak(TUint64 aThreadId)
1.1539 + {
1.1540 + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableDisabledBreak()");
1.1541 + DThread* thread = DebugUtils::OpenThreadHandle(aThreadId);
1.1542 + if(!thread)
1.1543 + {
1.1544 + LOG_MSG2("Thread: 0x%08x does not exist", aThreadId);
1.1545 + return KErrNotFound;
1.1546 + }
1.1547 + TUint64 processId = thread->iOwningProcess->iId;
1.1548 + thread->Close(NULL);
1.1549 +
1.1550 + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++)
1.1551 + {
1.1552 + TBool needsEnabling = EFalse;
1.1553 + if(iBreakPointList[i].iDisabledForStep)
1.1554 + {
1.1555 + if(iBreakPointList[i].iThreadSpecific)
1.1556 + {
1.1557 + needsEnabling = (aThreadId == iBreakPointList[i].iId);
1.1558 + }
1.1559 + else
1.1560 + {
1.1561 + needsEnabling = (processId == iBreakPointList[i].iId);
1.1562 + }
1.1563 + }
1.1564 + if (needsEnabling)
1.1565 + {
1.1566 + LOG_MSG2("Re-enabling breakpoint at address %x", iBreakPointList[i].iAddress);
1.1567 + TInt err = priv_DoEnableBreak(iBreakPointList[i], EFalse);
1.1568 + if(KErrNone != err)
1.1569 + {
1.1570 + LOG_MSG2("Error returned from DoEnableBreak: %d", err);
1.1571 + iBreakPointList[i].iDisabledForStep = EFalse;
1.1572 + }
1.1573 + return err;
1.1574 + }
1.1575 + }
1.1576 +
1.1577 + return KErrNone;
1.1578 + }
1.1579 +
1.1580 +/**
1.1581 +Public member function which removes all the breakpoints within a given thread.
1.1582 +
1.1583 +Note 1:
1.1584 +This function ensures exclusive access to the breakpoint data structures
1.1585 +by using a semaphore to serialise access.
1.1586 +
1.1587 +@see priv_DoRemoveThreadBreaks
1.1588 +
1.1589 +Note 2:
1.1590 +As implied by Note 1, the caller must have previously called Init() or this
1.1591 +function will return KErrNotReady;
1.1592 +
1.1593 +@param aThreadId Thread from which to remove all existing breakpoints
1.1594 +@return KErrNone if successful, one of the system wide error codes otherwise.
1.1595 +*/
1.1596 +void D_RMD_Breakpoints::DoRemoveThreadBreaks(TUint64 aThreadId)
1.1597 + {
1.1598 + // Ensure we have a valid semaphore
1.1599 + if (!iInitialised || !iLock)
1.1600 + {
1.1601 + return;
1.1602 + }
1.1603 +
1.1604 + // Acquire the lock
1.1605 + NKern::ThreadEnterCS();
1.1606 + Kern::SemaphoreWait(*iLock);
1.1607 +
1.1608 + // Really do the work
1.1609 + priv_DoRemoveThreadBreaks(aThreadId);
1.1610 +
1.1611 + // Release the lock
1.1612 + Kern::SemaphoreSignal(*iLock);
1.1613 + NKern::ThreadLeaveCS();
1.1614 + }
1.1615 +
1.1616 +/**
1.1617 +Private member function which removes all the breakpoints particular to a particular thread
1.1618 +
1.1619 +@see DoRemoveThreadBreaks
1.1620 +
1.1621 +@param aThreadId Thread from which to remove all existing breakpoints
1.1622 +@return KErrNone if successful, one of the system wide error codes otherwise.
1.1623 +*/
1.1624 +void D_RMD_Breakpoints::priv_DoRemoveThreadBreaks(TUint64 aThreadId)
1.1625 + {
1.1626 + LOG_MSG2("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks(aThreadId = 0x%016lx)\n",aThreadId);
1.1627 +
1.1628 + TInt err = KErrNone;
1.1629 + TUint64 threadId;
1.1630 +
1.1631 + for (TInt i=iBreakPointList.Count()-1; i >= 0; i--)
1.1632 + {
1.1633 + if ((iBreakPointList[i].iAddress != 0) && !iBreakPointList[i].iObsoleteLibraryBreakpoint)
1.1634 + {
1.1635 + threadId = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1);
1.1636 + if (threadId == aThreadId)
1.1637 + {
1.1638 + LOG_MSG4("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks() - Clearing breakpoint at address 0x%08x for thread id 0x%016lx with id 0x%08x", iBreakPointList[i].iAddress, iBreakPointList[i].iId, iBreakPointList[i].iBreakId);
1.1639 +
1.1640 + err = priv_DoClearBreak(iBreakPointList[i].iBreakId, EFalse);
1.1641 +
1.1642 + if (err != KErrNone)
1.1643 + {
1.1644 + LOG_MSG2("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks() - failed to remove break id 0x%08x\n",iBreakPointList[i].iBreakId);
1.1645 + return;
1.1646 + }
1.1647 + }
1.1648 + }
1.1649 + }
1.1650 + }
1.1651 +
1.1652 +// Remove the process breakpoints for process with PID aProcessId in the range [aCodeAddress, aCodeAddress + aCodeSize)
1.1653 +void D_RMD_Breakpoints::RemoveBreaksForProcess(TUint64 aProcessId, TUint32 aCodeAddress, TUint32 aCodeSize)
1.1654 + {
1.1655 + LOG_MSG("D_RMD_Breakpoints::RemoveBreaksForProcess()");
1.1656 + for (TInt i=iBreakPointList.Count() - 1; i>=0; i--)
1.1657 + {
1.1658 + TBreakEntry& breakEntry = iBreakPointList[i];
1.1659 + if(!breakEntry.iThreadSpecific && breakEntry.iId == aProcessId)
1.1660 + {
1.1661 + if ((breakEntry.iAddress >= aCodeAddress) && (breakEntry.iAddress < (aCodeAddress + aCodeSize)))
1.1662 + {
1.1663 + LOG_MSG2("Removing process breakpoint at address %x", (TUint32)breakEntry.iAddress);
1.1664 + TInt err = DoClearBreak(breakEntry.iBreakId, ETrue);
1.1665 + if(KErrNone != err)
1.1666 + {
1.1667 + LOG_MSG2("Error removing process breakpoint: %d", err);
1.1668 + }
1.1669 + }
1.1670 + }
1.1671 + }
1.1672 + }
1.1673 +
1.1674 +// mark the breakpoints in the range [aCodeAddress, aCodeAddress + aCodeSize)
1.1675 +void D_RMD_Breakpoints::InvalidateLibraryBreakPoints(TUint32 aCodeAddress, TUint32 aCodeSize)
1.1676 + {
1.1677 + LOG_MSG("D_RMD_Breakpoints::InvalidateLibraryBreakPoints()");
1.1678 + for (TInt i=0; i<iBreakPointList.Count(); i++)
1.1679 + {
1.1680 + if ((iBreakPointList[i].iAddress >= aCodeAddress) && (iBreakPointList[i].iAddress < (aCodeAddress + aCodeSize)))
1.1681 + {
1.1682 + LOG_EVENT_MSG2("Disabling library breakpoint at address %x", iBreakPointList[i].iAddress);
1.1683 + iBreakPointList[i].iObsoleteLibraryBreakpoint = ETrue;
1.1684 + }
1.1685 + }
1.1686 + }
1.1687 +
1.1688 +TInt D_RMD_Breakpoints::BreakPointCount() const
1.1689 + {
1.1690 + return iBreakPointList.Count();
1.1691 + }
1.1692 +
1.1693 +/**
1.1694 + Gets next breakpoint in list.
1.1695 + @param aBreakEntry The break entry to get the successor of. If NULL then returns the first entry.
1.1696 + @return A pointer to the next break entry, or NULL if the end of the list has been reached
1.1697 + */
1.1698 +TBreakEntry* D_RMD_Breakpoints::GetNextBreak(const TBreakEntry* aBreakEntry) const
1.1699 + {
1.1700 + if(!aBreakEntry)
1.1701 + {
1.1702 + return (TBreakEntry*)&(iBreakPointList[0]);
1.1703 + }
1.1704 + TInt index = iBreakPointList.FindInSignedKeyOrder(*aBreakEntry) + 1;
1.1705 + return (index < BreakPointCount()) ? (TBreakEntry*)&(iBreakPointList[index]) : NULL;
1.1706 + }
1.1707 +
1.1708 +TBool D_RMD_Breakpoints::IsTemporaryBreak(const TBreakEntry& aBreakEntry) const
1.1709 + {
1.1710 + // Ensure we have a valid semaphore
1.1711 + if (!iInitialised || !iLock)
1.1712 + {
1.1713 + return EFalse;
1.1714 + }
1.1715 +
1.1716 + // Acquire the lock
1.1717 + NKern::ThreadEnterCS();
1.1718 + Kern::SemaphoreWait(*iLock);
1.1719 +
1.1720 + // Really do the work
1.1721 + TBool tempBreak = priv_IsTemporaryBreak(aBreakEntry);
1.1722 +
1.1723 + // Release the lock
1.1724 + Kern::SemaphoreSignal(*iLock);
1.1725 + NKern::ThreadLeaveCS();
1.1726 +
1.1727 + return tempBreak;
1.1728 + }
1.1729 +
1.1730 +/**
1.1731 +Private member function which tells us if a breakpoint is temporary
1.1732 +
1.1733 +@see IsTemporaryBreak
1.1734 +
1.1735 +@param aBreakEntry
1.1736 +@return TBool indicating if the break is temporary or not
1.1737 +*/
1.1738 +TBool D_RMD_Breakpoints::priv_IsTemporaryBreak(const TBreakEntry& aBreakEntry) const
1.1739 + {
1.1740 + return aBreakEntry.iBreakId < NUMBER_OF_TEMP_BREAKPOINTS;
1.1741 + }
1.1742 +
1.1743 +
1.1744 +// End of file - d_rmd_breakpoints.cpp