int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint aCeltPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { // Attach the debug engine to a program. // // Attach can either be called to attach to a new process, or to complete an attach // to a launched process. // So could we simplify and move code from LaunchSuspended to here and maybe even // eliminate the debughost? Although I supposed DebugHost has some other uses as well. if (aCeltPrograms != 1) { System.Diagnostics.Debug.Fail("Cosmos Debugger only supports one debug target at a time."); throw new ArgumentException(); } try { EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out mProgramID)); mProgram = rgpPrograms[0]; AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); AD7ModuleLoadEvent.Send(this, mModule, true); // Dummy main thread // We dont support threads yet, but the debugger expects threads. // So we create a dummy object to represente our only "thread". mThread = new AD7Thread(this, mProcess); AD7LoadCompleteEvent.Send(this, mThread); } 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 (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 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)); } }
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); }
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); }
// Gets a description of the stack frame. int IDebugStackFrame2.GetInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, FRAMEINFO[] pFrameInfo) { try { SetFrameInfo((enum_FRAMEINFO_FLAGS)dwFieldSpec, out pFrameInfo[0]); return(VSConstants.S_OK); } //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 AD7MemoryAddress(m_engine, m_threadContext.eip); return(VSConstants.E_NOTIMPL); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { 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.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_ID)) { //props.dwThreadId = (uint)m_debuggedThread.Id; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT)) { // sample debug engine doesn't support suspending threads props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_STATE)) { props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_PRIORITY)) { props.bstrPriority = "Normal"; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_NAME)) { props.bstrName = ThreadNameString; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_LOCATION)) { 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)); } }
// 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) { // 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); }
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); }
// 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)); } }
// 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.MessageBox.Show("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)); } }
// 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. 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 (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// 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.guidFilterLocalsPlusArgs || guidFilter == AD7Guids.guidFilterAllLocalsPlusArgs) { CreateLocalsPlusArgsProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterLocals) { CreateLocalProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterArgs) { CreateParameterProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else { hr = VSConstants.E_NOTIMPL; } } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(hr); }
// During startup these methods are called in this order: // -LaunchSuspended // -ResumeProcess // -Attach - Triggered by Attach int IDebugEngineLaunch2.LaunchSuspended(string aPszServer, IDebugPort2 aPort, string aDebugInfo , string aArgs, string aDir, string aEnv, string aOptions, enum_LAUNCH_FLAGS aLaunchFlags , uint aStdInputHandle, uint aStdOutputHandle, uint hStdError, IDebugEventCallback2 aAD7Callback , out IDebugProcess2 oProcess) { // Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. oProcess = null; try { mEngineCallback = new EngineCallback(this, aAD7Callback); var xDebugInfo = new NameValueCollection(); NameValueCollectionHelper.LoadFromString(xDebugInfo, aDebugInfo); //TODO: In the future we might support command line args for kernel etc //string xCmdLine = EngineUtils.BuildCommandLine(exe, args); //var processLaunchInfo = new ProcessLaunchInfo(exe, xCmdLine, dir, env, options, launchFlags, hStdInput, hStdOutput, hStdError); AD7EngineCreateEvent.Send(this); oProcess = mProcess = new AD7Process(xDebugInfo, mEngineCallback, this, aPort); // We only support one process, so just use its ID for the program ID mProgramID = mProcess.ID; //AD7ThreadCreateEvent.Send(this, xProcess.Thread); mModule = new AD7Module(); mProgNode = new AD7ProgramNode(mProcess.PhysID); } catch (NotSupportedException) { return(VSConstants.S_FALSE); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// 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. 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 sample 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); if (result == false) { //DebuggedModule module = m_engine.DebuggedProcess.ResolveAddress(m_address); //if (module != null) //{ // result = (compareTo.m_address >= module.BaseAddress) && // (compareTo.m_address < module.BaseAddress + module.Size); //} } 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 (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { var xDocPos = (IDebugDocumentPosition2)(Marshal.GetObjectForIUnknown(mBpRequestInfo.bpLocation.unionmember2)); // Get the name of the document that the breakpoint was put in string xDocName; EngineUtils.CheckOk(xDocPos.GetFileName(out xDocName)); xDocName = xDocName.ToLower(); //Bug: Some filenames were returned with the drive letter as lower case but in DocumentGUIDs it was captialised so file-not-found! // Get the location in the document that the breakpoint is in. var xStartPos = new TEXT_POSITION[1]; var xEndPos = new TEXT_POSITION[1]; EngineUtils.CheckOk(xDocPos.GetRange(xStartPos, xEndPos)); UInt32 xAddress = 0; var xDebugInfo = mEngine.mProcess.mDebugInfoDb; // We must check for DocID. This is important because in a solution that contains many projects, // VS will send us BPs from other Cosmos projects (and possibly non Cosmos ones, didnt look that deep) // but we wont have them in our doc list because it contains only ones from the currently project // to run. Guid xDocID; if (xDebugInfo.DocumentGUIDs.TryGetValue(xDocName, out xDocID)) { // Find which Method the Doc, Line, Col are in. // Must add +1 for both Line and Col. They are 0 based, while SP ones are 1 based. // () around << are VERY important.. + has precedence over << Int64 xPos = (((Int64)xStartPos[0].dwLine + 1) << 32) + xStartPos[0].dwColumn + 1; try { var potXMethods = xDebugInfo.Connection.Query(new SQLinq <Method>().Where(x => x.DocumentID == xDocID && x.LineColStart <= xPos && x.LineColEnd >= xPos)); var xMethod = potXMethods.Single(); var asm = xDebugInfo.Connection.Get <AssemblyFile>(xMethod.AssemblyFileID); // We have the method. Now find out what Sequence Point it belongs to. var xSPs = xDebugInfo.GetSequencePoints(asm.Pathname, xMethod.MethodToken); var xSP = xSPs.Single(q => q.LineColStart <= xPos && q.LineColEnd >= xPos); // We have the Sequence Point, find the MethodILOp var xOp = xDebugInfo.Connection.Query(new SQLinq <MethodIlOp>().Where(q => q.MethodID == xMethod.ID && q.IlOffset == xSP.Offset)).First(); // Get the address of the Label xAddress = xDebugInfo.AddressOfLabel(xOp.LabelName); if (xAddress > 0) { var xBPR = new AD7BreakpointResolution(mEngine, xAddress, GetDocumentContext(xAddress)); var xBBP = new AD7BoundBreakpoint(mEngine, xAddress, this, xBPR); mBoundBPs.Add(xBBP); } // Ask the symbol engine to find all addresses in all modules with symbols that match this source and line number. //uint[] addresses = mEngine.DebuggedProcess.GetAddressesForSourceLocation(null, documentName, startPosition[0].dwLine + 1, startPosition[0].dwColumn); lock (mBoundBPs) { //foreach (uint addr in addresses) { // AD7BreakpointResolution breakpointResolution = new AD7BreakpointResolution(mEngine, addr, GetDocumentContext(addr)); // AD7BoundBreakpoint boundBreakpoint = new AD7BoundBreakpoint(mEngine, addr, this, breakpointResolution); // m_boundBreakpoints.Add(boundBreakpoint); // mEngine.DebuggedProcess.SetBreakpoint(addr, boundBreakpoint); //} } } catch (InvalidOperationException) { //No elements in potXMethods sequence! return(VSConstants.S_FALSE); } } 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 sample 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 (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the MODULE_INFO that describes this module. // This is how the debugger obtains most of the information about the module. 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 = System.IO.Path.GetFileName(this.DebuggedModule.Name); info.m_bstrName = "DEADBEEF"; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URL)) { //info.m_bstrUrl = this.DebuggedModule.Name; info.m_bstrUrl = "DEADBEEF"; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URL; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS)) { //info.m_addrLoadAddress = (ulong)this.DebuggedModule.BaseAddress; 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 = (ulong)this.DebuggedModule.BaseAddress; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_SIZE)) { //info.m_dwSize = this.DebuggedModule.Size; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_SIZE; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADORDER)) { //info.m_dwLoadOrder = this.DebuggedModule.GetLoadOrder(); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADORDER; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION)) { //if (this.DebuggedModule.SymbolsLoaded) { //info.m_bstrUrlSymbolLocation = this.DebuggedModule.SymbolPath; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION; } } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_FLAGS)) { info.m_dwModuleFlags = 0; //if (this.DebuggedModule.SymbolsLoaded) { info.m_dwModuleFlags |= (enum_MODULE_FLAGS.MODULE_FLAG_SYMBOLS); } info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS; } infoArray[0] = info; return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }