// 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(Constants.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 & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0) { pinfo[0].bstrAddress = m_address.ToString(); pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS; } // Fields not supported by the sample if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) { } return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// 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(Constants.E_NOTIMPL); } if (result) { foundIndex = c; return(Constants.S_OK); } } return(Constants.S_FALSE); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Construct a FRAMEINFO for this stack frame with the requested information. public void SetFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, out FRAMEINFO frameInfo) { frameInfo = new FRAMEINFO(); uint ip = m_threadContext.eip; DebuggedModule module = m_engine.DebuggedProcess.ResolveAddress(ip); // The debugger is asking for the formatted name of the function which is displayed in the callstack window. // There are several optional parts to this name including the module, argument types and values, and line numbers. // The optional information is requested by setting flags in the dwFieldSpec parameter. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME) != 0) { // If there is source information, construct a string that contains the module name, function name, and optionally argument names and values. if (m_hasSource) { frameInfo.m_bstrFuncName = ""; if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE) != 0) { frameInfo.m_bstrFuncName = System.IO.Path.GetFileName(module.Name) + "!"; } frameInfo.m_bstrFuncName += m_functionName; if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS) != 0 && m_numParameters > 0) { frameInfo.m_bstrFuncName += "("; for (int i = 0; i < m_parameters.Length; i++) { if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES) != 0) { frameInfo.m_bstrFuncName += m_parameters[i].m_typeName + " "; } if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES) != 0) { frameInfo.m_bstrFuncName += m_parameters[i].m_name; } if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES) != 0) { frameInfo.m_bstrFuncName += "=" + m_parameters[i].m_value; } if (i < m_parameters.Length - 1) { frameInfo.m_bstrFuncName += ", "; } } frameInfo.m_bstrFuncName += ")"; } if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_LINES) != 0) { frameInfo.m_bstrFuncName += " Line:" + m_lineNum.ToString(); } } else { // No source information, so only return the module name and the instruction pointer. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE) != 0) { frameInfo.m_bstrFuncName = EngineUtils.GetAddressDescription(module, ip); } else { frameInfo.m_bstrFuncName = EngineUtils.GetAddressDescription(null, ip); } } frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME; } // The debugger is requesting the name of the module for this stack frame. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_MODULE) != 0 && module != null) { frameInfo.m_bstrModule = module.Name; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_MODULE; } // The debugger is requesting the range of memory addresses for this frame. // For the sample engine, this is the contents of the frame pointer. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_STACKRANGE) != 0) { frameInfo.m_addrMin = m_threadContext.ebp; frameInfo.m_addrMax = m_threadContext.ebp; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_STACKRANGE; } // The debugger is requesting the IDebugStackFrame2 value for this frame info. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FRAME) != 0) { frameInfo.m_pFrame = this; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_FRAME; } // Does this stack frame of symbols loaded? if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_DEBUGINFO) != 0) { frameInfo.m_fHasDebugInfo = m_hasSource ? 1 : 0; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_DEBUGINFO; } // Is this frame stale? if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_STALECODE) != 0) { frameInfo.m_fStaleCode = 0; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_STALECODE; } // The debugger would like a pointer to the IDebugModule2 that contains this stack frame. if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP) != 0) { if (module != null) { AD7Module ad7Module = (AD7Module)module.Client; Debug.Assert(ad7Module != null); frameInfo.m_pModule = ad7Module; frameInfo.m_dwValidFields |= enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP; } } }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { IDebugDocumentPosition2 docPosition = (IDebugDocumentPosition2)(Marshal.GetObjectForIUnknown(m_bpRequestInfo.bpLocation.unionmember2)); // Get the name of the document that the breakpoint was put in string documentName; EngineUtils.CheckOk(docPosition.GetFileName(out documentName)); // Get the location in the document that the breakpoint is in. TEXT_POSITION[] startPosition = new TEXT_POSITION[1]; TEXT_POSITION[] endPosition = new TEXT_POSITION[1]; EngineUtils.CheckOk(docPosition.GetRange(startPosition, endPosition)); // Ask the symbol engine to find all addresses in all modules with symbols that match this source and line number. uint[] addresses = m_engine.DebuggedProcess.GetAddressesForSourceLocation(null, documentName, startPosition[0].dwLine + 1, startPosition[0].dwColumn); lock (m_boundBreakpoints) { if (addresses.Length > 0) { foreach (uint addr in addresses) { AD7BreakpointResolution breakpointResolution = new AD7BreakpointResolution(m_engine, addr, GetDocumentContext(addr)); AD7BoundBreakpoint boundBreakpoint = new AD7BoundBreakpoint(m_engine, addr, this, breakpointResolution); m_boundBreakpoints.Add(boundBreakpoint); m_engine.DebuggedProcess.SetBreakpoint(addr, boundBreakpoint); } } else { // A real debug engine should send a warning breakpoint here } } return(Constants.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(Constants.S_FALSE); } } 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) { pbstrError = ""; pichError = 0; ppExpr = null; if (IsDebuggingNPL()) { VariableInformation varInfo = VariableInformation.Create(m_engine.DebuggedProcess, pszCode); if (varInfo != null) { ppExpr = new AD7Expression(varInfo); return(Constants.S_OK); } else { return(Constants.S_FALSE); } } try { if (m_parameters != null) { foreach (VariableInformation currVariable in m_parameters) { if (String.CompareOrdinal(currVariable.m_name, pszCode) == 0) { ppExpr = new AD7Expression(currVariable); return(Constants.S_OK); } } } if (m_locals != null) { foreach (VariableInformation currVariable in m_locals) { if (String.CompareOrdinal(currVariable.m_name, pszCode) == 0) { ppExpr = new AD7Expression(currVariable); return(Constants.S_OK); } } } pbstrError = "Invalid Expression"; pichError = (uint)pbstrError.Length; return(Constants.S_FALSE); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { int processId = EngineUtils.GetProcessId(rgpPrograms[0]); if (processId == 0) { return(Constants.E_NOTIMPL); // sample engine only supports system processes } EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out m_ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (m_pollThread == null) { // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.AttachToProcess(m_engineCallback, processId); })); m_pollThread.SetDebugProcess(m_debuggedProcess); } else { if (processId != m_debuggedProcess.Id) { Debug.Fail("Asked to attach to a process while we are debugging"); return(Constants.E_FAIL); } m_pollThread.SetDebugProcess(m_debuggedProcess); } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); // start polling for debug events on the poll thread m_pollThread.RunOperationAsync(new Operation(delegate { m_debuggedProcess.ResumeEventPump(); })); return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
public string GetAddressDescription(uint ip) { DebuggedModule module = m_debuggedProcess.ResolveAddress(ip); return(EngineUtils.GetAddressDescription(module, ip)); }
// 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 & enum_MODULE_INFO_FIELDS.MIF_NAME) != 0) { info.m_bstrName = System.IO.Path.GetFileName(this.DebuggedModule.Name); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_URL) != 0) { info.m_bstrUrl = this.DebuggedModule.Name; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URL; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS) != 0) { info.m_addrLoadAddress = (ulong)this.DebuggedModule.BaseAddress; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS) != 0) { // 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 & enum_MODULE_INFO_FIELDS.MIF_SIZE) != 0) { info.m_dwSize = this.DebuggedModule.Size; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_SIZE; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_LOADORDER) != 0) { info.m_dwLoadOrder = this.DebuggedModule.GetLoadOrder(); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADORDER; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION) != 0) { if (this.DebuggedModule.SymbolsLoaded) { info.m_bstrUrlSymbolLocation = this.DebuggedModule.SymbolPath; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION; } } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_FLAGS) != 0) { 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(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }