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