// 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 { if (_functionName != null) { name = _functionName; } else { name = EngineUtils.GetAddressDescription(Engine.DebuggedProcess, ThreadContext.pc.Value); } return(Constants.S_OK); } catch (MIException 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; if (_codeContext == null) { return(Constants.E_FAIL); } try { AD7MemoryAddress[] codeContexts = new AD7MemoryAddress[1]; codeContexts[0] = _codeContext; ppEnumCodeCxts = new AD7CodeContextEnum(codeContexts); return(Constants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// This function is used to terminate a process that the SampleEngine launched // The debugger will call IDebugEngineLaunch2::CanTerminateProcess before calling this method. int IDebugEngineLaunch2.TerminateProcess(IDebugProcess2 process) { Debug.Assert(_pollThread != null); Debug.Assert(_engineCallback != null); Debug.Assert(_debuggedProcess != null); try { AD_PROCESS_ID processId = EngineUtils.GetProcessId(process); if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { return(Constants.S_FALSE); } _pollThread.RunOperation(() => _debuggedProcess.CmdTerminate()); _debuggedProcess.Terminate(); return(Constants.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 { // we have no "parser" as such, so we accept anything that isn't blank and let the Evaluate method figure out the errors ppExpr = new AD7Expression(Engine, Engine.DebuggedProcess.Natvis.GetVariable(pszCode, this)); return(Constants.S_OK); } catch (MIException 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()) { 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(Constants.S_FALSE); } else { 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... _engine.Callback.OnBreakpointError(_BPError); return(Constants.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 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 | enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE)) != 0) { string addr = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch); if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0) { pinfo[0].bstrAddress = addr; pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS; } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0) { pinfo[0].bstrAddressAbsolute = addr; pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE; } } // Fields not supported by the sample if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0) { DebuggedModule module = _engine.DebuggedProcess.ResolveAddress(_address); if (module != null) { pinfo[0].bstrModuleUrl = module.Name; pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL; } } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION) != 0) { if (string.IsNullOrEmpty(_functionName)) { _functionName = Engine.GetAddressDescription(_address); } if (!(string.IsNullOrEmpty(_functionName))) { pinfo[0].bstrFunction = _functionName; pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION; } } return(Constants.S_OK); } catch (MIException 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[] 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(Constants.S_OK); } catch (MIException 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(_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); // Complete the win32 attach on the poll thread _pollThread.RunOperation(new Operation(delegate { throw new NotImplementedException(); })); _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; } else { if (!EngineUtils.ProcIdEquals(processId, _debuggedProcess.Id)) { Debug.Fail("Asked to attach to a process while we are debugging"); return(Constants.E_FAIL); } } AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); this.ProgramCreateEventSent = true; return(Constants.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 = Constants.S_OK; } else if (guidFilter == AD7Guids.guidFilterLocals) { CreateLocalProperties(dwFields, out elementsReturned, out enumObject); hr = Constants.S_OK; } else if (guidFilter == AD7Guids.guidFilterArgs) { CreateParameterProperties(dwFields, out elementsReturned, out enumObject); hr = Constants.S_OK; } else if (guidFilter == AD7Guids.guidFilterRegisters) { CreateRegisterContent(dwFields, out elementsReturned, out enumObject); hr = Constants.S_OK; } else { hr = Constants.E_NOTIMPL; } } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(hr); }
// 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]; List <ArgumentList> parameters = null; if ((dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS) != 0) { _engine.DebuggedProcess.WorkerThread.RunOperation(async() => parameters = await _engine.DebuggedProcess.GetParameterInfoOnly(this, (dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES) != 0, (dwFieldSpec & enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES) != 0, low, high)); } 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], p != null ? p.Item2 : null); } } enumObject = new AD7FrameInfoEnum(frameInfoArray); return(Constants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// 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 sample engine sends in this fashion is Program Destroy. // It responds to that event by shutting down the engine. public int ContinueFromSynchronousEvent(IDebugEvent2 eventObject) { try { if (eventObject is AD7ProgramCreateEvent) { Exception exception = null; try { _engineCallback.OnLoadComplete(); // At this point breakpoints and exception settings have been sent down, so we can resume the target _pollThread.RunOperation(() => { return(_debuggedProcess.ResumeFromLaunch()); }); } catch (Exception e) { exception = e; // Return from the catch block so that we can let the exception unwind - the stack can get kind of big } if (exception != null) { // If something goes wrong, report the error and then stop debugging. The SDM will drop errors // from ContinueFromSynchronousEvent, so we want to deal with them ourself. SendStartDebuggingError(exception); _debuggedProcess.Terminate(); } return(Constants.S_OK); } else if (eventObject is AD7ProgramDestroyEvent) { Dispose(); } else { Debug.Fail("Unknown syncronious event"); } } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(Constants.S_OK); }
// 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. public int CreatePendingBreakpoint(IDebugBreakpointRequest2 pBPRequest, out IDebugPendingBreakpoint2 ppPendingBP) { Debug.Assert(_breakpointManager != null); ppPendingBP = null; try { _breakpointManager.CreatePendingBreakpoint(pBPRequest, out ppPendingBP); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(Constants.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(Constants.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, _engineGuid))); if (_ad7ProgramId == Guid.Empty) { Debug.Fail("Unexpected problem -- IDebugEngine2.Attach wasn't called"); return(Constants.E_FAIL); } // NOTE: We wait for the program create event to be continued before we really resume the process return(Constants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { return(EngineUtils.UnexpectedException(e)); } }
// 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(Constants.S_OK); } catch (MIException e) { return(e.HResult); } 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 = _textPosition.BeginPosition.dwColumn; pBegPosition[0].dwLine = _textPosition.BeginPosition.dwLine; pEndPosition[0].dwColumn = _textPosition.EndPosition.dwColumn; pEndPosition[0].dwLine = _textPosition.EndPosition.dwLine; } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(Constants.S_OK); }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { // Make sure that HostMarshal calls happen on main thread instead of poll thread. lock (_boundBreakpoints) { if (_bp != null) // already bound { Debug.Fail("Breakpoint already bound"); return(Constants.S_FALSE); } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_CONDITION) != 0 && _bpRequestInfo.bpCondition.styleCondition == enum_BP_COND_STYLE.BP_COND_WHEN_TRUE) { _condition = _bpRequestInfo.bpCondition.bstrCondition; } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_BPLOCATION) != 0) { switch ((enum_BP_LOCATION_TYPE)_bpRequestInfo.bpLocation.bpLocationType) { case enum_BP_LOCATION_TYPE.BPLT_CODE_FUNC_OFFSET: try { IDebugFunctionPosition2 functionPosition = HostMarshal.GetDebugFunctionPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); EngineUtils.CheckOk(functionPosition.GetFunctionName(out _functionName)); } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember2); } break; case enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT: try { IDebugCodeContext2 codePosition = HostMarshal.GetDebugCodeContextForIntPtr(_bpRequestInfo.bpLocation.unionmember1); if (!(codePosition is AD7MemoryAddress)) { goto default; // context is not from this engine } _codeAddress = ((AD7MemoryAddress)codePosition).Address; } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember1); } break; case enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE: try { IDebugDocumentPosition2 docPosition = HostMarshal.GetDocumentPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); // Get the name of the document that the breakpoint was put in EngineUtils.CheckOk(docPosition.GetFileName(out _documentName)); // Get the location in the document that the breakpoint is in. EngineUtils.CheckOk(docPosition.GetRange(_startPosition, _endPosition)); } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember2); } // Get the document checksum if (_engine.DebuggedProcess.MICommandFactory.SupportsBreakpointChecksums()) { try { _checksums = GetSHA1Checksums(); } catch (Exception) { // If we fail to get a checksum there's nothing else we can do } } break; case enum_BP_LOCATION_TYPE.BPLT_DATA_STRING: string address = HostMarshal.GetDataBreakpointStringForIntPtr(_bpRequestInfo.bpLocation.unionmember3); if (address.Contains(",")) { this.AddressId = address; _address = address.Split(',')[0]; } else { this.AddressId = null; _address = address; } _size = (uint)_bpRequestInfo.bpLocation.unionmember4; if (_condition != null) { goto default; // mi has no conditions on watchpoints } break; default: this.SetError(new AD7ErrorBreakpoint(this, ResourceStrings.UnsupportedBreakpoint), true); return(Constants.S_FALSE); } } } if (!_enabled && IsHardwareBreakpoint) { return(Constants.S_OK); } return(BindWithTimeout()); } 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(Constants.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)); } }
// 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 contextCompare, IDebugMemoryContext2[] compareToItems, uint compareToLength, out uint foundIndex) { foundIndex = uint.MaxValue; try { for (uint c = 0; c < compareToLength; c++) { AD7MemoryAddress compareTo = compareToItems[c] as AD7MemoryAddress; if (compareTo == null) { continue; } if (!AD7Engine.ReferenceEquals(_engine, compareTo._engine)) { continue; } bool result; switch (contextCompare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = (_address == compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = (_address < compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = (_address > compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = (_address <= compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = (_address >= compareTo._address); break; // The debug engine doesn't understand scopes case enum_CONTEXT_COMPARE.CONTEXT_SAME_SCOPE: result = (_address == compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_FUNCTION: if (_address == compareTo._address) { result = true; break; } string funcThis = Engine.GetAddressDescription(_address); if (string.IsNullOrEmpty(funcThis)) { result = false; break; } string funcCompareTo = Engine.GetAddressDescription(compareTo._address); result = (funcThis == funcCompareTo); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_MODULE: result = (_address == compareTo._address); if (result == false) { DebuggedModule module = _engine.DebuggedProcess.ResolveAddress(_address); if (module != null) { result = module.AddressInModule(compareTo._address); } } 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 (MIException 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 & 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 read 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 = (uint)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 (this.Process.LaunchOptions is LocalLaunchOptions localLaunchOptions && string.IsNullOrWhiteSpace(localLaunchOptions.MIDebuggerServerAddress) && string.IsNullOrWhiteSpace(localLaunchOptions.DebugServer) && (dwFields & enum_MODULE_INFO_FIELDS.MIF_TIMESTAMP) != 0 && this.DebuggedModule.Name != null) { try { long ft = File.GetLastWriteTimeUtc(this.DebuggedModule.Name).ToFileTime(); uint low = (uint)(ft & 0xFFFFFFFF); uint high = (uint)((ulong)(ft >> 32)); info.m_TimeStamp = new FILETIME() { dwLowDateTime = low, dwHighDateTime = high }; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_TIMESTAMP; } catch {} } 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); } if (this.Process.Is64BitArch) { info.m_dwModuleFlags |= enum_MODULE_FLAGS.MODULE_FLAG_64BIT; } info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS; } infoArray[0] = info; return(Constants.S_OK); } catch (MIException 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 & 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 read 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 = (uint)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); } if (this.Process.Is64BitArch) { info.m_dwModuleFlags |= enum_MODULE_FLAGS.MODULE_FLAG_64BIT; } info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS; } infoArray[0] = info; return(Constants.S_OK); } catch (MIException 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()) { // Make sure that HostMarshal calls happen on main thread instead of poll thread. lock (_boundBreakpoints) { if (_bp != null) // already bound { Debug.Fail("Breakpoint already bound"); return(Constants.S_FALSE); } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_CONDITION) != 0 && _bpRequestInfo.bpCondition.styleCondition == enum_BP_COND_STYLE.BP_COND_WHEN_TRUE) { _condition = _bpRequestInfo.bpCondition.bstrCondition; } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_BPLOCATION) != 0) { switch ((enum_BP_LOCATION_TYPE)_bpRequestInfo.bpLocation.bpLocationType) { case enum_BP_LOCATION_TYPE.BPLT_CODE_FUNC_OFFSET: try { IDebugFunctionPosition2 functionPosition = HostMarshal.GetDebugFunctionPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); EngineUtils.CheckOk(functionPosition.GetFunctionName(out _functionName)); } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember2); } break; case enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT: try { IDebugCodeContext2 codePosition = HostMarshal.GetDebugCodeContextForIntPtr(_bpRequestInfo.bpLocation.unionmember1); if (!(codePosition is AD7MemoryAddress)) { goto default; // context is not from this engine } _codeAddress = ((AD7MemoryAddress)codePosition).Address; } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember1); } break; case enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE: try { IDebugDocumentPosition2 docPosition = HostMarshal.GetDocumentPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); // Get the name of the document that the breakpoint was put in EngineUtils.CheckOk(docPosition.GetFileName(out _documentName)); // Get the location in the document that the breakpoint is in. EngineUtils.CheckOk(docPosition.GetRange(_startPosition, _endPosition)); } finally { HostMarshal.Release(_bpRequestInfo.bpLocation.unionmember2); } // Get the document checksum if (_engine.DebuggedProcess.MICommandFactory.SupportsBreakpointChecksums()) { try { _checksums = GetSHA1Checksums(); } catch (Exception) { // If we fail to get a checksum there's nothing else we can do } } break; case enum_BP_LOCATION_TYPE.BPLT_DATA_STRING: _address = HostMarshal.GetDataBreakpointStringForIntPtr(_bpRequestInfo.bpLocation.unionmember3); _size = (uint)_bpRequestInfo.bpLocation.unionmember4; if (_condition != null) { goto default; // mi has no conditions on watchpoints } break; default: this.SetError(new AD7ErrorBreakpoint(this, ResourceStrings.UnsupportedBreakpoint), true); return(Constants.S_FALSE); } } } Task bindTask = null; _engine.DebuggedProcess.WorkerThread.RunOperation(() => { bindTask = _engine.DebuggedProcess.AddInternalBreakAction(this.BindAsync); }); bindTask.Wait(_engine.GetBPLongBindTimeout()); 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 this.SetError(new AD7ErrorBreakpoint(this, ResourceStrings.LongBind, enum_BP_ERROR_TYPE.BPET_SEV_LOW | enum_BP_ERROR_TYPE.BPET_TYPE_WARNING), true); return(Constants.S_FALSE); } else { 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... _engine.Callback.OnBreakpointError(_BPError); return(Constants.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)); } }