diff -r d8d70de2bd36 -r 57b9594f5772 kernel/eka/drivers/debug/rmdebug/rm_debug_kerneldriver.cpp --- a/kernel/eka/drivers/debug/rmdebug/rm_debug_kerneldriver.cpp Wed Aug 18 11:08:29 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3791 +0,0 @@ -// Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the License "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// Device driver for kernel side debug assist -// - -#ifdef __WINS__ -#error - this driver cannot be built for emulation -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debug_logging.h" -#include "d_rmd_breakpoints.h" // moved breakpoints code lives here -#include "d_rmd_stepping.h" // moved stepping code lives here -#include "rm_debug_kerneldriver.h" -#include "d_list_manager.h" -#include "rm_debug_driver.h" -#include "rm_debug_eventhandler.h" -#include "d_debug_functionality.h" -#include "d_process_tracker.h" -#include "debug_utils.h" -#include "d_buffer_manager.h" - -using namespace Debug; - -///////////////////////////////////////////////////////////////////////// -// -// DRM_DebugDriverFactory implementation -// -///////////////////////////////////////////////////////////////////////// - -// -// DRM_DebugDriverFactory constructor -// -DRM_DebugDriverFactory::DRM_DebugDriverFactory() - { - iVersion = TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); - } - -// -// DRM_DebugDriverFactory::Create -// -TInt DRM_DebugDriverFactory::Create(DLogicalChannelBase*& aChannel) - { - if (iOpenChannels != 0) - return KErrInUse; // a channel is already open - - aChannel = new DRM_DebugChannel(this); - - return aChannel ? KErrNone : KErrNoMemory; - } - -// -// DRM_DebugDriverFactory::Install -// -TInt DRM_DebugDriverFactory::Install() - { - return(SetName(&KRM_DebugDriverName)); - } - -// -// DRM_DebugDriverFactory::Install -// -void DRM_DebugDriverFactory::GetCaps(TDes8& aDes) const - { - TCapsRM_DebugDriver b; - b.iVersion = TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber); - - Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); - } - -///////////////////////////////////////////////////////////////////////// -// -// DRM_DebugChannel implementation -// -///////////////////////////////////////////////////////////////////////// - -// -// DRM_DebugChannel constructor -// -DRM_DebugChannel::DRM_DebugChannel(DLogicalDevice* aLogicalDevice) - : iExcludedROMAddressStart(ROM_LINEAR_BASE), - iExcludedROMAddressEnd(0), - iPageSize(0x1000), - iBreakManager(0), - iStepper(0), - iStepLock(0), - iDfcQ(NULL), - iInitialisedCodeModifier(0), - iAsyncGetValueRequest(NULL) - { - LOG_MSG("DRM_DebugChannel::DRM_DebugChannel()"); - - iDevice = aLogicalDevice; - - iClientThread = &Kern::CurrentThread(); - iClientThread->Open(); - - LOG_MSG3("DRM_DebugChannel::DRM_DebugChannel() clientThread = 0x%08x, id=%d", - iClientThread, iClientThread->iId ); - - - iPageSize = Kern::RoundToPageSize(1); - } - -// -// DRM_DebugChannel destructor -// -DRM_DebugChannel::~DRM_DebugChannel() - { - LOG_MSG("DRM_DebugChannel::~DRM_DebugChannel()"); - - if (iAsyncGetValueRequest) - { - Kern::QueueRequestComplete(iClientThread, iAsyncGetValueRequest, KErrCancel); // does nothing if request not pending - Kern::DestroyClientRequest(iAsyncGetValueRequest); - } - - NKern::ThreadEnterCS(); - Kern::SafeClose((DObject*&)iClientThread, NULL); - NKern::ThreadLeaveCS(); - - // Close breakpoint manager - if (iBreakManager) - { - NKern::ThreadEnterCS(); - delete iBreakManager; - NKern::ThreadLeaveCS(); - } - - // Close stepping manager - if (iStepper) - { - NKern::ThreadEnterCS(); - delete iStepper; - NKern::ThreadLeaveCS(); - } - - //close the debug process list - iDebugProcessList.Close(); - - DestroyDfcQ(); - - //close the code modifier - if (iInitialisedCodeModifier) - { - DebugSupport::CloseCodeModifier(); - } - } - -void DRM_DebugChannel::DestroyDfcQ() - { - LOG_MSG("DRM_DebugChannel::DestroyDfcQ()"); - if (iDfcQ) - { - NKern::ThreadEnterCS(); - iDfcQ->Destroy(); - NKern::ThreadLeaveCS(); - } - } - -// -// DRM_DebugChannel::DoCreate -// -TInt DRM_DebugChannel::DoCreate(TInt /*aUnit*/, const TDesC* anInfo, const TVersion& aVer) - { - LOG_MSG("DRM_DebugChannel::DoCreate()"); - TInt err = Kern::CreateClientDataRequest(iAsyncGetValueRequest); - if(err != KErrNone) - return err; - - if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), aVer)) - return KErrNotSupported; - - // Do the security check here so that any arbitrary application doesn't make - // use of Trk kernel driver. - if (!DoSecurityCheck()) - { - LOG_MSG("DRM_DebugChannel::DoCreate() - permission denied!"); - return KErrPermissionDenied; - } - - if (anInfo) - { - // this is the end address of the user library. - // this doesn't seem to be valid for EKA2. - // right now we dont need this for EKA2 since we are not worried - // about kernel being stopped as kernel is multithreaded. - // just retaining this for future use. - TBuf8<32> buf; - TInt err = Kern::ThreadRawRead(iClientThread, anInfo, &buf, 32); - if(err != KErrNone) - return err; - } - - // Allocate a D_RMD_Breakpoints class as a breakpoint manager - NKern::ThreadEnterCS(); - iBreakManager = new D_RMD_Breakpoints(this); - NKern::ThreadLeaveCS(); - if (iBreakManager == NULL) - { - LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct breakpoint manager"); - return KErrNoMemory; - } - - // Initialise the new breakpoint manager object - iBreakManager->Init(); - - // Allocate a DRMDStepping class as the stepping manager - NKern::ThreadEnterCS(); - iStepper = new DRMDStepping(this); - NKern::ThreadLeaveCS(); - if (iStepper == NULL) - { - LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct stepper manager"); - return KErrNoMemory; - } - - // Initialize the code modifier for managing breakpoints. - TUint caps; //ignored for now - err = DebugSupport::InitialiseCodeModifier(caps, NUMBER_OF_MAX_BREAKPOINTS); - //if code modifier initializer failed, - //return here, since we can't set an breakpoints - if(err != KErrNone) - { - return err; - } - else - { - iInitialisedCodeModifier = ETrue; - } - - //create and set the driver's Dfc queue - err = CreateDfcQ(); - if(err != KErrNone) - { - LOG_MSG("DRM_DebugChannel::DoCreate() Creating Dfc queue failed."); - } - SetDfcQ(iDfcQ); - - iMsgQ.Receive(); - - iEventHandler = new DRM_DebugEventHandler; - if (!iEventHandler) - return KErrNoMemory; - err = iEventHandler->Create(iDevice, this, iClientThread); - if (err != KErrNone) - return err; - - //return KErrNone; - return iEventHandler->Start(); - } - -/** -Forward call to either synch or asynch methods while serialising all calls via lock. - -Protect access via a the event handler lock to -serialise all calls and protect concurrent access to data structures - -@param aMsg pointer to a TMessageBase object - -@return error returned by called methods - -@see DRM_DebugEventHandler::HandleSpecificEvent where lock is also used -@see DRM_DebugEventHandler::iProtectionLock - -*/ -TInt DRM_DebugChannel::SendMsg(TMessageBase* aMsg) - { - DThread * currThread = &Kern::CurrentThread(); - LOG_MSG3("DRM_DebugChannel::SendMsg() currThread = 0x%08x, iClientThread=0x%08x", currThread, iClientThread ); - - iEventHandler->LockDataAccess(); - - TThreadMessage& m = *(TThreadMessage*)aMsg; - TInt id = m.iValue; - TInt err = KErrNone; - - if (id != (TInt)ECloseMsg && id != KMaxTInt && id < 0) - { - // DoRequest - TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); - err = SendRequest(aMsg); - if (err != KErrNone) - Kern::RequestComplete(pStatus,err); - } - else - { - err = DLogicalChannel::SendMsg(aMsg); - } - - iEventHandler->ReleaseDataAccess(); - return err; - } - -// -// DRM_DebugChannel::SendRequest -// -TInt DRM_DebugChannel::SendRequest(TMessageBase* aMsg) - { - LOG_MSG("DRM_DebugChannel::SendRequest()"); - - TThreadMessage& m = *(TThreadMessage*)aMsg; - TInt function = ~m.iValue; - TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); - TAny* a1 = m.Ptr1(); - - TInt err = KErrNotSupported; - switch(function) - { - case RRM_DebugDriver::ERequestGetEvent: - err = PreAsyncGetValue((TEventInfo*)a1,pStatus); - break; - } - if (err == KErrNone) - err = DLogicalChannel::SendMsg(aMsg); - return err; - } - -// -// DRM_DebugChannel::PreAsyncGetValue -// -TInt DRM_DebugChannel::PreAsyncGetValue(TEventInfo* aValue, TRequestStatus* aStatus) - { - LOG_MSG3("DRM_DebugChannel::PreAsyncGetValue() TEventInfo=0x%08x, TRequestStatus=0x%08x", - aValue, aStatus ); - - iAsyncGetValueRequest->Reset(); - - TInt err = iAsyncGetValueRequest->SetStatus(aStatus); - if (err != KErrNone) - return err; - - iAsyncGetValueRequest->SetDestPtr(aValue); - return KErrNone; - } - -/** - Create the Dfc queue for receiving messages - */ -TInt DRM_DebugChannel::CreateDfcQ() - { - LOG_MSG("DRM_DebugChannel::CreateDfcQ()"); - TInt r = Kern::DynamicDfcQCreate(iDfcQ, KRmDebugDriverThreadPriority, KRM_DebugDriverName); - // Fix to stop t_rmdebug2 etc crashing the device. - // This should be removed once the rm debug driver has been updated for WDP. - if (r == KErrNone) - iDfcQ->SetRealtimeState(ERealtimeStateOff); - return r; - } - -// -// DRM_DebugChannel::DoCancel -// -// New: The cancel call does not take an enum parameter describing -// the request to be cancelled. Rather it supplies a pointer -// to a user-side struct defining the cancellation -// -void DRM_DebugChannel::DoCancel(TInt aReqNo) - { - LOG_MSG("DRM_DebugChannel::DoCancel()"); - - TRMD_DebugCancelInfo info; - - TInt err = Kern::ThreadRawRead(iClientThread,(TAny*)aReqNo,(TAny*)&info,sizeof(info)); - if (err != KErrNone) - { - // How do we cancel something we know nothing about??? - LOG_MSG("DRM_DebugChannel::DoCancel - bad arguments"); - return; - } - - // Find the process - DTargetProcess* pProcess = TheDProcessTracker.FindProcess(info.iProcessName); - if (pProcess == NULL) - { - // We are doomed. We don't know which event to cancel.. - LOG_MSG2("Cannot determine which process is being debugged: %S", &(info.iProcessName)); - - return; - } - - // Find the agent - DDebugAgent* debugAgent = pProcess->Agent(info.iAgentId); - if (debugAgent == NULL) - { - // Bad agent means there is no tracking agent - LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",info.iAgentId); - return; - } - - // Agent completes/pends the request as appropriate. - debugAgent->CancelGetEvent(); - - } - -// -// DRM_DebugChannel::DoRequest -// -void DRM_DebugChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) - { - LOG_MSG4("DRM_DebugChannel::DoRequest(), iClientThread=0x%08x, tid=0x%08x, TRequestStatus=0x%08x", - iClientThread, I64LOW(iClientThread->iId), aStatus); - - switch(aReqNo) - { - case RRM_DebugDriver::ERequestGetEvent: - { - TEventMetaData eventMetaData; - TInt err = Kern::ThreadRawRead(iClientThread, a2, (TUint8 *)&eventMetaData, sizeof(TEventMetaData) ); - if (err != KErrNone) - { - LOG_MSG("Error: could not read argument data from the DSS (TEventMetaData)"); - - // We could not read information from the user, so the a2 argument is probably wrong - Kern::RequestComplete(iClientThread, aStatus, KErrArgument); - return; - } - - // Find the process - DTargetProcess* pProcess = TheDProcessTracker.FindProcess(eventMetaData.iTargetProcessName); - if (pProcess == NULL) - { - LOG_MSG("Cannot identify process being debugged"); - - // We could not locate the process, so the user asked for the wrong one. - Kern::RequestComplete(iClientThread, aStatus, KErrArgument); - return; - } - - // Find the agent - DDebugAgent* debugAgent = pProcess->Agent(eventMetaData.iDebugAgentProcessId); - LOG_MSG5(" For agent pid=%d, DTargetProcess=0x%08x, Agent=0x%08x, iAsyncGetValueRequest0x%08x", - I64LOW(eventMetaData.iDebugAgentProcessId), pProcess, debugAgent, iAsyncGetValueRequest ); - - if (debugAgent == NULL) - { - // Bad agent means there is no tracking agent - LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",eventMetaData.iDebugAgentProcessId); - return; - } - // Agent completes/pends the request as appropriate. - debugAgent->GetEvent(iAsyncGetValueRequest, iClientThread); - - break; - } - default: - { - // Don't know what to do, should not get here! - LOG_MSG("DRM_DebugChannel::DoRequest was passed an unsupported request aReqNo"); - - Kern::RequestComplete(iClientThread, aStatus, KErrNotSupported); - } - } - } - -// -// DRM_DebugChannel::DoControl -// -TInt DRM_DebugChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) - { - LOG_MSG("DRM_DebugChannel::DoControl()"); - - LOG_MSG2("DoControl Function %d", aFunction); - - TInt err = KErrBadHandle; - DThread* threadObj = NULL; - - switch(aFunction) - { - /* Security first */ - case RRM_DebugDriver::EControlIsDebuggable: - { - err = IsDebuggable((TUint32)a1); - break; - } - case RRM_DebugDriver::EControlSetBreak: - { - err = SetBreak((TSetBreakInfo*)a1); - break; - } - case RRM_DebugDriver::EControlClearBreak: - { - err = iBreakManager->DoClearBreak((TInt32)a1); - break; - } - case RRM_DebugDriver::EControlModifyBreak: - { - err = iBreakManager->DoModifyBreak((TModifyBreakInfo*)a1); - break; - } - case RRM_DebugDriver::EControlModifyProcessBreak: - { - err = iBreakManager->DoModifyProcessBreak((TModifyProcessBreakInfo*)a1); - break; - } - case RRM_DebugDriver::EControlBreakInfo: - { - err = iBreakManager->DoBreakInfo((TGetBreakInfo*)a1); - break; - } - case RRM_DebugDriver::EControlSuspendThread: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = DoSuspendThread(threadObj); - } - break; - } - case RRM_DebugDriver::EControlResumeThread: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = DoResumeThread(threadObj); - } - break; - } - case RRM_DebugDriver::EControlStepRange: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = StepRange(threadObj, (TRM_DebugStepInfo*)a2); - } - break; - } - case RRM_DebugDriver::EControlReadMemory: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = ReadMemory(threadObj, (TRM_DebugMemoryInfo*)a2); - } - break; - } - case RRM_DebugDriver::EControlWriteMemory: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = WriteMemory(threadObj, (TRM_DebugMemoryInfo*)a2); - } - break; - } - case RRM_DebugDriver::EControlReadRegistersLegacy: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = ReadRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); - } - break; - } - case RRM_DebugDriver::EControlWriteRegistersLegacy: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = WriteRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); - } - break; - } - case RRM_DebugDriver::EControlReadRegisters: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = ReadRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); - } - break; - } - case RRM_DebugDriver::EControlWriteRegisters: - { - threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); - if (threadObj) - { - err = WriteRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); - } - break; - } - case RRM_DebugDriver::EControlGetDebugFunctionalityBufSize: - { - LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionalityBufSize\n"); - - TDebugFunctionality df; - - TUint size = df.GetDebugFunctionalityBufSize(); - - // Return size to user-side in a safe manner - err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&size, sizeof(TUint), iClientThread); - break; - } - case RRM_DebugDriver::EControlGetDebugFunctionality: - { - LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionality\n"); - - TDebugFunctionality df; - - TUint32 dfsize = df.GetDebugFunctionalityBufSize(); - - // Alloc tmp buffer for Debug Functionality data - NKern::ThreadEnterCS(); - TUint8* dfbuffer = (TUint8*)Kern::AllocZ(dfsize); - NKern::ThreadLeaveCS(); - if (dfbuffer==NULL) - { - LOG_MSG2("Could not allocate memory for %d bytes\n",dfsize); - - // could not allocate memory - return KErrNoMemory; - } - - // Temporary descriptor to hold DF data - TPtr8 tmpPtr(dfbuffer,0,dfsize); - - // Obtain the DF data - if (df.GetDebugFunctionality(tmpPtr) ) - { - // Return the DF data to the user-side - err = Kern::ThreadDesWrite(iClientThread, a1, tmpPtr, 0, KChunkShiftBy0, iClientThread); - } - else - { - // Failed. - err = KErrGeneral; - } - - // Free tmp buffer - NKern::ThreadEnterCS(); - Kern::Free(dfbuffer); - NKern::ThreadLeaveCS(); - break; - } - case RRM_DebugDriver::EControlAttachProcess: - { - LOG_MSG("RRM_DebugDriver::EControlAttachProcess"); - - err = AttachProcess(a1,a2); - break; - } - case RRM_DebugDriver::EControlDetachProcess: - { - LOG_MSG("RRM_DebugDriver::EControlDetachProcess"); - - err = DetachProcess(a1,a2); - break; - } - case RRM_DebugDriver::EControlDetachAgent: - { - LOG_MSG("RRM_DebugDriver::EControlDetachAgent"); - - err = DetachAgent(a1,a2); - break; - } - case RRM_DebugDriver::EControlSetEventAction: - { - LOG_MSG("RRM_DebugDriver::EControlSetEventAction"); - - err = SetEventAction(a1,a2); - break; - } - case RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize: - { - LOG_MSG("RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize\n"); - - TUint32 maxSize = TDebugFunctionality::GetMemoryOperationMaxBlockSize(); - - // Return size to user-side in a safe manner - err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&maxSize, sizeof(TUint32), iClientThread); - break; - } - case RRM_DebugDriver::EControlGetList: - { - LOG_MSG("RRM_DebugDriver::EControlGetList\n"); - err = GetList((TListInformation*)a1); - break; - } - case RRM_DebugDriver::EControlStep: - { - LOG_MSG("RRM_DebugDriver::EControlStep\n"); - - err = Step((TUint32)a1,(TUint32)a2); - break; - } - case RRM_DebugDriver::EControlKillProcess: - { - LOG_MSG("RRM_DebugDriver::EControlKillProcess\n"); - - err = KillProcess((TUint32)a1,(TUint32)a2); - break; - } - default: - { - err = KErrGeneral; - } - } - - if (KErrNone != err) - { - LOG_MSG2("Error %d from control function", err); - } - - if (threadObj) - { - // Close the thread handle which has been opened by DebugUtils::OpenThreadHandle - threadObj->Close(NULL); - } - - return err; - } - -void DRM_DebugChannel::HandleMsg(TMessageBase* aMsg) - { - LOG_MSG("DRM_DebugChannel::HandleMsg()"); - - TThreadMessage& m = *(TThreadMessage*)aMsg; - TInt id = m.iValue; - - if (id == (TInt)ECloseMsg) - { - if (iEventHandler) - { - iEventHandler->Stop(); - iEventHandler->Close(); - iEventHandler = NULL; - } - m.Complete(KErrNone, EFalse); - return; - } - - if (id == KMaxTInt) - { - // DoCancel - DoCancel(m.Int0()); - m.Complete(KErrNone, ETrue); - return; - } - - if (id < 0) - { - // DoRequest - TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); - DoRequest(~id, pStatus, m.Ptr1(), m.Ptr2()); - m.Complete(KErrNone, ETrue); - } - else - { - // DoControl - TInt err = DoControl(id, m.Ptr0(), m.Ptr1()); - m.Complete(err, ETrue); - } - } - -// -// DRM_DebugChannel::RemoveProcess -// -TBool DRM_DebugChannel::RemoveProcess(TAny* a1, TAny* a2) - { - LOG_MSG("DRM_DebugChannel::RemoveProcess()"); - - DProcess *aProcess = (DProcess*)a1; - - // Sanity check - if (!aProcess) - { - // No process was specified! - LOG_MSG("DRM_DebugChannel::RemoveProcess was called with an invalid process ID"); - return EFalse; - } - - // this is called when a process dies. we want to mark any breakpoints in this - // process space as obsolete. the main reason for this is so we don't return - // an error when the host debugger tries to clear breakpoints for the process - - TUint32 codeAddress = 0; - TUint32 codeSize = 0; - - LOG_EVENT_MSG2("Process being removed, Name %S", aProcess->iName); - - DCodeSeg* codeSeg = aProcess->iCodeSeg; - - if (codeSeg) - { - TModuleMemoryInfo processMemoryInfo; - TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, aProcess); - if (err != KErrNone) - { - codeAddress = processMemoryInfo.iCodeBase; - codeSize = processMemoryInfo.iCodeSize; - } - else - { - LOG_MSG2("Error in getting memory info: %d", err); - } - } - - if (!codeAddress || !codeSize) - { - LOG_EVENT_MSG2("Code segment not available for process %d", aProcess->iId); - // make sure there is not already a breakpoint at this address - for (TInt i = 0; i < iDebugProcessList.Count(); i++) - { - if (iDebugProcessList[i].iId == aProcess->iId) - { - codeAddress = iDebugProcessList[i].iCodeAddress; - codeSize = iDebugProcessList[i].iCodeSize; - - //now remove from the list - iDebugProcessList.Remove(i); - break; - } - } - } - - if (!codeAddress || !codeSize) - { - return EFalse; - } - - iBreakManager->RemoveBreaksForProcess(aProcess->iId, codeAddress, codeSize); - return EFalse; - } - -// -// DRM_DebugChannel::StartThread -// -TBool DRM_DebugChannel::StartThread(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::StartThread()"); - - DThread *aThread = (DThread*)a1; - if(!aThread) - { - LOG_MSG("Error getting DThread object"); - __NK_ASSERT_DEBUG(aThread); - return EFalse; - } - - //a2 points to the thread creating the new thread. - //We have no use for it at the moment so just ignore it for now - - TDriverEventInfo info; - info.iEventType = EEventsStartThread; - info.iThreadId = aThread->iId; - info.iThreadIdValid = ETrue; - DProcess* owningProcess = aThread->iOwningProcess; - if(owningProcess) - { - info.iProcessId = owningProcess->iId; - info.iProcessIdValid = ETrue; - DCodeSeg* p = owningProcess->iCodeSeg; - if(p && p->iFileName) - { - info.iFileName.Copy(*(p->iFileName)); - DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(p->iFileName)); - if(foundProcess) - { - foundProcess->NotifyEvent(info); - } - else - { - LOG_EVENT_MSG2("Couldn't find process with name [%S]", p->iFileName); - } - } - else - { - if(p) - { - LOG_EVENT_MSG("\tCode segment name missing"); - } - else - { - LOG_EVENT_MSG("\tCode segment is NULL"); - } - } - } - return EFalse; - } - -// -// DRM_DebugChannel::HandleAddProcessEvent -// -TBool DRM_DebugChannel::HandleAddProcessEvent(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::AddProcess()"); - - DProcess *aProcess = (DProcess*)a1; - // a2 points to the thread creating the new process. - DThread *aThread = (DThread*)a2; - - if(!aProcess) - { - LOG_MSG("Error getting DProcess object"); - __NK_ASSERT_DEBUG(aProcess); - return EFalse; - } - - TDriverEventInfo info; - info.iEventType = EEventsAddProcess; - info.iProcessId = aProcess->iId; - - info.iCreatorThreadId = aThread ? aThread->iId : 0; - info.iProcessIdValid = ETrue; - - // Copy TUids - info.iUids = aProcess->iUids; - - info.iUidsValid = ETrue; - - // copy name of the process - if (aProcess->iName) - { - // copy the name of the process - info.iFileName.Copy(*aProcess->iName); - - DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(aProcess->iName)); - if(foundProcess) - { - foundProcess->NotifyEvent(info); - } - else - { - // AddProcess event does not have fully-qualified path, it has "filename.exe" - // So we try a less-precise match - DTargetProcess* foundProcess = TheDProcessTracker.FuzzyFindProcess(*(aProcess->iName)); - if(foundProcess) - { - foundProcess->NotifyEvent(info); - } - else - { - LOG_EVENT_MSG2("Couldn't find process with name [%S]", aProcess->iName); - } - } - } - else - { - LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); - } - - return EFalse; - } - -// -// DRM_DebugChannel::HandleRemoveProcessEvent -// -TBool DRM_DebugChannel::HandleRemoveProcessEvent(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::RemoveProcess()"); - - DProcess *aProcess = (DProcess*)a1; - if(!aProcess) - { - LOG_MSG("Error getting DProcess object"); - __NK_ASSERT_DEBUG(aProcess); - return EFalse; - } - - // a2 points to the thread creating the new process. - // We have no use for it at the moment so just ignore it for now - // Also, it may not be known and therefore NULL - - TDriverEventInfo info; - info.iEventType = EEventsRemoveProcess; - info.iProcessId = aProcess->iId; - info.iProcessIdValid = ETrue; - - // copy name of the process - if (aProcess->iName) - { - // copy the name of the process - info.iFileName.Copy(*aProcess->iName); - - DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(aProcess->iName)); - if(foundProcess) - { - foundProcess->NotifyEvent(info); - } - else - { - // RemoveProcess event does not have fully-qualified path, it has "filename.exe" - // So we try a less-precise match - DTargetProcess* foundProcess = TheDProcessTracker.FuzzyFindProcess(*(aProcess->iName)); - if(foundProcess) - { - foundProcess->NotifyEvent(info); - } - else - { - LOG_EVENT_MSG2("Couldn't find process with name [%S]", aProcess->iName); - } - } - - } - else - { - LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); - } - - return EFalse; - } - -// -// DRM_DebugChannel::AddLibrary -// -TBool DRM_DebugChannel::AddLibrary(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary()"); - - DLibrary *aLibrary = (DLibrary*)a1; - DThread *aThread = (DThread*)a2; - - // sanity check - if (!aLibrary) - { - LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no library specified"); - return EFalse; - } - - if (!aThread) - { - LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no thread specified"); - return EFalse; - } - - LOG_EVENT_MSG2(("Lib loaded: %S"), aLibrary->iName); - - if (aThread) - { - // make sure this is not the debugger thread - if ((aThread != iClientThread) && (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) - { - TDriverEventInfo info; - - info.iEventType = EEventsAddLibrary; - info.iProcessId = aThread->iOwningProcess->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = aThread->iId; - info.iThreadIdValid = ETrue; - - //get the code address - DCodeSeg* codeSeg = aLibrary->iCodeSeg; - if (!codeSeg) - { - LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); - return EFalse; - } - - // Uid3 - info.iUids = codeSeg->iUids; - info.iUidsValid = ETrue; - - TModuleMemoryInfo memoryInfo; - TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; - if (err != KErrNone) - { - LOG_EVENT_MSG2("Error in getting memory info: %d", err); - return EFalse; - } - - info.iCodeAddress = memoryInfo.iCodeBase; - info.iDataAddress = memoryInfo.iInitialisedDataBase; - - info.iFileName.Copy(*(aLibrary->iName)); //just the name, without uid info. - - //queue up or complete the event - info.iArg1 = a1; - info.iArg2 = a2; - NotifyEvent(info); - } - - } - return EFalse; - } - -// -// DRM_DebugChannel::RemoveLibrary -// -TBool DRM_DebugChannel::RemoveLibrary(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary()"); - DLibrary *aLibrary = (DLibrary*)a1; - - // sanity check - if (!aLibrary) - { - LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary called with no library specified"); - return EFalse; - } - - LOG_EVENT_MSG2(("Lib unloaded: %S"), aLibrary->iName); - - // this is called when all handles to this library have been closed. this can happen when a process dies, or when a dll is - // unloaded while the process lives on. in former case, we don't need to notify the host debugger because that process is - // dying anyway. for the latter case, we do need to notify the host so it can unload the symbolics, etc. - - DThread* aThread = &Kern::CurrentThread(); - - if ((aThread) && - (aThread != iClientThread) && - (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) - { - //the library gets unloaded only when the mapcount is 0. - if (aLibrary->iMapCount != 0) - return EFalse; - - DCodeSeg* codeSeg = aLibrary->iCodeSeg; - if (!codeSeg) - { - LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); - return EFalse; - } - - TModuleMemoryInfo processMemoryInfo; - TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, NULL); //passing NULL for the DProcess argument should be ok; - if (err != KErrNone) - { - LOG_EVENT_MSG2("Error in getting memory info: %d", err); - return EFalse; - } - - TUint32 codeAddress = processMemoryInfo.iCodeBase; - TUint32 codeSize = processMemoryInfo.iCodeSize; - - // first invalidate all breakpoints that were set in the library code - iBreakManager->InvalidateLibraryBreakPoints(codeAddress, codeSize); - DProcess *process = &Kern::CurrentProcess(); - RArray* dynamicCode = &(process->iDynamicCode); - - for (TInt j=0; jCount(); j++) - { - if ((*dynamicCode)[j].iLib == aLibrary) - { - TDriverEventInfo info; - - info.iEventType = EEventsRemoveLibrary; - info.iFileName.Copy(*(aLibrary->iName)); //lib name without uid info - //info.iFileName.ZeroTerminate(); - info.iProcessId = process->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = 0xFFFFFFFF; // don't care! - info.iThreadIdValid = EFalse; - // Uid3 - info.iUids = codeSeg->iUids; - info.iUidsValid = ETrue; - - //queue up or complete the event - info.iArg1 = a1; - info.iArg2 = a2; - NotifyEvent(info); - } - } - } - return EFalse; - } - -// -// DRM_DebugChannel::HandleEventKillThread -// -TBool DRM_DebugChannel::HandleEventKillThread(TAny* a1, TAny* a2) - { - - LOG_MSG2("DRM_DebugChannel::HandleEventKillThread(Thread a1=0x%08x)", a1 ); - - DThread* currentThread = &Kern::CurrentThread(); - if (!currentThread) - { - LOG_MSG("Error getting current thread"); - __NK_ASSERT_DEBUG(currentThread); - return EFalse; - } - - // a1 should point to the current thread, check this to make sure it does - __NK_ASSERT_DEBUG((DThread*)a1 == currentThread); - - TDriverEventInfo info; - - info.iProcessId = currentThread->iOwningProcess->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = currentThread->iId; - info.iThreadIdValid = ETrue; - // 14 should probably be replaced by PC_REGISTER, for some reason PC_REGISTER had been replaced with 14 in the code - TInt err = ReadKernelRegisterValue(currentThread, 14, info.iCurrentPC); - if(err != KErrNone) - { - LOG_EVENT_MSG2("DRM_DebugChannel::HandleEventKillThread - Non-zero error code discarded: %d", err); - } - - if (currentThread->iExitType == EExitPanic) - { - info.iPanicCategory.Copy(currentThread->iExitCategory); - } - info.iExceptionNumber = currentThread->iExitReason; - info.iExitType = currentThread->iExitType; - info.iEventType = EEventsKillThread; - - // Are we debugging this process - decide based on iFileName - DCodeSeg* codeSeg = currentThread->iOwningProcess->iCodeSeg; - - // remove all the breakpoints in this thread, whether we are debugging it or not. - iBreakManager->DoRemoveThreadBreaks(info.iThreadId); - - // if the code seg exists then get the file name from it and check we're debugging it - if(codeSeg) - { - DTargetProcess* foundProcess = TheDProcessTracker.FindProcess(*(codeSeg->iFileName)); - if(!foundProcess) - { - // not debugging this process so return false - return EFalse; - } - } - else - { - // can't validate that we are debugging the thread - return EFalse; - } - - info.iArg1 = a1; - info.iArg2 = a2; - NotifyEvent(info); - - return ETrue; - } - -// -// DRM_DebugChannel::HandleSwException -// -TBool DRM_DebugChannel::HandleSwException(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::HandleSwException"); - TExcType aExcType = (TExcType)(TInt)a1; - - TDriverEventInfo info; - - DThread* currentThread = &Kern::CurrentThread(); - if (!currentThread) - { - LOG_MSG("Error getting current thread"); - __NK_ASSERT_DEBUG(currentThread); - return EFalse; - } - - info.iProcessId = currentThread->iOwningProcess->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = currentThread->iId; - info.iThreadIdValid = ETrue; - TInt err = ReadKernelRegisterValue(currentThread, PC_REGISTER, info.iCurrentPC); - if(err != KErrNone) - { - LOG_EVENT_MSG2("DRM_DebugChannel::HandleSwException - Non-zero error code discarded: %d", err); - } - info.iExceptionNumber = aExcType; - info.iEventType = EEventsSwExc; - info.iArg1 = a1; - info.iArg2 = a2; - - NotifyEvent(info); - - return EFalse; - } - -// -// DRM_DebugChannel::HandleHwException -// -TBool DRM_DebugChannel::HandleHwException(TAny* a1, TAny* a2) - { - TArmExcInfo* aExcInfo = (TArmExcInfo*)a1; - - // sanity check - if (!aExcInfo) - { - LOG_MSG("DRM_DebugChannel::HandleHwException called with no aExcInfo"); - __NK_ASSERT_DEBUG(aExcInfo); - return EFalse; - } - - TDriverEventInfo info; - - DThread* currentThread = &Kern::CurrentThread(); - - if (!currentThread) - { - LOG_MSG("Error getting current thread"); - __NK_ASSERT_DEBUG(currentThread); - return EFalse; - } - - info.iProcessId = currentThread->iOwningProcess->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = currentThread->iId; - info.iThreadIdValid = ETrue; - info.iRmdArmExcInfo.iFaultAddress= aExcInfo->iFaultAddress; - info.iRmdArmExcInfo.iFaultStatus= aExcInfo->iFaultStatus; - - LOG_MSG5("DRM_DebugChannel::HandleHwException current thread = 0x%08x, CritSect count=%d,\n" - " iFaultAddress=0x%08x, iFaultStatus=0x%08x", - currentThread, currentThread->iNThread.iCsCount, aExcInfo->iFaultAddress, aExcInfo->iFaultStatus); - - info.iRmdArmExcInfo.iR0= aExcInfo->iR0; - info.iRmdArmExcInfo.iR1= aExcInfo->iR1; - info.iRmdArmExcInfo.iR2= aExcInfo->iR2; - info.iRmdArmExcInfo.iR3= aExcInfo->iR3; - - info.iRmdArmExcInfo.iR4= aExcInfo->iR4; - info.iRmdArmExcInfo.iR5= aExcInfo->iR5; - info.iRmdArmExcInfo.iR6= aExcInfo->iR6; - info.iRmdArmExcInfo.iR7= aExcInfo->iR7; - info.iRmdArmExcInfo.iR8= aExcInfo->iR8; - info.iRmdArmExcInfo.iR9= aExcInfo->iR9; - info.iRmdArmExcInfo.iR10= aExcInfo->iR10; - info.iRmdArmExcInfo.iR11= aExcInfo->iR11; - info.iRmdArmExcInfo.iR12= aExcInfo->iR12; - - info.iRmdArmExcInfo.iR13= aExcInfo->iR13; - info.iRmdArmExcInfo.iR14= aExcInfo->iR14; - info.iRmdArmExcInfo.iR15= aExcInfo->iR15; - - info.iRmdArmExcInfo.iCpsr= aExcInfo->iCpsr; - info.iRmdArmExcInfo.iR13Svc= aExcInfo->iR13Svc; - info.iRmdArmExcInfo.iR14Svc= aExcInfo->iR14Svc; - info.iRmdArmExcInfo.iSpsrSvc= aExcInfo->iSpsrSvc; - LOG_MSG5(" iCpsr=0x%x, iExcCode=0x%x, R14=0x%x, R15=0x%x", - aExcInfo->iCpsr, aExcInfo->iExcCode, aExcInfo->iR14, aExcInfo->iR15); - - switch (aExcInfo->iExcCode) - { - case 0: - info.iExceptionNumber = EExcCodeAbort; - LOG_EVENT_MSG(" iExcCode == 0 => EExcCodeAbort"); - break; - case 1: - info.iExceptionNumber = EExcDataAbort; - LOG_EVENT_MSG(" iExcCode == 1 => EExcDataAbort"); - break; - case 2: - info.iExceptionNumber = EExcInvalidOpCode; - LOG_EVENT_MSG(" iExcCode == 2 => EExcInvalidOpCode"); - break; - default: - // new event? Something gone wrong? - __NK_ASSERT_DEBUG(EFalse); - return EFalse; - } - - info.iEventType = EEventsHwExc; - - info.iArg1 = a1; - info.iArg2 = a2; - - if(EExcInvalidOpCode == info.iExceptionNumber) - { - return HandleInvalidOpCodeException(info, currentThread); - } - - NotifyEvent(info); - return EFalse; - } - -// -// DRM_DebugChannel::HandUserTrace -// -TBool DRM_DebugChannel::HandleUserTrace(TAny* a1, TAny* a2) - { - LOG_EVENT_MSG("DRM_DebugChannel::HandleUserTrace()"); - - DThread* currentThread = &Kern::CurrentThread(); - if (!currentThread) - { - LOG_EVENT_MSG("Error getting current thread"); - __NK_ASSERT_DEBUG(currentThread); - return EFalse; - } - - TDriverEventInfo info; - info.iProcessId = currentThread->iOwningProcess->iId; - info.iProcessIdValid = ETrue; - info.iThreadId = currentThread->iId; - info.iThreadIdValid = ETrue; - info.iEventType = EEventsUserTrace; - info.iArg1 = a1; - info.iArg2 = a2; - - TInt err = KErrNone; - - //User Trace info - XTRAP(err, XT_DEFAULT, kumemget(info.iUserTraceText, info.iArg1, (TInt)a2)); - if(KErrNone != err) - { - return EFalse; - } - - info.iMessageStatus = ESingleMessage; - - NotifyEvent(info); - - return EFalse; - } - -// -// DRM_DebugChannel::HandleException -// -TBool DRM_DebugChannel::HandleInvalidOpCodeException(TDriverEventInfo& aEventInfo, DThread* aCurrentThread) - { - LOG_EVENT_MSG("DRM_DebugChannel::HandleInvalidOpCodeException()"); - - TInt err = KErrNone; - - TUint32 inst = KArmBreakPoint; - TInt instSize = 4; - - // change these for thumb mode - TUint32 regValue; - err = ReadKernelRegisterValue(aCurrentThread, STATUS_REGISTER, regValue); - if(err != KErrNone) - { - LOG_EVENT_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException - Non-zero error code discarded: %d", err); - } - - if (regValue & ECpuThumb) - { - inst = KThumbBreakPoint; - instSize = 2; - } - - TUint32 instruction = 0; - err = Kern::ThreadRawRead(aCurrentThread, (TUint32 *)aEventInfo.iRmdArmExcInfo.iR15, (TUint8 *)&instruction, instSize); - - if (KErrNone != err) - LOG_MSG2("Error reading instruction at currentpc: %d", err); - - if (!memcompare((TUint8 *)&inst, instSize, (TUint8 *)&instruction, instSize)) - { - TInt err = DoSuspendThread(aCurrentThread); - if(! ((KErrNone == err) || (KErrAlreadyExists == err)) ) - { - LOG_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException() Thread with id 0x%08x could not be suspended.", aCurrentThread->iId); - return EFalse; - } - - // the exception was a breakpoint instruction. see if we have a breakpoint at that address - TBreakEntry* breakEntry = NULL; - do - { - breakEntry = iBreakManager->GetNextBreak(breakEntry); - if (breakEntry && ((breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iThreadId) || (!breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iProcessId)) && breakEntry->iAddress == aEventInfo.iRmdArmExcInfo.iR15) - { - LOG_EVENT_MSG2("Breakpoint with Id %d has been hit", breakEntry->iBreakId); - - TBreakEntry tempBreakEntry = *breakEntry; - - //change the event type to breakpoint type - aEventInfo.iEventType = breakEntry->iThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint; - - // enable any breakpoints we had to disable for this thread - err = iBreakManager->DoEnableDisabledBreak(aEventInfo.iThreadId); - if (KErrNone != err) - LOG_MSG2("Error %d enabling disabled breakpoints", err); - - // see if this is a temp breakpoint - if (iBreakManager->IsTemporaryBreak(*breakEntry)) - { - // this was a temp breakpoint, so we need to clear it now - err = iBreakManager->DoClearBreak(breakEntry->iBreakId); - if (KErrNone != err) - LOG_MSG2("Error %d clearing temp breakpoint", err); - - // Find out how many steps remain to be done - - // reduce the number of steps to complete by 1 - tempBreakEntry.iNumSteps--; - - LOG_EVENT_MSG2("There are %d steps remaining\n", tempBreakEntry.iNumSteps); - - // New. If we have not finished do all the steps, continue stepping and don't notify event - if (tempBreakEntry.iNumSteps) - { - LOG_EVENT_MSG("Continuing stepping...not telling the agent yet\n"); - err = DoStepRange(aCurrentThread, aEventInfo.iRmdArmExcInfo.iR15, aEventInfo.iRmdArmExcInfo.iR15, ETrue, tempBreakEntry.iResumeOnceOutOfRange /*EFalse*/, tempBreakEntry.iNumSteps, ETrue); - if (err != KErrNone) - { - LOG_EVENT_MSG("Failed to continue stepping\n"); - - // what do we do? might as well stop here and tell the user - NotifyEvent(aEventInfo); - - return ETrue; - } - - // continue as though no event occured. No need to suspend/resume anything... - LOG_EVENT_MSG("Continuing to step\n"); - return ETrue; - } - - // Is this a case where we just want to continue? - if (tempBreakEntry.iResumeOnceOutOfRange) - { - LOG_EVENT_MSG("PC is out of range, continuing thread"); - DoResumeThread(aCurrentThread); - - return ETrue; - } - } - - // if the breakpoint is thread specific, make sure it's the right thread - // if not, just continue the thread. take special care if it's the debugger - // thread. if it hits a regular breakpoint, we NEVER want to stop at it. if - // it hits a temp breakpoint, we're probably just stepping past a real breakpoint - // and we do need to handle it. - TBool needToResume = (tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iThreadId) || - (!tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iProcessId); - - if (needToResume) - { - LOG_EVENT_MSG("breakpoint does not match threadId, calling DoResumeThread"); - err = DoResumeThread(aCurrentThread); - if (KErrNone != err) - LOG_MSG2("Error in DoResumeThread: %d", err); - - return EFalse; - } - - //normal user break point, just notify the event - break; - } - } while(breakEntry); - } - - NotifyEvent(aEventInfo); - - return (aEventInfo.iEventType == EEventsBreakPoint) || (aEventInfo.iEventType == EEventsProcessBreakPoint); - } - -// -// DRM_DebugChannel::SetBreak -// -TInt DRM_DebugChannel::SetBreak(TSetBreakInfo* aBreakInfo) - { - LOG_MSG("DRM_DebugChannel::SetBreak()"); - - TInt err = KErrNone; - - if (!aBreakInfo) - { - LOG_MSG("DRM_DebugChannel::SetBreak() was passed a NULL argument"); - return KErrArgument; - } - - //User side memory is not accessible directly - TSetBreakInfo info; - err = Kern::ThreadRawRead(iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TSetBreakInfo)); - if (err != KErrNone) - { - LOG_MSG("DRM_DebugChannel::SetBreak() was passed a bad argument"); - return err; - } - - DProcess* process = NULL; - if(info.iThreadSpecific) - { - // if the target thread is not suspended then return KErrInUse - if(!TheDProcessTracker.CheckSuspended(info.iId)) - { - LOG_MSG2("DRM_DebugChannel::SetBreak() Thread with id 0x%08x not suspended.", info.iId); - return KErrInUse; - } - DThread* thread = DebugUtils::OpenThreadHandle(info.iId); - if(!thread) - { - LOG_MSG2("DRM_DebugChannel::SetBreak() Thread with id 0x%08x not found", info.iId); - return KErrNotFound; - } - process = DebugUtils::OpenProcessHandle(thread->iOwningProcess->iId); - thread->Close(NULL); - } - else - { - process = DebugUtils::OpenProcessHandle(info.iId); - } - - if(!process) - { - LOG_MSG2("DRM_DebugChannel::SetBreak() Process with id 0x%08x not found", process->iId); - return KErrNotFound; - } - - TBool found = EFalse; - for(TInt i=0; iiId == iDebugProcessList[i].iId) - { - found = ETrue; - } - } - - if(!found) - { - DCodeSeg* codeSeg = process->iCodeSeg; - if (!codeSeg) - { - LOG_MSG2("DRM_DebugChannel::SetBreak() Code seg for process with id 0x%08x not found", process->iId); - return KErrNotFound; - } - - TModuleMemoryInfo memoryInfo; - TInt err = codeSeg->GetMemoryInfo(memoryInfo, process); - if (err != KErrNone) - { - LOG_MSG2("DRM_DebugChannel::SetBreak() Error getting memory info for process with id 0x%08x", process->iId); - return err; - } - - //add this process to the list of processes that we are debugging - TProcessInfo processInfo(process->iId, memoryInfo.iCodeBase, memoryInfo.iCodeSize, memoryInfo.iInitialisedDataBase); - iDebugProcessList.Append(processInfo); - process->Close(NULL); - } - - if (!info.iBreakId) //first check if the iId address is valid - return KErrArgument; - - if (err == KErrNone) - { - TInt32 iBreakId; - - err = iBreakManager->DoSetBreak(iBreakId, info.iId, info.iThreadSpecific, info.iAddress, info.iMode ); - - if (err == KErrNone) - { - err = Kern::ThreadRawWrite(iClientThread, (TUint8 *)info.iBreakId, &iBreakId, sizeof(TInt32), iClientThread); - } - } - - return err; - } - -// -// DRM_DebugChannel::StepRange -// -TInt DRM_DebugChannel::StepRange(DThread* aThread, TRM_DebugStepInfo* aStepInfo) - { - LOG_MSG("DRM_DebugChannel::StepRange()"); - - TInt err = KErrNone; - - if(!TheDProcessTracker.CheckSuspended(aThread)) - { - LOG_MSG2("DRM_DebugChannel::StepRange() Thread with id 0x%08x not suspended.", aThread->iId); - return KErrInUse; - } - - if (!aStepInfo) - return KErrArgument; - - TRM_DebugStepInfo info(0, 0, 0); - err = Kern::ThreadRawRead(iClientThread, aStepInfo, (TUint8*)&info, sizeof(TRM_DebugStepInfo)); - - if (err != KErrNone) - return err; - - err = DoStepRange(aThread, info.iStartAddress, info.iStopAddress, info.iStepInto, EFalse, ETrue); - - return err; - } - -/** -Read memory from a target thread and return the data to the client. If the -memory block has breakpoints in it then the correct values are placed in the -returned data - -@param aThread pointer to thread whose memory space the memory is to be read from -@param aMemoryInfo information about what memory to read - -@return KErrNone if memory read successfully, - KErrArgument if aMemoryInfo is not initialised correctly, - KErrNoMemory if a temporary buffer could not be allocated, - KErrBadHandle if aThread is invalid, - or another of the system wide error codes -*/ -TInt DRM_DebugChannel::ReadMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) - { - LOG_MSG("DRM_DebugChannel::ReadMemory()"); - - TInt err = KErrNone; - - if (!aMemoryInfo) - return KErrArgument; - - TRM_DebugMemoryInfo info(0, 0, 0); - err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); - if (err != KErrNone) - return err; - - if (!info.iData) - return KErrArgument; - - NKern::ThreadEnterCS(); - TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); - NKern::ThreadLeaveCS(); - if (!data) - { - return KErrNoMemory; - } - - TPtr8 dataDes(data, info.iLength); - - err = DoReadMemory(aThread, info.iAddress, info.iLength, dataDes); - if (err == KErrNone) - { - err = Kern::ThreadDesWrite(iClientThread, info.iData, dataDes, 0, KChunkShiftBy0, iClientThread); - } - - NKern::ThreadEnterCS(); - Kern::Free(data); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -Attempt to write memory to aThread's address space - -@param aThread thread to whose address space memory is to be written -@param aMemoryInfo memory info object representing the data to write - -@return KErrNone if memory written successfully, - KErrNoMemory if memory could not be allocated - KErrArgument if aMemoryInfo is NULL, if aMemoryInfo.iData is NULL, - if aMemoryInfo.iLength is greater than than the length of the passed - in descrptor - KErrBadHandle if aThread is invalid, - or another of the system wide error codes -*/ -TInt DRM_DebugChannel::WriteMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) - { - LOG_MSG("DRM_DebugChannel::WriteMemory()"); - - TInt err = KErrNone; - - if (!aMemoryInfo) - return KErrArgument; - - TRM_DebugMemoryInfo info(0, 0, 0); - err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); - if (err != KErrNone) - return err; - - if (!info.iData) - return KErrArgument; - - NKern::ThreadEnterCS(); - TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); - NKern::ThreadLeaveCS(); - if (!data) - { - return KErrNoMemory; - } - - TPtr8 dataDes(data, info.iLength); - - err = Kern::ThreadDesRead(iClientThread, info.iData, dataDes, 0); - if (err == KErrNone) - { - err = DoWriteMemory(aThread, info.iAddress, info.iLength, dataDes); - } - - NKern::ThreadEnterCS(); - Kern::Free(data); - NKern::ThreadLeaveCS(); - - return err; - } - -// -// DRM_DebugChannel::ReadRegisters -// -TInt DRM_DebugChannel::ReadRegistersLegacy(DThread* aThread, TRM_DebugRegisterInfo* aRegisterInfo) - { - LOG_MSG("DRM_DebugChannel::ReadRegistersLegacy()"); - - TInt err = KErrNone; - - if (!aRegisterInfo) - return KErrArgument; - - TRM_DebugRegisterInfo info(0, 0, 0); - err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); - if (err != KErrNone) - return err; - - if (!info.iValues) - return KErrArgument; - - TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; - - NKern::ThreadEnterCS(); - TUint8 *values = (TUint8*)Kern::Alloc(length); - NKern::ThreadLeaveCS(); - if (!values) - { - return KErrNoMemory; - } - - TPtr8 valuesDes(values, length); - - err = DoReadRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); - if (err == KErrNone) - { - err = Kern::ThreadDesWrite(iClientThread, info.iValues, valuesDes, 0, KChunkShiftBy0, iClientThread); - } - - NKern::ThreadEnterCS(); - Kern::Free(values); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -Get listing information. - -@param aListInformation pointer to a TListInformation object containing the - user specified listings information - -@return KErrNone on success, - KErrTooBig if the kernel's data is too big to fit in the passed buffer, - KErrArgument if aListInformation is NULL, - or one of the other system-wide error codes -*/ -TInt DRM_DebugChannel::GetList(TListInformation* aListInformation) const - { - LOG_MSG("DRM_DebugChannel::GetList()"); - - TInt err = KErrNone; - - if(aListInformation == NULL) - { - return KErrArgument; - } - - //read DSS' data into local structure - TListInformation info; - err = Kern::ThreadRawRead(iClientThread, aListInformation, (TUint8*)&info, sizeof(TListInformation)); - if(err != KErrNone) - { - return err; - } - - //check arguments - TPtr8 buffer(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iBuffer, buffer); - if(err != KErrNone) - { - //need to free the buffer if it was allocated - if(err != KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)buffer.Ptr()); - NKern::ThreadLeaveCS(); - } - return err; - } - - //get the list - TUint32 dataSize = 0; - TListManager manager; - err = KErrArgument; - switch(info.iType) - { - case EXipLibraries: - if(Debug::EScopeGlobal == info.iListScope) - { - err = manager.GetXipLibrariesList(buffer, dataSize); - } - break; - - case EThreads: - if(Debug::EScopeGlobal == info.iListScope) - { - err = manager.GetGlobalThreadList(buffer, dataSize); - } - else if(Debug::EScopeProcessSpecific == info.iListScope) - { - err = manager.GetThreadListForProcess(buffer, dataSize, info.iTargetId); - } - else if(Debug::EScopeThreadSpecific == info.iListScope) - { - err = manager.GetThreadListForThread(buffer, dataSize, info.iTargetId); - } - break; - - case EProcesses: - if(Debug::EScopeGlobal == info.iListScope) - { - err = manager.GetProcessList(buffer, dataSize); - } - break; - - case ECodeSegs: - if(Debug::EScopeGlobal == info.iListScope) - { - err = manager.GetGlobalCodeSegList(buffer, dataSize); - } - else if(Debug::EScopeProcessSpecific == info.iListScope) - { - err = manager.GetCodeSegListForProcess(buffer, dataSize, info.iTargetId); - } - else if(Debug::EScopeThreadSpecific == info.iListScope) - { - err = manager.GetCodeSegListForThread(buffer, dataSize, info.iTargetId); - } - break; - - default: - err = KErrNotSupported; - } - - if(err == KErrNone) - { - //if no error then write the buffer back - err = Kern::ThreadDesWrite(iClientThread, info.iBuffer, buffer, 0, KChunkShiftBy0, iClientThread); - } - - //write back the size of the data regardless of any error - TInt writeErr = Kern::ThreadRawWrite(iClientThread, info.iDataSize, (TUint8*)&dataSize, sizeof(TUint32), iClientThread); - if(writeErr != KErrNone) - { - //if there was an error writing the size return that error instead - err = writeErr; - } - - //free the buffer - NKern::ThreadEnterCS(); - Kern::Free((TAny*)buffer.Ptr()); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -Read registers and store register data in aRegisterInfo - -@param aThread thread to read registers from -@param aRegisterInfo structure specifying which registers to read and providing - descriptors to write the register data into - -@return KErrNone if registers were read successfully. Note that this does not - mean that all the registers could be read, the - aRegisterInfo.iRegisterFlags array should be checked as to whether each - individual register could be read, - KErrArgument if aRegisterInfo is NULL, or if any of the pointers that - are members of aRegisterInfo are NULL, if an unknown register is - specified or if the passed in register values buffer is too small - KErrNoMemory if there is insufficient memory, - KErrDied, if the thread with thread ID aThreadId is dead -*/ -TInt DRM_DebugChannel::ReadRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const - { - LOG_MSG("DRM_DebugChannel::ReadRegisters()"); - - TInt err = KErrNone; - - if (!aRegisterInfo) - return KErrArgument; - - TRM_DebugRegisterInformation info; - err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); - if (err != KErrNone) - return err; - - if ((!info.iRegisterIds) || (!info.iRegisterValues) || (!info.iRegisterFlags)) - return KErrArgument; - - //read ids from client thread - TPtr8 ids(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - NKern::ThreadLeaveCS(); - } - return err; - } - - //read values from client thread - TPtr8 values(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values, EFalse); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)values.Ptr()); - NKern::ThreadLeaveCS(); - } - - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - NKern::ThreadLeaveCS(); - return err; - } - - //read flags from client thread - TPtr8 flags(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)flags.Ptr()); - NKern::ThreadLeaveCS(); - } - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - Kern::Free((TAny*)values.Ptr()); - NKern::ThreadLeaveCS(); - return err; - } - - err = DoReadRegisters(aThread, ids, values, flags); - if (err == KErrNone) - { - err = Kern::ThreadDesWrite(iClientThread, info.iRegisterValues, values, 0, KChunkShiftBy0, iClientThread); - if(err == KErrNone) - { - err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); - } - } - - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - Kern::Free((TAny*)values.Ptr()); - Kern::Free((TAny*)flags.Ptr()); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -@deprecated use DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) instead -*/ -TInt DRM_DebugChannel::WriteRegistersLegacy(DThread* aThread, const TRM_DebugRegisterInfo* aRegisterInfo) - { - LOG_MSG("DRM_DebugChannel::WriteRegistersLegacy()"); - - TInt err = KErrNone; - - if (!aRegisterInfo) - return KErrArgument; - - TRM_DebugRegisterInfo info(0, 0, 0); - err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); - if (err != KErrNone) - return err; - - if (!info.iValues) - return KErrArgument; - - TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; - - NKern::ThreadEnterCS(); - TUint8 *values = (TUint8*)Kern::Alloc(length); - NKern::ThreadLeaveCS(); - if (!values) - { - return KErrNoMemory; - } - - TPtr8 valuesDes(values, length); - - err = Kern::ThreadDesRead(iClientThread, info.iValues, valuesDes, 0); - if (err == KErrNone) - { - err = DoWriteRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); - } - - NKern::ThreadEnterCS(); - Kern::Free(values); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -Write registers and store flags data in aRegisterInfo - -@param aThread thread to write registers to -@param aRegisterInfo structure specifying which registers to write and providing - descriptors to write the register flags data into - -@return KErrNone if registers were written successfully. Note that this does not - mean that all the registers could be written, the flags array - should be checked as to whether each individual register could be read, - KErrArgument if aRegisterInfo is NULL, or if any of the pointers that - are members of aRegisterInfo are NULL, if an unknown register is - specified or if the passed in register values buffer is too small, or - if aThread is NULL, - KErrGeneral if there was a problem initialising the register set, - KErrNoMemory if there is insufficient memory, - KErrDied, if the thread with thread ID aThreadId is dead -*/ -TInt DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const - { - LOG_MSG("DRM_DebugChannel::WriteRegisters()"); - - TInt err = KErrNone; - - if (!aRegisterInfo) - return KErrArgument; - - TRM_DebugRegisterInformation info; - err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); - if (err != KErrNone) - return err; - - if ((!info.iRegisterIds) || (!info.iRegisterValues) ||(!info.iRegisterFlags)) - return KErrArgument; - - //read ids from client thread - TPtr8 ids(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - NKern::ThreadLeaveCS(); - } - return err; - } - - //read values from client thread - TPtr8 values(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)values.Ptr()); - NKern::ThreadLeaveCS(); - } - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - NKern::ThreadLeaveCS(); - return err; - } - - //read flags from client thread - TPtr8 flags(NULL, 0); - err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); - if(err != KErrNone) - { - if(err == KErrNoMemory) - { - NKern::ThreadEnterCS(); - Kern::Free((TAny*)flags.Ptr()); - NKern::ThreadLeaveCS(); - } - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - Kern::Free((TAny*)values.Ptr()); - NKern::ThreadLeaveCS(); - return err; - } - - err = DoWriteRegisters(aThread, ids, values, flags); - if(err == KErrNone) - { - err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); - } - - NKern::ThreadEnterCS(); - Kern::Free((TAny*)ids.Ptr()); - Kern::Free((TAny*)values.Ptr()); - Kern::Free((TAny*)flags.Ptr()); - NKern::ThreadLeaveCS(); - - return err; - } - -/** -Suspends execution of the specified thread. - -@param aThread thread to resume - -@return KErrNone if there were no problems or KErrArgument if aThread is NULL -*/ -TInt DRM_DebugChannel::DoSuspendThread(DThread *aThread) - { - LOG_MSG("DRM_DebugChannel::DoSuspendThread()"); - - if (!aThread) - { - LOG_MSG("Invalid dthread object"); - return KErrArgument; - } - - return TheDProcessTracker.SuspendThread(aThread); - } - -/** -Resumes execution of the specified thread. - -@param aThread thread to resume - -@return KErrNone if there were no problems, KErrArgument if aThread is NULL - or an error value returned from DoStepRange() -*/ -TInt DRM_DebugChannel::DoResumeThread(DThread *aThread) - { - LOG_MSG("DRM_DebugChannel::DoResumeThread()"); - - if (!aThread) - return KErrArgument; - - // get the current PC - TUint32 currentPC; - TInt err = ReadKernelRegisterValue(aThread, PC_REGISTER, currentPC); - if(err != KErrNone) - { - LOG_MSG2("DRM_DebugChannel::DoResumeThread - Non-zero error code discarded: %d", err); - } - - // if there is a breakpoint at the current PC, we need to single step past it - TBreakEntry* breakEntry = NULL; - do - { - breakEntry = iBreakManager->GetNextBreak(breakEntry); - if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) - { - if (breakEntry->iAddress == currentPC) - { - return DoStepRange(aThread, currentPC, currentPC+1, ETrue, 1, ETrue); - } - } - } while(breakEntry); - - return TheDProcessTracker.ResumeThread(aThread); - } - -// -// DRM_DebugChannel::DoStepRange -// -TInt DRM_DebugChannel::DoStepRange(DThread *aThread, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto, TBool aResumeOnceOutOfRange, const TUint32 aNumSteps, TBool aUserRequest) - { - LOG_MSG("DRM_DebugChannel::DoStepRange()"); - - if (!aThread) - return KErrArgument; - - //check that the thread is suspended - if(!TheDProcessTracker.CheckSuspended(aThread)) - { - LOG_MSG2("DRM_DebugChannel::DoStepRange() Thread with id 0x%08x not suspended.", aThread->iId); - return KErrInUse; - } - - TUint32 startAddress = (aStartAddress & 0x1) ? aStartAddress + 1 : aStartAddress; - TUint32 stopAddress = (aStopAddress & 0x1) ? aStopAddress + 1 : aStopAddress;; - - // don't allow the user to step in the excluded ROM region. this could be called - // internally however. for example, the the special breakpoints we set to handle - // panics, exceptions, and library loaded events are in the user library, and we - // will need to step past the breakpoint before continuing the thread. - //if (aUserRequest && (startAddress >= iExcludedROMAddressStart) && (startAddress < iExcludedROMAddressEnd)) - //{ - // return KErrNotSupported; - //} - - // set the temp breakpoint, and disable the breakpoint at the current PC if necessary - // if its not a user request, and we are just trying to resume from a breakpoint, - // then we don't need to check for stubs. The last parameter aUserRequest tells - // ModifyBreaksForStep to check for stubs or not. In some cases, the check for stubs - // is true even if its not a user request.For example, this is true in cases where - // we are doing a step range and the instruction in the range modified PC. - // in this case, DoStepRange will be called from the exception handler where - // we need to check for the stubs for the valid behavior. So truly, we don't need to check - // for stubs only when resuming from a breakpoint. - ReturnIfError(iStepper->ModifyBreaksForStep(aThread, startAddress, stopAddress, aResumeOnceOutOfRange, aUserRequest, aNumSteps)); - - LOG_MSG("DRM_DebugChannel::DoStepRange() - resuming thread\n"); - - return TheDProcessTracker.ResumeThread(aThread); - } - -/** -Read memory from the specified addres into the aData descriptor. If there is a -breakpoint set in the region of memory returned then the correct data value is -inserted into the descriptor - -@param aThread pointer to thread whose address space memory is to be read from -@param aAddress address to start reading memory from -@param aLength length of memory block to read -@param aData descriptor to read memory into - -@return KErrNone if memory read successfully, - KErrNotSupported if reading from the rom section is not supported, - KErrBadHandle if aThread is invalid, - or one of the other system wide error codes -*/ -TInt DRM_DebugChannel::DoReadMemory(const DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) const - { - LOG_MSG("DRM_DebugChannel::DoReadMemory()"); - - // make sure the parameters are valid - if (aLength > aData.MaxSize()) - return KErrArgument; - - TInt err = KErrNone; - - // trap exceptions in case the address is invalid - XTRAPD(r, XT_DEFAULT, err = TryToReadMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); - - err = (KErrNone == r) ? err : r; - - if (KErrNone == err) - { - aData.SetLength(aLength); - - TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); - - // if we have any breakpoints in this range, put the actual instruction in the buffer - TBreakEntry* breakEntry = NULL; - do - { - breakEntry = iBreakManager->GetNextBreak(breakEntry); - if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) - { - if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) - { - TInt instSize; - - switch(breakEntry->iMode) - { - case EArmMode: - instSize = 4; - break; - - case EThumbMode: - instSize = 2; - break; - - case EThumb2EEMode: - default: - LOG_MSG("DRM_DebugChannel::DoReadMemory() cannot fixup breakpoints with unsupported architecture"); - return KErrNotSupported; - } - memcpy((TAny*)&data[breakEntry->iAddress - aAddress], (TAny *)breakEntry->iInstruction.Ptr(), instSize); - } - } - } while(breakEntry); - } - - return err; - } - -/** -Attempt to write memory to aThread's address space - -@param aThread thread to whose address space memory is to be written -@param aAddress memory location to write memory to -@param aLength number of bytes of data to write -@param aData descriptor containing memory to write - -@return KErrNone if memory written successfully, - KErrArgument if aLength is greater than than the length of the aData - KErrBadHandle if aThread is invalid, - or another of the system wide error codes -*/ -TInt DRM_DebugChannel::DoWriteMemory(DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) - { - LOG_MSG("DRM_DebugChannel::DoWriteMemory()"); - - // make sure the parameters are valid - if (aLength > aData.Length()) - return KErrArgument; - - TInt err = KErrNone; - - // trap exceptions in case the address is invalid - XTRAPD(r, XT_DEFAULT, err = TryToWriteMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); - - err = (KErrNone == r) ? err : r; - - // reset any breakpoints we may have just overwritten - if (KErrNone == err) - { - TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); - - TBreakEntry* breakEntry = NULL; - do - { - breakEntry = iBreakManager->GetNextBreak(breakEntry); - if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) - { - if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) - { - // default to arm mode - TUint32 inst; - TInt instSize; - - switch (breakEntry->iMode) - { - case EArmMode: - inst = KArmBreakPoint; - instSize = 4; - break; - - case EThumbMode: - inst = KThumbBreakPoint; - instSize = 2; - break; - - case EThumb2EEMode: - default: - LOG_MSG("DRM_DebugChannel::DoWriteMemory() cannot fixup breakpoints of unsupported architecture type"); - - return KErrNotSupported; - } - - breakEntry->iInstruction.Copy(&data[breakEntry->iAddress - aAddress], instSize); - memcpy((TAny*)breakEntry->iAddress, (TAny *)&inst, instSize); - } - } - - } while(breakEntry); - } - return err; - } - -// -// DRM_DebugChannel::DoReadRegisters -// -TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDes8 &aValues) - { - LOG_EVENT_MSG("DRM_DebugChannel::DoReadRegisters()"); - - // make sure the parameters are valid - if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) - return KErrArgument; - - // make sure the descriptor is big enough to hold the requested data - if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.MaxSize())) - return KErrArgument; - - TArmRegSet regSet; - TUint32 unused; - - NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); - - LOG_MSG2( "DRM_DebugChannel::DoReadRegistersLegacy() : unused = 0x%X\n", unused ); - - TArmReg *reg = ®Set.iR0; - - if (!reg) - return KErrGeneral; - - for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) - aValues.Append((TUint8 *)®[i], sizeof(TArmReg)); - - return KErrNone; -} - -/** - @prototype - - Experimental function for determining whether a thread is suspended. - - @param aThread thread to check if suspended - - @return ETrue if the thread is suspended, EFalse if it isn't or does not exist - */ -TBool DRM_DebugChannel::CheckSuspended(const DThread *aThread) const - { - if(!aThread) - { - return EFalse; - } - - if( (aThread->iNThread.iCsCount>0) && (aThread->iNThread.iCsFunction>0) ) - { - return ETrue; - } - - if(aThread->iNThread.iSuspendCount > 0) - { - return ETrue; - } - return EFalse; - } - -/** -Read registers and store register values in aRegisterValues and the flags -indicating which registers could be read in aRegisterFlags - -@param aThread thread to read registers from -@param aRegisterIds array containing register IDs to read -@param aRegisterValues array to store register values in -@param aRegisterFlags array to store flags in - -@return KErrNone if registers were read successfully. Note that this does not - mean that all the registers could be read, the aRegisterFlags array - should be checked as to whether each individual register could be read, - KErrArgument if aThread is NULL, if an unknown register is specified in - aRegisterValues or if aRegisterValues is too small - KErrGeneral if there was a problem initialising the register set -*/ -TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDes8 &aRegisterValues, TDes8& aRegisterFlags) const - { - LOG_MSG("DRM_DebugChannel::DoReadRegisters()"); - - // make sure the parameters are valid - if (!aThread) - return KErrArgument; - - //Need to revisit this to determine whether there is a way to validate this -#if 0 - if ( !CheckSuspended(aThread) ) - { - LOG_MSG2("DRM_DebugChannel::DoReadRegisters() thread with id 0x%08x is not suspended", aThread->iId); - return KErrInUse; - } -#endif - - //set lengths of output descriptors to 0 prior to filling - aRegisterValues.SetLength(0); - aRegisterFlags.SetLength(0); - - TArmRegSet regSet; - TUint32 flags; - - NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); - - LOG_MSG2( "DRM_DebugChannel::DoReadRegisters() : flags = 0x%X\n", flags ); - - TArmReg *regPtr = ®Set.iR0; - - if (!regPtr) - return KErrGeneral; - - TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); - - //iterate through registers setting the relevant aFlags value - for(TUint i=0; i aRegisterValues.MaxLength()) - { - //writing this value would cause overflow so exit - return KErrArgument; - } - aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); - } - else - { - if(registerTag.iSize == sizeof(TArmReg)) - { - if(GetFlagAtOffset(flags, armReg)) - { - //set flag as valid - aRegisterFlags.Append(EValid); - } - else - { - // Even though the flag is invalid, we can return the value of the register - // and let the user decide what to do - aRegisterFlags.Append(EInValid); - } - - if(aRegisterValues.Length() + sizeof(TArmReg) > aRegisterValues.MaxLength()) - { - //writing this value would cause overflow so exit - return KErrArgument; - } - //write value into register into regSet - aRegisterValues.Append((TUint8 *)®Ptr[armReg], registerTag.iSize); - } - else - { - //currently all kernel supported registers are 4 bytes so - //return EBadSize. Would need updating if/when other register - //value sizes are supported - aRegisterFlags.Append(EBadSize); - aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); - } - } - } - return KErrNone; - } - -// -// DRM_DebugChannel::DoWriteRegisters -// -TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 &aValues) - { - LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); - - // make sure the parameters are valid - if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) - return KErrArgument; - - // make sure the descriptor is big enough to hold the data to write - if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.Length())) - return KErrArgument; - - TArmRegSet regSet; - TUint32 unused; - - NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); - - TArmReg *reg = ®Set.iR0; - - for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) - reg[i] = *(TUint32 *)&aValues[(i-aFirstRegister)*sizeof(TArmReg)]; - - NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); - - return KErrNone; - } - -/** -Write registers and store flags indicating which registers could be read in -aRegisterFlags - -@param aThread thread to write registers to -@param aRegisterIds array containing register IDs to write -@param aRegisterValues array containing register values to write -@param aRegisterFlags array to store flags in - -@return KErrNone if registers were written successfully. Note that this does not - mean that all the registers could be written, the aRegisterFlags array - should be checked as to whether each individual register could be read, - KErrArgument if aThread is NULL, if the buffer passed in as - aRegisterValue is too small, or if an unknown register is requested, - KErrGeneral if there was a problem initialising the register set -*/ -TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDesC8 &aRegisterValues, TDes8 &aRegisterFlags) const - { - LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); - - // make sure the parameters are valid - if (!aThread) - return KErrArgument; - - //check that the thread is suspended before reading the registers - if(!TheDProcessTracker.CheckSuspended(aThread)) - { - LOG_MSG2("DRM_DebugChannel::DoWriteRegisters() thread with id 0x%08x is not suspended", aThread->iId); - return KErrInUse; - } - - //get register values from kernel - TArmRegSet regSet; - TUint32 flags; - NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); - - //set lengths of output descriptors to 0 prior to filling - aRegisterFlags.SetLength(0); - - //pointer to first kernel register - TArmReg *regPtr = ®Set.iR0; - - if (!regPtr) - return KErrGeneral; - - //calculate number of registers - TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); - - //iterate through registers setting the relevant aRegisterFlags value and - //setting the necessary value in regSet ready to write to kernel - for(TUint i=0, offset = 0; i aRegisterValues.Length()) - { - //getting this value would cause overflow so exit - return KErrArgument; - } - //write value into register into regSet - regPtr[armReg] = *(TUint32 *)&aRegisterValues[offset]; - } - else - { - //currently all kernel supported registers are 4 bytes so - //return EBadSize. Would need updating if/when other register - //value sizes are supported - aRegisterFlags.Append(EBadSize); - } - - } - else - { - //set flag as invalid as register value couldn't be read - aRegisterFlags.Append(EInValid); - } - offset+=registerTag.iSize; - } - - //write the input data into the registers - NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); - - //return normally - return KErrNone; - } - -// -// DRM_DebugChannel::DoSecurityCheck -// -TBool DRM_DebugChannel::DoSecurityCheck() - { - LOG_MSG("DRM_DebugChannel::DoSecurityCheck"); - DProcess* clientProcess = iClientThread->iOwningProcess; - if (clientProcess) - { - SSecurityInfo secureInfo = clientProcess->iS; - - LOG_MSG2("DoSecurityCheck - client secure id is 0x%08x",secureInfo.iSecureId); - - // Ensure we really are communicating with the Debug Security Server - if (secureInfo.iSecureId == KUidDebugSecurityServer.iUid ) - { - return ETrue; - } - } - return EFalse; - } - -/** -Attempt to read memory from aThread's address space - -@param aThread thread from whose address space memory is to be read -@param aSrc pointer to memory location to read memory from -@param aDest pointer to memory location to write memory to -@param aLength number of bytes of data to read - -@return KErrNone if memory read successfully, - or another of the system wide error codes -*/ -TInt DRM_DebugChannel::TryToReadMemory(const DThread *aThread, const TAny *aSrc, TAny *aDest, const TUint32 aLength) const - { - LOG_MSG("DRM_DebugChannel::TryToReadMemory()"); - - // make sure the parameters are valid - if (!aThread) - return KErrArgument; - - //Need to revisit this to determine whether there is a way to validate this -#if 0 - //check that the thread is suspended before reading the memory - if ( !CheckSuspended(aThread) ) - { - LOG_MSG2("DRM_DebugChannel::TryToReadMemory() thread with id 0x%08x is not suspended", aThread->iId); - return KErrInUse; - } -#endif - - LOG_MSG2("Using Kern::ThreadRawRead to read memory at address %x", aSrc); - return Kern::ThreadRawRead((DThread *)aThread, aSrc, aDest, aLength); - } - -/** -Attempt to write memory to aThread's address space - -@param aThread thread to whose address space memory is to be written -@param aDest pointer to memory location to write memory to -@param aSrc pointer to memory location to read memory from -@param aLength number of bytes of data to write - -@return KErrNone if memory written successfully, or another of the system wide - error codes -*/ -TInt DRM_DebugChannel::TryToWriteMemory(const DThread *aThread, TAny *aDest, const TAny *aSrc, const TUint32 aLength) - { - LOG_MSG("DRM_DebugChannel::TryToWriteMemory()"); - - //check that the thread is suspended before writing the memory - if(!TheDProcessTracker.CheckSuspended((DThread*)aThread)) - { - LOG_MSG2("DRM_DebugChannel::TryToWriteMemory() thread with id 0x%08x is not suspended", aThread->iId); - return KErrInUse; - } - - LOG_MSG2("Using Kern::ThreadRawWrite to write memory at address %x", (TUint32)aDest); - return Kern::ThreadRawWrite((DThread *)aThread, aDest, aSrc, aLength, iClientThread); - } - -/** -@deprecated use DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) instead -*/ -TInt32 DRM_DebugChannel::ReadRegister(DThread *aThread, TInt aNum) - { - LOG_MSG("DRM_DebugChannel::ReadRegister()"); - - if (!aThread || (aNum < 0) || (aNum >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) - { - LOG_MSG2("Invalid register number (%d) passed to ReadRegister", aNum); - return 0; - } - - TArmRegSet regSet; - TUint32 unused; - - NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); - - TArmReg *reg = ®Set.iR0; - - return ((TUint32 *)reg)[aNum]; - } - -/** -Given a TArmReg register ID, read the value of the register. The register value -will be stored in aValue if the register could be read. - -@param aThread thread to read register from -@param aKernelRegisterId ID of register to read from -@param aValue value read from register - -@return KErrNone if value was successfully stored in aValue, - KErrNotSupported if aKernelRegister is not supported by the debug - security server, - or a return value from DRM_DebugChannel::ReadDebugRegisterValue() -*/ -TInt32 DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) const - { - //get register ID as a TRegisterInfo ID - TRegisterInfo regId; - TInt err = GetDebugRegisterId(aKernelRegisterId, regId); - if(err != KErrNone) - return err; - - //get the value for the register - err = ReadDebugRegisterValue(aThread, regId, aValue); - return err; - } - -/** -Given a TRegisterInfo register ID, read the value of this register. The -register value will be stored in aValue if the register could be read. - -@param aThread thread to read register from -@param aDebugRegisterId ID of register to read from -@param aValue value read from register - -@return KErrNone if value was successfully stored in aValue, - TRegisterFlag::EInValid if value could not be read from the register, - TRegisterFlag::ENotSupported if the register is not supported, - KErrNoMemory if temporary memory could not be allocated, - or a return value from DRM_DebugChannel::DoReadRegisters -*/ -TInt32 DRM_DebugChannel::ReadDebugRegisterValue(DThread *aThread, const TRegisterInfo aDebugRegisterId, T4ByteRegisterValue &aValue) const - { - //allocate temporary buffers to store data - NKern::ThreadEnterCS(); - TUint8* id = (TUint8*)Kern::Alloc(sizeof(TRegisterInfo)); - NKern::ThreadLeaveCS(); - if(id == NULL) - { - return KErrNoMemory; - } - - TPtr8 idPtr(id, sizeof(TRegisterInfo)); - - NKern::ThreadEnterCS(); - TUint8* value = (TUint8*)Kern::Alloc(sizeof(T4ByteRegisterValue)); - NKern::ThreadLeaveCS(); - if(value == NULL) - { - return KErrNoMemory; - } - TPtr8 valuePtr(value, sizeof(T4ByteRegisterValue)); - - NKern::ThreadEnterCS(); - TUint8* flag = (TUint8*)Kern::Alloc(sizeof(TUint8)); - NKern::ThreadLeaveCS(); - if(flag == NULL) - { - return KErrNoMemory; - } - TPtr8 flagPtr(flag, sizeof(TUint8)); - - //store register id in buffer - idPtr.Append((TUint8*)&aDebugRegisterId, sizeof(TRegisterInfo)); - - //read registers - TInt err = DoReadRegisters(aThread, idPtr, valuePtr, flagPtr); - if(err == KErrNone) - { - if(*flag == EValid) - { - //register could be read so store value - aValue = *(T4ByteRegisterValue*)value; - } - else - { - //register couldn't be read for some reason - err = *flag; - } - } - - //free memory - NKern::ThreadEnterCS(); - Kern::Free(id); - Kern::Free(value); - Kern::Free(flag); - NKern::ThreadLeaveCS(); - - return err; - } - -// -// DRM_DebugChannel::NotifyEvent -// -void DRM_DebugChannel::NotifyEvent(const TDriverEventInfo& aEventInfo) - { - LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent()"); - - // Look for the relevant DTargetProcess - // We can find out the relevant process id from aEventInfo - TUint32 pid = aEventInfo.iProcessId; - - //opening handle to process - DProcess* targetProcess = DebugUtils::OpenProcessHandle(pid); - - if(!targetProcess) - { - LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent - process does not exist!"); - return; - } - - // Are we debugging this process - decide based on iFileName - DCodeSeg* p = targetProcess->iCodeSeg; - DTargetProcess* foundProcess; - if (p) - { - foundProcess = TheDProcessTracker.FindProcess(*(p->iFileName)); - } - else - { - // special case: may not have a code seg in some cases. in which case we tell everyone! - if (targetProcess->iName) - { - // copy the name of the process - foundProcess = TheDProcessTracker.FindProcess(*(targetProcess->iName)); - } - else - { - foundProcess = NULL; - } - } - - //close the handle - targetProcess->Close(NULL); - - if (!foundProcess) - { - // No: just ignore this exception - LOG_EVENT_MSG("DRM_DebugChannel::NotifyEvent - we are not debugging this process!"); - return; - } - - foundProcess->NotifyEvent(aEventInfo); - } - -#ifndef __LAUNCH_AS_EXTENSION__ -DECLARE_STANDARD_LDD() - { - return new DRM_DebugDriverFactory; - } -#else - -DStopModeExtension* TheStopModeExtension = NULL; - -DECLARE_EXTENSION_LDD() - { - return new DRM_DebugDriverFactory; - } - -/** - This value is used as an initialiser for the size of the Stop-Mode Debug API's - default request buffer. - */ -const TInt KRequestBufferSize = 0x200; -/** - This value is used as an initialiser for the size of the Stop-Mode Debug API's - default response buffer. - */ -const TInt KResponseBufferSize = 0x1000; - -DECLARE_STANDARD_EXTENSION() - { - __KTRACE_OPT(KBOOT,Kern::Printf("Starting RM_DEBUG extension")); - - // get a reference to the DDebuggerInfo and to the DStopModeExtension - TSuperPage& superPage = Kern::SuperPage(); - - if(!superPage.iDebuggerInfo) - { - //kdebug has not been installed so create DDebuggerInfo using our stub constructor - superPage.iDebuggerInfo = new DDebuggerInfo(); - } - - if(!TheStopModeExtension) - { - TheStopModeExtension = new DStopModeExtension(); - } - - // create the request buffer and store a reference to it - TTag tag; - tag.iTagId = EBuffersRequest; - tag.iType = ETagTypePointer; - tag.iSize = KRequestBufferSize; - TInt err = TheDBufferManager.CreateBuffer(tag); - if(KErrNone != err) - { - return KErrNone; - } - - // create the response buffer and store a reference to it - tag.iTagId = EBuffersResponse; - tag.iSize = KResponseBufferSize; - err = TheDBufferManager.CreateBuffer(tag); - if(KErrNone != err) - { - return KErrNone; - } - // create the debug functionality buffer and store a reference to it - TDebugFunctionality df; - TUint dfSize = df.GetStopModeFunctionalityBufSize(); - tag.iTagId = EBuffersFunctionality; - tag.iSize = dfSize; - err = TheDBufferManager.CreateBuffer(tag); - if(KErrNone != err) - { - return KErrNone; - } - - // fill the functionality buffer with the functionality data and store it in - // the super page - TPtr8 dfBlockPtr((TUint8*)tag.iValue, dfSize); - if(!df.GetStopModeFunctionality(dfBlockPtr)) - { - return KErrNone; - } - TheStopModeExtension->iFunctionalityBlock = (DFunctionalityBlock*)tag.iValue; - - DStopModeExtension::Install(TheStopModeExtension); - - return KErrNone; - } - -/** - * This stub constructor is intended to be used in the case where the old deprecated - * stop mode api, kdebug, is not in place. It will initialise all values to NULL except - * the pointer to the new stop mode api extension. This allows the new stop mode solution - * to both co-exist and exist independantly of the existing one * - */ -DDebuggerInfo::DDebuggerInfo(): - iObjectOffsetTable(NULL), - iObjectOffsetTableCount(NULL), - iThreadContextTable(NULL), - iStopModeExtension(new DStopModeExtension()), - iContainers(NULL), - iCodeSegLock(NULL), - iCodeSegGlobalList(NULL), - iScheduler(NULL), - iShadowPages(NULL), - iShadowPageCount(0), - iCurrentThread(NULL), - iEventMask(), - iEventHandlerBreakpoint(0), - iMemModelObjectOffsetTable(NULL), - iMemModelObjectOffsetTableCount(0) - { - } - -/** - * Installs the stop-mode debugger extension - * Make the stop-mode API visible to a JTAG debugger, by publishing its - * existence in the superpage -*/ -void DStopModeExtension::Install(DStopModeExtension* aExt) - { - Kern::SuperPage().iDebuggerInfo->iStopModeExtension = aExt; - } - -#endif - -/** -Helper function - -Allocates memory in current thread with a max length the same as aSrcDes. If -aReadFromClient is true (as it is by default) then the data from aSrdDes is -copied into the allocated aDestDes buffer. - -Use of this function should be followed at a later time by a call such as -Kern::Free(aDestDes.Ptr()) - -@param aThread pointer to thread to read data from -@param aSrcDes descriptor in aThread to read data from -@param aDestDes location to read data to. Memory is allocated at this location, - if memory is already allocated at this location then the function will - return KErrArgument -@param aReadFromClient if false then data is not actually read from the - client, the memory is simply allocated -@param aOffest offset into aSrcDes to start reading from. Default is 0. - -@return KErrNone if there were no problems, - KErrArgument if aDestDes.Ptr() != NULL or aSrcDes has max length 0, - KErrNoMemory if could not allocate memory, - or one of the other system wide error codes -*/ -TInt DRM_DebugChannel::AllocAndReadDes(DThread *aThread, const TDesC8& aSrcDes, TPtr8& aDestDes, const TBool aReadFromClient, const TUint aOffset) const - { - - //check thread is not null - if(!aThread) - { - return KErrArgument; - } - - //check aDestDes is empty - if(aDestDes.Ptr() != NULL) - { - return KErrArgument; - } - - //get the source descriptor's max length and exit if 0 - TUint srcMaxLength = Kern::ThreadGetDesMaxLength(aThread, &aSrcDes); - if(srcMaxLength == 0) - { - return KErrNone; - } - - //allocate memory and return if none available - NKern::ThreadEnterCS(); - TUint8 *destPtr = (TUint8*)Kern::Alloc(srcMaxLength); - NKern::ThreadLeaveCS(); - if (!destPtr) - { - return KErrNoMemory; - } - - //point the TPtr8 at the target memory - aDestDes.Set(destPtr, srcMaxLength, srcMaxLength); - - if(aReadFromClient) - { - //read data from the client thread and return status code - return Kern::ThreadDesRead(aThread, &aSrcDes, aDestDes, aOffset); - } - else - { - return KErrNone; - } - } - -/** -Helper function to extract a TRegisterInfo value from a descriptor containing -binary data. - -@param aRegisterIds descriptor containing register IDs -@param aOffset offset in bytes into the descriptor to start reading data from. - If this value is not a multiple of sizeof(TRegisterInfo) then a - KErrArgument error is returned. -@param aValue will contain the returned value - -@return KErrNone if aValue was set correctly, KErrArgument if bad arguments - were passed in -*/ -TInt DRM_DebugChannel::GetTRegisterInfo(const TDesC8 &aRegisterIds, const TUint aIndex, TRegisterInfo &aValue) const - { - TUint length = aRegisterIds.Length(); - - TUint size = sizeof(TRegisterInfo); - - //check that not trying to read past end of descriptor - if((aIndex + 1) * size > length) - return KErrArgument; - - //get pointer to descriptor's data - const TUint8 *dataPtr = aRegisterIds.Ptr(); - const TRegisterInfo *registerId = reinterpret_cast(dataPtr + (aIndex * size)); - - aValue = *registerId; - - return KErrNone; - } - -/** -Helper function to get the kernel register ID of the TRegisterInfo defined register. - -@param aDebugRegister the debug register ID to return the kernel ID for -@param aKernelRegister corresponding value of register aDebugRegister - -@return KErrNone if translation occurred without problems - KErrNotSupported if aDebugRegister is not supported by the kernel -*/ -TInt DRM_DebugChannel::GetKernelRegisterId(const TRegisterInfo aDebugRegister, TArmReg& aKernelRegister) const - { - if(Register::IsCoreReg(aDebugRegister)) - { - TUint id = Register::GetCoreRegId(aDebugRegister); - //first 17 registers match the first 17 kernel registers - if(id < 17) - { - aKernelRegister = id; - } - else - { - return KErrNotSupported; - } - } - else if(Register::IsCoproReg(aDebugRegister)) - { - TUint32 crn = Register::GetCRn(aDebugRegister); - TUint32 crm = Register::GetCRm(aDebugRegister); - TUint32 opcode1 = Register::GetOpcode1(aDebugRegister); - TUint32 opcode2 = Register::GetOpcode2(aDebugRegister); - TUint32 coproNum = Register::GetCoproNum(aDebugRegister); - - //each coprocessor register has potentially different characteristics - //so need to identify each individually - - //this is the DACR, the ARM ARM specifies that the CRn and the - //Opcodes are not relevant, section B3-24, point 3.7.3 - if((coproNum == 15) && (crm == 3)) - { - aKernelRegister = EArmDacr; - } - else - { - return KErrNotSupported; - } - } - else // might be supported at a later date - { - return KErrNotSupported; - } - - return KErrNone; - } - -/** -Helper function to get the debug register ID of the kernel defined register. - -@param aKernelRegister the kernel register ID to return the debug ID for -@param aDebugRegister corresponding value of register aKernelRegister - -@return KErrNone if translation occured without problems - KErrNotSupported if aKernelRegister is not supported by the debug - security server -*/ -TInt DRM_DebugChannel::GetDebugRegisterId(const TArmReg aKernelRegister, TRegisterInfo &aDebugRegister) const - { - - // registers 0 - 15 and the CPSR share the same values as with the debug enums - if(aKernelRegister < 17) - { - TUint32 id = aKernelRegister; - aDebugRegister = id << 8; - } - //the DACR value is special and corresponds to EDF_Register_DACR - else if(aKernelRegister == EArmDacr) - { - aDebugRegister = 0x00300f01; - } - // must be an unsupported register, return an error as such - else - { - return KErrNotSupported; - } - - //found a supported register so return KErrNone - return KErrNone; - } - -/** -Helper function to find out whether the aIndex flag is set. This is equivalent -to the aIndex bit of aFlags being non-zero. - -@param aFlags set of flags -@param aIndex offset into aFlags to get flag from - -@return ETrue if bit is set, EFalse if not -*/ -TBool DRM_DebugChannel::GetFlagAtOffset(const TUint32 aFlags, const TArmReg aIndex) const - { - return aFlags & (1<= KMaxPath) - { - return KErrArgument; - } - - if (maxLength < 1 || maxLength >= KMaxPath) - { - return KErrArgument; - } - - // Allocate space to store the target process name in a kernel-side TPtr8 - NKern::ThreadEnterCS(); - TUint8* buffer = (TUint8*)Kern::AllocZ(length); - NKern::ThreadLeaveCS(); - if (buffer==NULL) - { - // Out of memory - return KErrNoMemory; - } - - // A temporary descriptor to store the target process name - TPtr8 targetProcessName(buffer,length,length); - - // Read the user-side data into targetProcessName - err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); - if (err != KErrNone) - { - // Could not read the user-side descriptor containing the target process name - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - - // Obtain the Debug Agent Id - TUint64 debugAgentId = 0; - - err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); - if (err != KErrNone) - { - // Something bad happened so free the memory and return - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - return err; - } - - // Add the target process to our list of tracked processes - err = TheDProcessTracker.AttachProcess(targetProcessName, debugAgentId); - - // Free the kernel-side memory containing targetProcessName data - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - -/* Register the detachment of a debug agent to a process to be debugged. - * - * @param - a1 TDes8 target process name in a1 - * @param a2 - &TUint64 - Debug Agent Id - * - * @return - KErrNone if successful. KErrArgument if the filepath is not a valid size. - * KErrOutOfMemory if there is insufficient memory. Or one of the other system wide error codes - * if appropriate. - */ -TInt DRM_DebugChannel::DetachProcess(TAny* a1, TAny* a2) - { - // Validate the supplied TDes8 target process name in a1 - TInt length, maxLength; - TUint8* aPtr; - - TInt err = Kern::ThreadGetDesInfo(iClientThread,\ - a1,\ - length,\ - maxLength,\ - aPtr,\ - EFalse); - if (err != KErrNone) - { - return err; - } - - if (length < 1 || length >= KMaxPath) - { - return KErrArgument; - } - - if (maxLength < 1 || maxLength >= KMaxPath) - { - return KErrArgument; - } - - // Allocate space to store the target process name in a kernel-side TPtr8 - NKern::ThreadEnterCS(); - TUint8* buffer = (TUint8*)Kern::AllocZ(length); - NKern::ThreadLeaveCS(); - if (buffer==NULL) - { - // Out of memory - return KErrNoMemory; - } - - TPtr8 targetProcessName(buffer,length,length); - - // Read the user-side data into targetProcessName - err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); - if (err != KErrNone) - { - // Something bad happened so free the memory and return - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - - // Obtain the AgentId - TUint64 debugAgentId = 0; - - err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); - if (err != KErrNone) - { - // Something bad happened so free the memory and return - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - - // Remove the process from our list of tracked processes - err = TheDProcessTracker.DetachProcess(targetProcessName, debugAgentId); - - // Free the kernel-side memory containing targetProcessName data - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - -/* Register the detachment of a debug agent from all processes being debugged. - * - * @param - a1 - &TUint64 Debug Agent Id. - * @return - KErrNone if successful. One of the system-wide error codes otherwise. - */ -TInt DRM_DebugChannel::DetachAgent(TAny* a1, TAny* a2) - { - // Obtain the AgentId - TUint64 debugAgentId = 0; - - TInt err = Kern::ThreadRawRead(iClientThread,a1,&debugAgentId,sizeof(debugAgentId)); - if (err != KErrNone) - { - return err; - } - - // Remove the process from our list of tracked processes - return TheDProcessTracker.DetachAgent(debugAgentId); - } - -/* Set the action associated with a particular kernel event for a given agent and target process - * - * @param - a1 TDes8 target process name in a1 - * @param - a2 &TRM_DebugEventActionInfo - * @return - KErrNone if successful. KErrArgument if the filepath is an invalid size. Or one of - * the other system wide error codes if appropriate. - */ -TInt DRM_DebugChannel::SetEventAction(TAny* a1, TAny* a2) - { - // Validate the supplied TDes8 target process name in a1 - TInt length, maxLength; - TUint8* aPtr; - - TInt err = Kern::ThreadGetDesInfo(iClientThread,\ - a1,\ - length,\ - maxLength,\ - aPtr,\ - EFalse); - if (err != KErrNone) - { - return err; - } - - if (length < 1 || length >= KMaxPath) - { - return KErrArgument; - } - - if (maxLength < 1 || maxLength >= KMaxPath) - { - return KErrArgument; - } - - // Allocate space to store the target process name in a kernelspace TPtr8 - NKern::ThreadEnterCS(); - TUint8* buffer = (TUint8*)Kern::AllocZ(length); - NKern::ThreadLeaveCS(); - if (buffer==NULL) - { - // Out of memory - return KErrNoMemory; - } - TPtr8 targetProcessName(buffer,length,length); - - // Read the user-side data into targetProcessName - err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); - if (err != KErrNone) - { - // Something bad happened so free the memory and return - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - - // Read the Event and Action from the user-side - TRM_DebugEventActionInfo info(0,0,0); - - err = Kern::ThreadRawRead(iClientThread, a2, &info, sizeof(info)); - if (err != KErrNone) - { - // Could not read event action data from the user-side - - // Free memory used for targetProcessName - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return err; - } - - // Find the target process - DTargetProcess* pProcess = TheDProcessTracker.FindProcess(targetProcessName); - if (pProcess == NULL) - { - // Could not find this process - - // Free memory used for targetProcessName - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return KErrArgument; - } - - TUint64 debugAgentId = info.iAgentId; - - // Find the agent - DDebugAgent* debugAgent = pProcess->Agent(debugAgentId); - if (debugAgent == NULL) - { - // Bad agent means there is no tracking agent - LOG_MSG2("Cannot locate debug agent with pid 0x%0x16lx",info.iAgentId); - - // Free memory used for targetProcessName - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return KErrGeneral; - } - - // Set the event action - debugAgent->SetEventAction((TEventType)info.iEvent,(TKernelEventAction)info.iAction); - - // Free memory used for targetProcessName - NKern::ThreadEnterCS(); - Kern::Free(buffer); - NKern::ThreadLeaveCS(); - - return KErrNone; - } - -TInt DRM_DebugChannel::Step(const TUint32 aThreadId, const TUint32 aNumSteps) - { - LOG_MSG3("DRM_DebugChannel::Step(aThreadId = 0x%08x, aNumSteps = 0x%08x)\n",aThreadId,aNumSteps); - - DThread* thread = DebugUtils::OpenThreadHandle(aThreadId); - - if (thread == NULL) - { - // The thread terminated before we could open it. - LOG_MSG2("DRM_DebugChannel::Step - Could not open thread %u", aThreadId); - - return KErrArgument; - } - - // We simply repeat this for desired number of steps - TInt err = KErrNone; - - // Need to step from the current location for 'n' steps - TUint32 startAddress; - - // We always step from the current PC. - err = ReadKernelRegisterValue(thread, PC_REGISTER, startAddress); - if(err != KErrNone) - { - LOG_MSG2("DRM_DebugChannel::Step - Could not read the PC: %d", err); - - // Close the handle - thread->Close(NULL); - - return err; - } - - err = DoStepRange(thread, startAddress, startAddress, ETrue, EFalse, aNumSteps, ETrue); - - if (err != KErrNone) - { - // There was a problem, return straightaway - LOG_MSG("DRM_DebugChannel::Step - failed to step"); - } - - // Close the handle - thread->Close(NULL); - - return err; - } - -TInt DRM_DebugChannel::KillProcess(const TUint32 aProcessId, const TInt aReason) - { - LOG_MSG3("DRM_DebugChannel::KillProcess(aProcessId = 0x%08x, aReason = 0x%08x)\n",aProcessId,aReason); - - DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); - - if (process == NULL) - { - // The process terminated before we could open it to kill it ourselves. - LOG_MSG2("DRM_DebugChannel::KillProcess - Could not open process %u", aProcessId); - - return KErrArgument; - } - - TInt err = KErrNone; - - DebugSupport::TerminateProcess(process,aReason); - - // Close the handle - process->Close(NULL); - - return err; - } - -/* Security critical - this checks whether the specified process is debuggable or not - * - * @param aProcessId - The process id of the process to check - * @return KErrNone if debuggable, KErrPermissionDenied if not debuggable. - */ -TInt DRM_DebugChannel::IsDebuggable(const TUint32 aProcessId) - { - /* In order to ensure that only processes which are debuggable - * can be debugged, this function enables the security server - * to read the DProcess.iDebugAttributes field and ensure - * the process was created from a debuggable executable. - */ - LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x)\n",aProcessId); - - TInt err = KErrPermissionDenied; - - DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); - if (process) - { - if (process->iDebugAttributes & TProcessCreateInfo::EDebugAllowed) - { - // Yes this process exists and is debuggable - err = KErrNone; - } - process->Close(NULL); - } - - if (err == KErrNone) - { - LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x) - Yes it is debuggable\n",aProcessId); - } - - return err; - }