// Retrieves a list of all code contexts associated with this document context. // The engine sample only supports one code context per document context and // the code contexts are always memory addresses. int IDebugDocumentContext2.EnumCodeContexts(out IEnumDebugCodeContexts2 ppEnumCodeCxts) { ppEnumCodeCxts = null; if (_codeContext == null) { return(VSConstants.E_FAIL); } try { AD7MemoryAddress[] codeContexts = new AD7MemoryAddress[1]; codeContexts[0] = _codeContext; ppEnumCodeCxts = new AD7CodeContextEnum(codeContexts); return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Parses a text-based expression for evaluation. // The engine sample only supports locals and parameters so the only task here is to check the names in those collections. int IDebugExpressionContext2.ParseText(string pszCode, enum_PARSEFLAGS dwFlags, uint nRadix, out IDebugExpression2 ppExpr, out string pbstrError, out uint pichError) { pbstrError = null; pichError = 0; ppExpr = null; try { ppExpr = new AD7Expression(Engine, new VariableInformation(pszCode, ThreadContext, Engine, Thread)); return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets information that describes this context. public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo) { try { pinfo[0].dwFields = 0; if (dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS)) { pinfo[0].bstrAddress = m_address.ToString(); pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS; } // Fields not supported by the sample //if ((dwFields & (uint)enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0){} //if ((dwFields & (uint)enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0){} //if ((dwFields & (uint)enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0){} //if ((dwFields & (uint)enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION) != 0) {} //if ((dwFields & (uint)enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) {} return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the document context for this stack frame. The debugger will call this when the current stack frame is changed // and will use it to open the correct source document for this stack frame. int IDebugStackFrame2.GetDocumentContext(out IDebugDocumentContext2 docContext) { docContext = null; try { if (mHasSource) { // Assume all lines begin and end at the beginning of the line. TEXT_POSITION begTp = new TEXT_POSITION(); begTp.dwColumn = 0; begTp.dwLine = mLineNum - 1; TEXT_POSITION endTp = new TEXT_POSITION(); endTp.dwColumn = 0; endTp.dwLine = mLineNum - 1; docContext = new AD7DocumentContext(mDocName, begTp, endTp, null); return(VSConstants.S_OK); } } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_FALSE); }
int IDebugEngine2.ContinueFromSynchronousEvent(IDebugEvent2 aEvent) { // Called by the SDM to indicate that a synchronous debug event, previously sent by the DE to the SDM, // was received and processed. The only event the engine sends in this fashion is Program Destroy. // It responds to that event by shutting down the engine. // // This is used in some cases - I set a BP here and it does get hit sometime during breakpoints // being triggered for example. try { if (aEvent is AD7ProgramDestroyEvent) { mEngineCallback = null; mProgramID = Guid.Empty; mThread = null; mProgNode = null; } else { System.Diagnostics.Debug.Fail("Unknown synchronious event"); } } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// Gets the document context for this stack frame. The debugger will call this when the current stack frame is changed // and will use it to open the correct source document for this stack frame. int IDebugStackFrame2.GetDocumentContext(out IDebugDocumentContext2 docContext) { docContext = null; try { if (hasSource) { // Assume all lines begin and end at the beginning of the line. // TODO: Accurate line endings var lineNumber = (uint)LineNumber; TEXT_POSITION begTp = new TEXT_POSITION(); begTp.dwColumn = 0; begTp.dwLine = lineNumber - 1; TEXT_POSITION endTp = new TEXT_POSITION(); endTp.dwColumn = 0; endTp.dwLine = lineNumber - 1; docContext = new MonoDocumentContext(engine.TranslateToLocalPath(documentName), begTp, endTp, null); return(VSConstants.S_OK); } } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_FALSE); }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { Task bindTask = null; _engine.DebuggedProcess.WorkerThread.RunOperation(() => { bindTask = _engine.DebuggedProcess.AddInternalBreakAction(this.BindAsync); }); bindTask.Wait(250); //wait a quarter of a second if (!bindTask.IsCompleted) { //send a low severity warning bp. This will allow the UI to respond quickly, and if the mi debugger doesn't end up binding, this warning will get //replaced by the real mi debugger error text _BPError = new AD7ErrorBreakpoint(this, ResourceStrings.LongBind, enum_BP_ERROR_TYPE.BPET_SEV_LOW | enum_BP_ERROR_TYPE.BPET_TYPE_WARNING); _engine.Callback.OnBreakpointError(_BPError); return(VSConstants.S_FALSE); } else { return(VSConstants.S_OK); } } else { // The breakpoint could not be bound. This may occur for many reasons such as an invalid location, an invalid expression, etc... _engine.Callback.OnBreakpointError(_BPError); return(VSConstants.S_FALSE); } } catch (MIException e) { return(e.HResult); } catch (AggregateException e) { if (e.GetBaseException() is InvalidCoreDumpOperationException) { return(AD7_HRESULT.E_CRASHDUMP_UNSUPPORTED); } else { return(EngineUtils.UnexpectedException(e)); } } catch (InvalidCoreDumpOperationException) { return(AD7_HRESULT.E_CRASHDUMP_UNSUPPORTED); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets properties that describe a thread. int IDebugThread2.GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] ptp) { try { THREADPROPERTIES props = new THREADPROPERTIES(); if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0) { props.dwThreadId = _debuggedThread.TargetId; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT) != 0) { // sample debug engine doesn't support suspending threads props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0) { props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_PRIORITY) != 0) { props.bstrPriority = "Normal"; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0) { props.bstrName = _debuggedThread.Name; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_LOCATION) != 0) { props.bstrLocation = GetCurrentLocation(true); props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_LOCATION; if (props.bstrLocation == null) { // Thread deletion events may be delayed, in which case the thread object may still be present in the cache // but the engine is unable to retrieve new data for it. So handle failure to get info for a dead thread. props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_DEAD; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; props.bstrLocation = ResourceStrings.ThreadExited; } } ptp[0] = props; return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Creates an enumerator for properties associated with the stack frame, such as local variables. // The sample engine only supports returning locals and parameters. Other possible values include // class fields (this pointer), registers, exceptions... int IDebugStackFrame2.EnumProperties(enum_DEBUGPROP_INFO_FLAGS dwFields, uint nRadix, ref Guid guidFilter, uint dwTimeout, out uint elementsReturned, out IEnumDebugPropertyInfo2 enumObject) { int hr; elementsReturned = 0; enumObject = null; try { if (guidFilter == AD7Guids.guidFilterAllLocals || guidFilter == AD7Guids.guidFilterAllLocalsPlusArgs || guidFilter == AD7Guids.guidFilterArgs || guidFilter == AD7Guids.guidFilterLocals || guidFilter == AD7Guids.guidFilterLocalsPlusArgs) { EnsureLocalsAndParameters(); } if (guidFilter == AD7Guids.guidFilterLocalsPlusArgs || guidFilter == AD7Guids.guidFilterAllLocalsPlusArgs || guidFilter == AD7Guids.guidFilterAllLocals) { CreateLocalsPlusArgsProperties(dwFields, out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterLocals) { CreateLocalProperties(dwFields, out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterArgs) { CreateParameterProperties(dwFields, out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else { hr = VSConstants.E_NOTIMPL; } } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(hr); }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { AD_PROCESS_ID processId = EngineUtils.GetProcessId(rgpPrograms[0]); EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(); _engineCallback = new EngineCallback(this, ad7Callback); _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; } else { if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { Debug.Fail("Asked to attach to a process while we are debugging"); return(VSConstants.E_FAIL); } } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); this.ProgramCreateEventSent = true; return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, reportOnlyCorrupting: true)) { return(EngineUtils.UnexpectedException(e)); } }
// Gets properties that describe a thread. int IDebugThread2.GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] propertiesArray) { try { THREADPROPERTIES props = new THREADPROPERTIES(); if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0) { props.dwThreadId = (uint)debuggedThread.Id; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT) != 0) { // sample debug engine doesn't support suspending threads props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0) { props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_PRIORITY) != 0) { props.bstrPriority = "Normal"; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0) { props.bstrName = ThreadNameString; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_LOCATION) != 0) { props.bstrLocation = GetCurrentLocation(true); props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_LOCATION; } return(VSConstants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
int IDebugEngine2.CreatePendingBreakpoint(IDebugBreakpointRequest2 pBPRequest, out IDebugPendingBreakpoint2 ppPendingBP) { // Creates a pending breakpoint in the engine. A pending breakpoint is contains all the information needed to bind a breakpoint to // a location in the debuggee. ppPendingBP = null; try { BPMgr.CreatePendingBreakpoint(pBPRequest, out ppPendingBP); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// Resume a process launched by IDebugEngineLaunch2.LaunchSuspended int IDebugEngineLaunch2.ResumeProcess(IDebugProcess2 process) { Debug.Assert(_pollThread != null); Debug.Assert(_engineCallback != null); Debug.Assert(_debuggedProcess != null); Debug.Assert(_ad7ProgramId == Guid.Empty); try { AD_PROCESS_ID processId = EngineUtils.GetProcessId(process); if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { return(VSConstants.S_FALSE); } // Send a program node to the SDM. This will cause the SDM to turn around and call IDebugEngine2.Attach // which will complete the hookup with AD7 IDebugPort2 port; EngineUtils.RequireOk(process.GetPort(out port)); IDebugDefaultPort2 defaultPort = (IDebugDefaultPort2)port; IDebugPortNotify2 portNotify; EngineUtils.RequireOk(defaultPort.GetPortNotify(out portNotify)); EngineUtils.RequireOk(portNotify.AddProgramNode(new AD7ProgramNode(_debuggedProcess.Id))); if (_ad7ProgramId == Guid.Empty) { Debug.Fail("Unexpected problem -- IDebugEngine2.Attach wasn't called"); return(VSConstants.E_FAIL); } // NOTE: We wait for the program create event to be continued before we really resume the process return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, reportOnlyCorrupting: true)) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets properties that describe a thread.. /// </summary> /// <param name="dwFields">The fields.</param> /// <param name="propertiesArray">The properties array.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] propertiesArray) { try { var props = new THREADPROPERTIES(); if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0) { props.dwThreadId = (uint)_debuggedThread.Id; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT) != 0) { props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0) { props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_PRIORITY) != 0) { props.bstrPriority = "Normal"; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0) { props.bstrName = ThreadNameString; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_LOCATION) != 0) { props.bstrLocation = GetCurrentLocation(); props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_LOCATION; } return(S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
int IDebugEngineLaunch2.ResumeProcess(IDebugProcess2 aProcess) { // Resume a process launched by IDebugEngineLaunch2.LaunchSuspended try { // Send a program node to the SDM. This will cause the SDM to turn around and call IDebugEngine2.Attach // which will complete the hookup with AD7 var xProcess = aProcess as AD7Process; if (xProcess == null) { return(VSConstants.E_INVALIDARG); } IDebugPort2 xPort; EngineUtils.RequireOk(aProcess.GetPort(out xPort)); var xDefPort = (IDebugDefaultPort2)xPort; IDebugPortNotify2 xNotify; EngineUtils.RequireOk(xDefPort.GetPortNotify(out xNotify)); // This triggers Attach EngineUtils.RequireOk(xNotify.AddProgramNode(mProgNode)); Callback.OnModuleLoad(mModule); Callback.OnSymbolSearch(mModule, xProcess.mISO.Replace("iso", "pdb"), enum_MODULE_INFO_FLAGS.MIF_SYMBOLS_LOADED); // Important! // // This call triggers setting of breakpoints that exist before run. // So it must be called before we resume the process. // If not called VS will call it after our 3 startup events, but thats too late. // This line was commented out in earlier Cosmos builds and caused problems with // breakpoints and timing. Callback.OnThreadStart(mThread); // Not sure what this does exactly. It was commented out before // but so was a lot of stuff we actually needed. If its uncommented it // throws: // "Operation is not valid due to the current state of the object." //AD7EntrypointEvent.Send(this); // Now finally release our process to go after breakpoints are set mProcess.ResumeFromLaunch(); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// Gets a description of the stack frame. int IDebugStackFrame2.GetInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, FRAMEINFO[] pFrameInfo) { try { SetFrameInfo(dwFieldSpec, out pFrameInfo[0]); return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets a description of the stack frame. /// </summary> /// <param name="dwFieldSpec">The field spec.</param> /// <param name="nRadix">The radix.</param> /// <param name="pFrameInfo">The frame information.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int GetInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, FRAMEINFO[] pFrameInfo) { try { SetFrameInfo(dwFieldSpec, out pFrameInfo[0]); return(S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
int IDebugEngineLaunch2.TerminateProcess(IDebugProcess2 aProcess) { // This function is used to terminate a process that the SampleEngine launched // The debugger will call IDebugEngineLaunch2::CanTerminateProcess before calling this method. try { mProcess.Terminate(); mEngineCallback.OnProcessExit(0); mProgram = null; } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
/// <summary> /// Retrieves a list of the stack frames for this thread. /// For the sample engine, enumerating the stack frames requires walking the callstack in the debuggee for this thread /// and coverting that to an implementation of IEnumDebugFrameInfo2. /// Real engines will most likely want to cache this information to avoid recomputing it each time it is asked for, /// and or construct it on demand instead of walking the entire stack. /// </summary> /// <param name="dwFieldSpec">The field spec.</param> /// <param name="nRadix">The radix.</param> /// <param name="enumObject">The enum object.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int EnumFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, out IEnumDebugFrameInfo2 enumObject) { // Ask the lower-level to perform a stack walk on this thread enumObject = null; try { var numStackFrames = _debuggedThread.Backtrace.FrameCount; FRAMEINFO[] frameInfoArray; if (numStackFrames == 0) { // failed to walk any frames. Only return the top frame. frameInfoArray = new FRAMEINFO[0]; // MonoStackFrame frame = new MonoStackFrame(engine, this, debuggedThread); // frame.SetFrameInfo(dwFieldSpec, out frameInfoArray[0]); } else { frameInfoArray = new FRAMEINFO[numStackFrames]; for (var i = 0; i < numStackFrames; i++) { var i1 = i; var frame = new MonoStackFrame(_engine, this, () => _debuggedThread.Backtrace.GetFrame(i1)); if (_lineNumberOverride != null) { frame.LineNumber = _lineNumberOverride.Value; } frame.SetFrameInfo(dwFieldSpec, out frameInfoArray[i]); } } enumObject = new MonoFrameInfoEnumerator(frameInfoArray); return(S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the code context for this stack frame. The code context represents the current instruction pointer in this stack frame. int IDebugStackFrame2.GetCodeContext(out IDebugCodeContext2 memoryAddress) { memoryAddress = null; try { //memoryAddress = new AD7MemoryAddress(m_engine, m_threadContext.eip); return(VSConstants.E_NOTIMPL); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the name of the stack frame. // The name of a stack frame is typically the name of the method being executed. int IDebugStackFrame2.GetName(out string name) { name = null; try { name = mFunctionName; return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the code context for this stack frame. The code context represents the current instruction pointer in this stack frame. int IDebugStackFrame2.GetCodeContext(out IDebugCodeContext2 memoryAddress) { memoryAddress = null; try { memoryAddress = new MonoMemoryAddress(engine, (uint)frame().Address, null); return(VSConstants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets the code context for this stack frame. The code context represents the current instruction pointer in this /// stack frame. /// </summary> /// <param name="memoryAddress">The memory address.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int GetCodeContext(out IDebugCodeContext2 memoryAddress) { memoryAddress = null; try { memoryAddress = new MonoMemoryAddress(_engine, (uint)_frame().Address, null); return(S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Retrieves a list of the stack frames for this thread. // For the sample engine, enumerating the stack frames requires walking the callstack in the debuggee for this thread // and coverting that to an implementation of IEnumDebugFrameInfo2. // Real engines will most likely want to cache this information to avoid recomputing it each time it is asked for, // and or construct it on demand instead of walking the entire stack. int IDebugThread2.EnumFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, out IEnumDebugFrameInfo2 enumObject) { enumObject = null; try { // get the thread's stack frames System.Collections.Generic.List <ThreadContext> stackFrames = null; _engine.DebuggedProcess.WorkerThread.RunOperation(async() => stackFrames = await _engine.DebuggedProcess.ThreadCache.StackFrames(_debuggedThread)); int numStackFrames = stackFrames != null ? stackFrames.Count : 0; FRAMEINFO[] frameInfoArray; if (numStackFrames == 0) { // failed to walk any frames. Return an empty stack. frameInfoArray = new FRAMEINFO[0]; } else { uint low = stackFrames[0].Level; uint high = stackFrames[stackFrames.Count - 1].Level; FilterUnknownFrames(stackFrames); numStackFrames = stackFrames.Count; frameInfoArray = new FRAMEINFO[numStackFrames]; for (int i = 0; i < numStackFrames; i++) { //var p = parameters != null ? parameters.Find((ArgumentList t) => t.Item1 == stackFrames[i].Level) : null; AD7StackFrame frame = new AD7StackFrame(_engine, this, stackFrames[i]); frame.SetFrameInfo(dwFieldSpec, out frameInfoArray[i], null); } } enumObject = new AD7FrameInfoEnum(frameInfoArray); return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Retrieves a list of the stack frames for this thread. // For the sample engine, enumerating the stack frames requires walking the callstack in the debuggee for this thread // and coverting that to an implementation of IEnumDebugFrameInfo2. // Real engines will most likely want to cache this information to avoid recomputing it each time it is asked for, // and or construct it on demand instead of walking the entire stack. int IDebugThread2.EnumFrameInfo(enum_FRAMEINFO_FLAGS aFieldSpec, uint aRadix, out IEnumDebugFrameInfo2 oEnumObject) { // Check mStackFrame, not address because it is possible for 2 sequential breaks to be on the same address // but in that case we would need a new stack frame. // // EnumFrameInfo is called several times on each break becuase "different callers can call with different flags". // We ignore flags through and always return full, but EnumFrameInfo gets called half a dozen times which is slow // if we refresh each and every time. So we cache our info. if (mProcess.mStackFrame == null || true) { // Ask the lower-level to perform a stack walk on this thread //m_engine.DebuggedProcess.DoStackWalk(this.m_debuggedThread); oEnumObject = null; try { //System.Collections.Generic.List<X86ThreadContext> stackFrames = this.m_debuggedThread.StackFrames; //int numStackFrames = stackFrames.Count; FRAMEINFO[] xFrameInfoArray; //if (numStackFrames == 0) { // failed to walk any frames. Only return the top frame. xFrameInfoArray = new FRAMEINFO[1]; var xFrame = new AD7StackFrame(mEngine, this, mProcess); xFrame.SetFrameInfo((enum_FRAMEINFO_FLAGS)aFieldSpec, out xFrameInfoArray[0]); //} else { //frameInfoArray = new FRAMEINFO[numStackFrames]; //for (int i = 0; i < numStackFrames; i++) { //AD7StackFrame frame = new AD7StackFrame(m_engine, this, stackFrames[i]); //frame.SetFrameInfo(dwFieldSpec, out frameInfoArray[i]); //} //} mProcess.mStackFrame = new AD7FrameInfoEnum(xFrameInfoArray); } catch (Exception e) { //catch (ComponentException e) { // return e.HResult; //} return(EngineUtils.UnexpectedException(e)); } } oEnumObject = mProcess.mStackFrame; return(VSConstants.S_OK); }
// Parses a text-based expression for evaluation. // The engine sample only supports locals and parameters so the only task here is to check the names in those collections. int IDebugExpressionContext2.ParseText(string pszCode, enum_PARSEFLAGS dwFlags, uint nRadix, out IDebugExpression2 ppExpr, out string pbstrError, out uint pichError) { //System.Windows.Forms.AD7Util.MessageBox("pszCode: " + pszCode); pbstrError = ""; pichError = 0; ppExpr = null; try { if (mParams != null) { foreach (DebugLocalInfo currVariable in mParams) { if (String.CompareOrdinal(currVariable.Name, pszCode) == 0) { ppExpr = new AD7Expression(currVariable, mProcess, this); return(VSConstants.S_OK); } } } if (mLocals != null) { foreach (DebugLocalInfo currVariable in mLocals) { if (String.CompareOrdinal(currVariable.Name, pszCode) == 0) { ppExpr = new AD7Expression(currVariable, mProcess, this); return(VSConstants.S_OK); } } } pbstrError = "Invalid Expression"; pichError = (uint)pbstrError.Length; return(VSConstants.S_FALSE); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Creates an enumerator for properties associated with the stack frame, such as local variables. /// The sample engine only supports returning locals and parameters. Other possible values include /// class fields (this pointer), registers, exceptions... /// </summary> /// <param name="dwFields"></param> /// <param name="nRadix"></param> /// <param name="guidFilter"></param> /// <param name="dwTimeout"></param> /// <param name="elementsReturned"></param> /// <param name="enumObject"></param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int EnumProperties(enum_DEBUGPROP_INFO_FLAGS dwFields, uint nRadix, ref Guid guidFilter, uint dwTimeout, out uint elementsReturned, out IEnumDebugPropertyInfo2 enumObject) { int hr; elementsReturned = 0; enumObject = null; try { if ((guidFilter == Guids.FilterLocalsPlusArgs) || (guidFilter == Guids.FilterAllLocalsPlusArgs) || (guidFilter == Guids.FilterAllLocals)) { CreateLocalsPlusArgsProperties(out elementsReturned, out enumObject); hr = S_OK; } else if (guidFilter == Guids.FilterLocals) { CreateLocalProperties(out elementsReturned, out enumObject); hr = S_OK; } else if (guidFilter == Guids.FilterArgs) { CreateParameterProperties(out elementsReturned, out enumObject); hr = S_OK; } else { hr = E_NOTIMPL; } } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(hr); }
public int EnumCodeContexts(out IEnumDebugCodeContexts2 ppEnumCodeCxts) { ppEnumCodeCxts = null; try { var codeContexts = new MonoMemoryAddress[1]; codeContexts[0] = address; ppEnumCodeCxts = new MonoCodeContextEnum(codeContexts); return(VSConstants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Retrieves a list of all code contexts associated with this document context. /// </summary> /// <param name="ppEnumCodeCxts">The enumerator.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int EnumCodeContexts(out IEnumDebugCodeContexts2 ppEnumCodeCxts) { ppEnumCodeCxts = null; try { var codeContexts = new IDebugCodeContext2[1]; codeContexts[0] = _address; ppEnumCodeCxts = new MonoCodeContextEnumerator(codeContexts); return(S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Retrieves a list of all code contexts associated with this document context. // The engine sample only supports one code context per document context and // the code contexts are always memory addresses. int IDebugDocumentContext2.EnumCodeContexts(out IEnumDebugCodeContexts2 ppEnumCodeCxts) { ppEnumCodeCxts = null; try { AD7MemoryAddress[] codeContexts = new AD7MemoryAddress[1]; codeContexts[0] = m_codeContext; ppEnumCodeCxts = new AD7CodeContextEnum(codeContexts); return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }