/// <summary> /// Retrieves a list of all code contexts associated with this document context. The VSNDK Debug Engine only supports one code context per document /// context and the code contexts are always memory addresses. (http://msdn.microsoft.com/en-us/library/bb146273.aspx) /// </summary> /// <param name="ppEnumCodeCxts"> Returns an IEnumDebugCodeContexts2 object that contains a list of code contexts. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> 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 (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets a description of the process. (http://msdn.microsoft.com/en-us/library/bb145895.aspx) /// </summary> /// <param name="Fields"> A combination of values from the PROCESS_INFO_FIELDS enumeration that specifies which fields of /// the pProcessInfo parameter are to be filled in. </param> /// <param name="pProcessInfo"> A PROCESS_INFO structure that is filled in with a description of the process. </param> /// <returns> VSConstants.S_OK. </returns> public int GetInfo(enum_PROCESS_INFO_FIELDS Fields, PROCESS_INFO[] pProcessInfo) { try { if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_FILE_NAME) != 0) { pProcessInfo[0].bstrFileName = this._name; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_FILE_NAME; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_BASE_NAME) != 0) { pProcessInfo[0].bstrBaseName = this._name.Substring(_name.LastIndexOf('/') + 1); pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_BASE_NAME; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_TITLE) != 0) { pProcessInfo[0].bstrTitle = this._name; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_TITLE; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_PROCESS_ID) != 0) { pProcessInfo[0].ProcessId.dwProcessId = Convert.ToUInt32(this._processID); pProcessInfo[0].ProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_PROCESS_ID; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_SESSION_ID) != 0) { // pProcessInfo[0].dwSessionId = 0; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_SESSION_ID; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_ATTACHED_SESSION_NAME) != 0) { // pProcessInfo[0].bstrAttachedSessionName = null; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_ATTACHED_SESSION_NAME; } if ((Fields & enum_PROCESS_INFO_FIELDS.PIF_CREATION_TIME) != 0) { // pProcessInfo[0].CreationTime = null; pProcessInfo[0].Fields |= enum_PROCESS_INFO_FIELDS.PIF_CREATION_TIME; } return(VSConstants.S_OK); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets the file statement range of the document context. A statement range is the range of the lines that contributed the code /// to which this document context refers. (http://msdn.microsoft.com/en-us/library/bb161669.aspx) /// </summary> /// <param name="pBegPosition"> A TEXT_POSITION structure that is filled in with the starting position. Set to a null value if it is not needed. </param> /// <param name="pEndPosition"> A TEXT_POSITION structure that is filled in with the ending position. Set to a null value if it is not needed. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugDocumentContext2.GetStatementRange(TEXT_POSITION[] pBegPosition, TEXT_POSITION[] pEndPosition) { try { pBegPosition[0].dwColumn = m_begPos.dwColumn; pBegPosition[0].dwLine = m_begPos.dwLine; pEndPosition[0].dwColumn = m_endPos.dwColumn; pEndPosition[0].dwLine = m_endPos.dwLine; } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
/// <summary> /// Bind this breakpoint. (http://msdn.microsoft.com/en-ca/library/bb145901.aspx) /// </summary> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { AD7BoundBreakpoint xBBP = null; // Visual Studio returns a start position that is one less than it actually is xBBP = new AD7BoundBreakpoint(m_engine, m_bpRequestInfo, this); if (VSNDK.Package.ControlDebugEngine.isDebugEngineRunning == false) { return(VSConstants.S_FALSE); } if ((xBBP == null) || (xBBP.GDB_ID == 0)) { return(VSConstants.S_FALSE); } // Set the enabled state of the bound breakpoint based on the pending breakpoint's enabled state ((IDebugBoundBreakpoint2)xBBP).Enable(Convert.ToInt32(m_enabled)); m_boundBreakpoints.Add(xBBP); 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... The VSNDK debug engine does not support this, but a real world engine will want to send an // instance of IDebugBreakpointErrorEvent2 to the UI and return a valid instance of IDebugErrorBreakpoint2 from // IDebugPendingBreakpoint2::EnumErrorBreakpoints. The debugger will then display information about why the // breakpoint did not bind to the user. return(VSConstants.S_FALSE); } } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Compares the memory context to each context in the given array in the manner indicated by compare flags, /// returning an index of the first context that matches. (http://msdn.microsoft.com/en-ca/library/bb161750.aspx) /// </summary> /// <param name="uContextCompare"> A value from the CONTEXT_COMPARE enumeration that determines the type of comparison. </param> /// <param name="compareToItems"> An array of references to the IDebugMemoryContext2 objects to compare against. </param> /// <param name="compareToLength"> The number of contexts in the compareToItems array. </param> /// <param name="foundIndex"> Returns the index of the first memory context that satisfies the comparison. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> public int Compare(enum_CONTEXT_COMPARE uContextCompare, IDebugMemoryContext2[] compareToItems, uint compareToLength, out uint foundIndex) { foundIndex = uint.MaxValue; try { enum_CONTEXT_COMPARE contextCompare = (enum_CONTEXT_COMPARE)uContextCompare; for (uint c = 0; c < compareToLength; c++) { AD7MemoryAddress compareTo = compareToItems[c] as AD7MemoryAddress; if (compareTo == null) { continue; } if (!AD7Engine.ReferenceEquals(this.m_engine, compareTo.m_engine)) { continue; } bool result; switch (contextCompare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = (this.m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = (this.m_address < compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = (this.m_address > compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = (this.m_address <= compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = (this.m_address >= compareTo.m_address); break; // The VSNDK debug engine doesn't understand scopes or functions case enum_CONTEXT_COMPARE.CONTEXT_SAME_SCOPE: case enum_CONTEXT_COMPARE.CONTEXT_SAME_FUNCTION: result = (this.m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_MODULE: result = (this.m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_PROCESS: result = true; break; default: // A new comparison was invented that we don't support return(VSConstants.E_NOTIMPL); } if (result) { foundIndex = c; return(VSConstants.S_OK); } } return(VSConstants.S_FALSE); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets the properties that describe this thread. /// (http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.debugger.interop.idebugthread100.getthreadproperties100.aspx) /// </summary> /// <param name="dwFields"> A combination of flags from the THREADPROPERTIES100 enumeration that determines which fields of /// ptp are to be filled in. </param> /// <param name="ptp"> A THREADPROPERTIES100 structure that that is filled in with the properties of the thread. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugThread100.GetThreadProperties100(uint dwFields, THREADPROPERTIES100[] ptp) { try { if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_ID) != 0) { try { ptp[0].dwThreadId = Convert.ToUInt32(this._id); } catch { ptp[0].dwThreadId = 0; } ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_ID; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_SUSPENDCOUNT) != 0) { // VSNDK debug engine doesn't support suspending threads ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_SUSPENDCOUNT; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_STATE) != 0) { if (this._state == "running") { ptp[0].dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; } else { ptp[0].dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_STOPPED; } ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_STATE; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_PRIORITY) != 0) { ptp[0].bstrPriority = "Normal"; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_PRIORITY; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_NAME) != 0) { ptp[0].bstrName = _threadDisplayName; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_NAME; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_DISPLAY_NAME) != 0) { // Thread display name is being requested ptp[0].bstrDisplayName = _threadDisplayName; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_DISPLAY_NAME; // Give this display name a higher priority than the default (0) // so that it will actually be displayed ptp[0].DisplayNamePriority = 10; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_DISPLAY_NAME_PRIORITY; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_LOCATION) != 0) { ptp[0].bstrLocation = ""; if (__stackFrames != null) { foreach (AD7StackFrame frame in __stackFrames) { if ((frame.m_functionName != "") && (frame.m_functionName != "??")) { ptp[0].bstrLocation = frame.m_functionName; break; } } } else { ptp[0].bstrLocation = getFunctionName(); } if (ptp[0].bstrLocation == "") { ptp[0].bstrLocation = "[External Code]"; } ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_LOCATION; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_CATEGORY) != 0) { if (this._id == "1") { ptp[0].dwThreadCategory = (uint)enum_THREADCATEGORY.THREADCATEGORY_Main; } else { ptp[0].dwThreadCategory = (uint)enum_THREADCATEGORY.THREADCATEGORY_Worker; } ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_CATEGORY; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_AFFINITY) != 0) { // Thread cpu affinity is being requested ptp[0].AffinityMask = 0; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_AFFINITY; } if ((dwFields & (uint)enum_THREADPROPERTY_FIELDS100.TPF100_PRIORITY_ID) != 0) { // Thread display name is being requested ptp[0].priorityId = 0; ptp[0].dwFields |= (uint)enum_THREADPROPERTY_FIELDS100.TPF100_PRIORITY_ID; } return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets the properties that describe this thread. (http://msdn.microsoft.com/en-ca/library/bb145602.aspx) /// </summary> /// <param name="dwFields"> A combination of flags from the THREADPROPERTY_FIELDS enumeration that determines which fields of /// ptp are to be filled in. </param> /// <param name="ptp"> A THREADPROPERTIES structure that that is filled in with the properties of the thread. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugThread2.GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] ptp) { try { if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0) { try { ptp[0].dwThreadId = Convert.ToUInt32(this._id); } catch { ptp[0].dwThreadId = 0; } ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT) != 0) { // VSNDK debug engine doesn't support suspending threads ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0) { if (this._state == "running") { ptp[0].dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; } else { ptp[0].dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_STOPPED; } ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_PRIORITY) != 0) { ptp[0].bstrPriority = "Normal"; ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0) { ptp[0].bstrName = _threadDisplayName; ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_LOCATION) != 0) { ptp[0].bstrLocation = ""; if (__stackFrames != null) { foreach (AD7StackFrame frame in __stackFrames) { if (frame.m_functionName != "") { ptp[0].bstrLocation = frame.m_functionName; break; } } } if (ptp[0].bstrLocation == "") { ptp[0].bstrLocation = "[External Code]"; } ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_LOCATION; } return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Retrieves a list of the stack frames for this thread. (http://msdn.microsoft.com/en-ca/library/bb145138.aspx) /// </summary> /// <param name="dwFieldSpec"> A combination of flags from the FRAMEINFO_FLAGS enumeration that specifies which fields of the /// FRAMEINFO structures are to be filled out. </param> /// <param name="nRadix"> Radix used in formatting numerical information in the enumerator. </param> /// <param name="ppEnum"> Returns an IEnumDebugFrameInfo2 object that contains a list of FRAMEINFO structures describing the /// stack frame. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugThread2.EnumFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, out IEnumDebugFrameInfo2 ppEnum) { if (this._id == "") { ppEnum = null; return(Constants.S_FALSE); } if (this._engine.evaluatedTheseFlags(this._id, dwFieldSpec)) { ppEnum = new AD7FrameInfoEnum(previousFrameInfoArray); return(Constants.S_OK); } // Ask for general stack information. if ((this._id != "") && (this._id != this._engine.currentThread()._id)) { _engine.eDispatcher.selectThread(this._id); } string stackResponse = _engine.eDispatcher.getStackFrames().Replace("#;;;;", ""); if (stackResponse == "") { ppEnum = null; return(Constants.S_FALSE); } string[] frameStrings = stackResponse.Split('#'); // Query the stack depth without inquiring GDB. int numStackFrames = frameStrings.Length; if (numStackFrames > 30) // limiting the amount of stackFrames to avoid VS crashing. { numStackFrames = 30; } ppEnum = null; try { bool created = false; FRAMEINFO[] frameInfoArray = new FRAMEINFO[numStackFrames]; for (int i = 0; i < numStackFrames; i++) { string[] frameInfo = frameStrings[i].Split(';'); if (frameInfo.Length >= 3) { if (frameInfo[3].Contains("~")) { // Need to lengthen the path used by Visual Studio. StringBuilder longPathName = new StringBuilder(1024); GetLongPathName(frameInfo[3], longPathName, longPathName.Capacity); frameInfo[3] = longPathName.ToString(); } AD7StackFrame frame = AD7StackFrame.create(_engine, this, frameInfo, ref created); if (frame.m_thread.__stackFrames == null) // that's weird, but sometimes VS is not initializing __stackFrames, so I added this loop to avoid other problems. { while (frame.m_thread.__stackFrames == null) { frame.m_thread.__stackFrames = new ArrayList() { frame } } ; } frame.SetFrameInfo(dwFieldSpec, out frameInfoArray[i]); } } if ((previousFrameInfoArray.Length != frameInfoArray.Length) || (created == true)) { previousFrameInfoArray = frameInfoArray; ppEnum = new AD7FrameInfoEnum(frameInfoArray); } else { bool isEqual = true; for (int i = 0; i < frameInfoArray.Length; i++) { if (frameInfoArray[i].m_bstrFuncName != previousFrameInfoArray[i].m_bstrFuncName) { isEqual = false; break; } if (frameInfoArray[i].m_dwValidFields != previousFrameInfoArray[i].m_dwValidFields) { isEqual = false; break; } if (frameInfoArray[i].m_bstrLanguage != previousFrameInfoArray[i].m_bstrLanguage) { isEqual = false; break; } } if (!isEqual) { previousFrameInfoArray = frameInfoArray; ppEnum = new AD7FrameInfoEnum(frameInfoArray); } else { ppEnum = new AD7FrameInfoEnum(previousFrameInfoArray); } } if ((this._id != "") && (this._id != this._engine.currentThread()._id)) { _engine.eDispatcher.selectThread(this._engine.currentThread()._id); } return(Constants.S_OK); } catch (ComponentException e) { if ((this._id != "") && (this._id != this._engine.currentThread()._id)) { _engine.eDispatcher.selectThread(this._engine.currentThread()._id); } return(e.HResult); } catch (Exception e) { if ((this._id != "") && (this._id != this._engine.currentThread()._id)) { _engine.eDispatcher.selectThread(this._engine.currentThread()._id); } return(EngineUtils.UnexpectedException(e)); } }
/// <summary> /// Gets information about this module. (http://msdn.microsoft.com/en-ca/library/bb161975.aspx) /// </summary> /// <param name="dwFields"> A combination of flags from the MODULE_INFO_FIELDS enumeration that specify which fields of pInfo /// are to be filled out. </param> /// <param name="infoArray"> A MODULE_INFO structure that is filled in with a description of the module. </param> /// <returns> If successful, returns S_OK; otherwise, returns an error code. </returns> int IDebugModule2.GetInfo(enum_MODULE_INFO_FIELDS dwFields, MODULE_INFO[] infoArray) { try { MODULE_INFO info = new MODULE_INFO(); if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_NAME)) { info.m_bstrName = ""; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URL)) { info.m_bstrUrl = ""; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URL; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS)) { info.m_addrLoadAddress = 0; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS)) { // A debugger that actually supports showing the preferred base should crack the PE header and get // that field. This debugger does not do that, so assume the module loaded where it was suppose to. info.m_addrPreferredLoadAddress = 0; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_SIZE)) { info.m_dwSize = 0; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_SIZE; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADORDER)) { info.m_dwLoadOrder = 0; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADORDER; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION)) { info.m_bstrUrlSymbolLocation = ""; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_FLAGS)) { info.m_dwModuleFlags = 0; info.m_dwModuleFlags |= (enum_MODULE_FLAGS.MODULE_FLAG_SYMBOLS); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_VERSION)) { info.m_bstrVersion = ""; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_VERSION; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_DEBUGMESSAGE)) { info.m_bstrDebugMessage = ""; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_DEBUGMESSAGE; } infoArray[0] = info; return(VSConstants.S_OK); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }