void IFunctionTracer.OnExitBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) { FunctionTraceEntryDataItem traceDataItem = bp.GetDataItem <FunctionTraceEntryDataItem>(); if (OnFunctionExited != null) { DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance); StackFrameAnalyzer exitAnalyzer = null; if (traceDataItem != null) { DkmSystemInformationFlags systemInformationFlags = frame.ModuleInstance.Process.SystemInformation.Flags; bool isTarget64Bit = systemInformationFlags.HasFlag(DkmSystemInformationFlags.Is64Bit); int pointerSize = (isTarget64Bit) ? 8 : 4; exitAnalyzer = new CachedFrameAnalyzer( frameAnalyzer.Parameters, traceDataItem.EntryArgumentValues, pointerSize); } OnFunctionExited(frame, exitAnalyzer); } // Since this was a one-shot breakpoint, it is unconditionally closed. bp.Close(); }
void IDkmRuntimeMonitorBreakpointHandler.EnableRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var bp = runtimeBreakpoint as DkmRuntimeInstructionBreakpoint; if (bp == null) { Debug.Fail("Non-Python breakpoint passed to EnableRuntimeBreakpoint."); throw new NotImplementedException(); } var instrAddr = bp.InstructionAddress as DkmCustomInstructionAddress; if (instrAddr == null || instrAddr.RuntimeInstance.Id.RuntimeType != Guids.PythonRuntimeTypeGuid) { Debug.Fail("Non-Python breakpoint passed to EnableRuntimeBreakpoint."); throw new NotImplementedException(); } var traceManager = bp.Process.GetDataItem <TraceManager>(); if (traceManager == null) { Debug.Fail("EnableRuntimeBreakpoint called before TraceMananger is initialized."); throw new InvalidOperationException(); } var loc = new SourceLocation(instrAddr.AdditionalData); bp.SetDataItem(DkmDataCreationDisposition.CreateNew, loc); traceManager.AddBreakpoint(bp); }
void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint runtimeBreakpoint, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { if (runtimeBreakpoint.SourceId == Guids.LocalComponentGuid) { ulong retAddr, frameBase, vframe; thread.GetCurrentFrameInfo(out retAddr, out frameBase, out vframe); new LocalComponent.HandleBreakpointRequest { BreakpointId = runtimeBreakpoint.UniqueId, ThreadId = thread.UniqueId, FrameBase = frameBase, VFrame = vframe, ReturnAddress = retAddr }.SendHigher(thread.Process); } else if (runtimeBreakpoint.SourceId == Guids.PythonTraceManagerSourceGuid || runtimeBreakpoint.SourceId == Guids.PythonStepTargetSourceGuid) { var traceManager = runtimeBreakpoint.Process.GetDataItem <TraceManager>(); if (traceManager != null) { traceManager.OnNativeBreakpointHit(runtimeBreakpoint, thread); } } else { Debug.Fail("RemoteComponent received a notification for a breakpoint that it does not know how to handle."); throw new ArgumentException(); } }
void IFunctionTracer.OnEntryBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) { // The function was just entered. Install the exit breakpoint on the calling thread at the // return address, and notify any listeners. DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance); bool suppressExitBreakpoint = false; if (OnFunctionEntered != null) { OnFunctionEntered(frame, frameAnalyzer, out suppressExitBreakpoint); } if (!suppressExitBreakpoint) { ulong ret = frame.VscxGetReturnAddress(); DkmInstructionAddress retAddr = thread.Process.CreateNativeInstructionAddress(ret); DkmRuntimeInstructionBreakpoint exitBp = DkmRuntimeInstructionBreakpoint.Create( Guids.Source.FunctionTraceExit, thread, retAddr, false, null); // Capture the value of every argument now, since when the exit breakpoint gets hit, the // target function will have already returned and its frame will be cleaned up. exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways, new FunctionTraceEntryDataItem { EntryArgumentValues = frameAnalyzer.GetAllArgumentValues(frame) }); exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways, new FunctionTraceDataItem { Tracer = this }); exitBp.Enable(); } }
void IDkmRuntimeMonitorBreakpointHandler.DisableRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var breakpointData = runtimeBreakpoint.GetDataItem <NullcBreakpointDataItem>(); if (breakpointData != null) { var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(runtimeBreakpoint.Process); var address = breakpointData.instructionAddress.CPUInstructionPart.InstructionPointer; runtimeBreakpoint.Process.InvisibleWriteMemory(breakpointData.instructionAddress.CPUInstructionPart.InstructionPointer, breakpointData.prevValue); // Skip internal breakpoints used in stepper if (runtimeBreakpoint.SourceId != DebugHelpers.NullcStepperBreakpointSourceId) { if (processData.activeBreakpointLocations.Contains(address)) { processData.activeBreakpointLocations.Remove(address); } // If we were planning to restore the breakpoint, forget about it if (processData.lastHitBreakpointLocation == address) { processData.lastHitBreakpointLocation = 0; } } } }
void IDkmRuntimeMonitorBreakpointHandler.EnableRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var process = runtimeBreakpoint.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process); var runtimeInstructionBreakpoint = runtimeBreakpoint as DkmRuntimeInstructionBreakpoint; if (runtimeInstructionBreakpoint != null) { var customInstructionAddress = runtimeInstructionBreakpoint.InstructionAddress as DkmCustomInstructionAddress; if (customInstructionAddress != null) { LuaAddressEntityData entityData = new LuaAddressEntityData(); entityData.ReadFrom(customInstructionAddress.EntityId.ToArray()); var breakpoint = new LuaBreakpoint { source = entityData.source, line = entityData.line, functionAddress = entityData.functionAddress, runtimeBreakpoint = runtimeBreakpoint }; processData.activeBreakpoints.Add(breakpoint); UpdateBreakpoints(process, processData); } } }
public TraceManager(DkmProcess process) { _process = process; _pyrtInfo = process.GetPythonRuntimeInfo(); _breakpointData = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <ArrayProxy <CliStructProxy <BreakpointData> > >("breakpointData"); _currentBreakpointData = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <ByteProxy>("currentBreakpointData"); _breakpointDataInUseByTraceFunc = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <ByteProxy>("breakpointDataInUseByTraceFunc"); _currentSourceLocation = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <CliStructProxy <CurrentSourceLocation> >("currentSourceLocation"); _stepKind = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <Int32Proxy>("stepKind"); _stepThreadId = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <UInt64Proxy>("stepThreadId"); _steppingStackDepth = _pyrtInfo.DLLs.DebuggerHelper.GetExportedStaticVariable <Int32Proxy>("steppingStackDepth"); var onBreakpointHit = _pyrtInfo.DLLs.DebuggerHelper.FindExportName("OnBreakpointHit", true); _onBreakpointHitBP = DkmRuntimeInstructionBreakpoint.Create(Guids.PythonTraceManagerSourceGuid, null, onBreakpointHit, false, null); _onBreakpointHitBP.Enable(); var onStepComplete = _pyrtInfo.DLLs.DebuggerHelper.FindExportName("OnStepComplete", true); _onStepCompleteBP = DkmRuntimeInstructionBreakpoint.Create(Guids.PythonTraceManagerSourceGuid, null, onStepComplete, false, null); _onStepCompleteBP.Enable(); var onStepFallThrough = _pyrtInfo.DLLs.DebuggerHelper.FindExportName("OnStepFallThrough", true); _onStepFallThroughBP = DkmRuntimeInstructionBreakpoint.Create(Guids.PythonTraceManagerSourceGuid, null, onStepFallThrough, false, null); _onStepFallThroughBP.Enable(); WriteBreakpoints(); }
void IFunctionTracer.OnEntryBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) { // The function was just entered. Install the exit breakpoint on the calling thread at the // return address, and notify any listeners. DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance); bool suppressExitBreakpoint = false; if (OnFunctionEntered != null) OnFunctionEntered(frame, frameAnalyzer, out suppressExitBreakpoint); if (!suppressExitBreakpoint) { ulong ret = frame.VscxGetReturnAddress(); DkmInstructionAddress retAddr = thread.Process.CreateNativeInstructionAddress(ret); DkmRuntimeInstructionBreakpoint exitBp = DkmRuntimeInstructionBreakpoint.Create( Guids.Source.FunctionTraceExit, thread, retAddr, false, null); // Capture the value of every argument now, since when the exit breakpoint gets hit, the // target function will have already returned and its frame will be cleaned up. exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways, new FunctionTraceEntryDataItem { EntryArgumentValues = frameAnalyzer.GetAllArgumentValues(frame) }); exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways, new FunctionTraceDataItem { Tracer = this }); exitBp.Enable(); } }
void IDkmRuntimeMonitorBreakpointHandler.TestRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var traceManager = runtimeBreakpoint.Process.GetDataItem <TraceManager>(); if (traceManager == null) { Debug.Fail("TestRuntimeBreakpoint called before TraceMananger is initialized."); throw new InvalidOperationException(); } }
public void AddBreakpoint(DkmRuntimeBreakpoint bp) { var loc = bp.GetDataItem <SourceLocation>(); if (!_breakpoints.TryGetValue(loc, out List <DkmRuntimeBreakpoint> bpsAtLoc)) { _breakpoints[loc] = bpsAtLoc = new List <DkmRuntimeBreakpoint>(); } bpsAtLoc.Add(bp); WriteBreakpoints(); }
private static void InjectHelperDll(DkmProcess process) { var injectionData = process.GetDataItem <HelperDllInjectionDataHolder>(); if (injectionData != null) { // Injection is already in progress. return; } injectionData = new HelperDllInjectionDataHolder(); process.SetDataItem(DkmDataCreationDisposition.CreateNew, injectionData); var pyrtInfo = process.GetPythonRuntimeInfo(); // Loading the helper is done via CreateRemoteThread(LoadLibrary), which is inherently asynchronous. // On the other hand, we will not handle breakpoints until it is loaded - they won't even be bound. // If any Python code is running in the meantime, this may cause us to skip breakpoints, which is // very surprising in the run (F5) scenario, as the user expects all preset breakpoints to be hit. // To fix that, we need block the Python interpreter loop until the helper is fully loaded. // // Pausing all threads is not a good way to do this, because one of the threads may be holding the // loader lock, which will prevent the helper from loading and result in a deadlock. So instead, // block at a known location at the beginning of PyInitialize_Ex, and only freeze the thread that // calls it - this is sufficient to prevent execution of Python code in run scenario before helper // is loaded. // // For attach-to-running-process scenario, we do nothing because the attach itself is inherently // asynchronous, and so there's no user expectation that breakpoints light up instantly. // If Python is already initialized, this is attach-to-running-process - don't block. var initialized = pyrtInfo.DLLs.Python.GetStaticVariable <Int32Proxy>( "initialized", GetPyInitializeObjectFile(pyrtInfo.LanguageVersion) ); if (initialized.Read() == 0) { // When Py_InitializeEx is hit, suspend the thread. DkmRuntimeBreakpoint makePendingCallsBP = null; makePendingCallsBP = CreateRuntimeDllExportedFunctionBreakpoint(pyrtInfo.DLLs.Python, "Py_InitializeEx", (thread, frameBase, vFrame) => { makePendingCallsBP.Close(); if (process.GetPythonRuntimeInstance() == null) { thread.Suspend(true); injectionData.SuspendedThread = thread; } }); makePendingCallsBP.Enable(); } // Inject the helper DLL; OnHelperDllInitialized will resume the thread once the DLL is loaded and initialized. DebugAttach.AttachDkm(process.LivePart.Id); }
public static void VscxOnRuntimeBreakpointReceived( this DkmProcess process, DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { RuntimeBreakpointHandler handler = process.GetDataItem<RuntimeBreakpointHandler>(); if (handler == null) return; handler.OnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor); }
public void OnRuntimeBreakpointReceived( DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { FunctionTraceDataItem traceDataItem = bp.GetDataItem<FunctionTraceDataItem>(); if (traceDataItem != null && traceDataItem.Tracer != null) { if (bp.SourceId == Guids.Source.FunctionTraceEnter) traceDataItem.Tracer.OnEntryBreakpointHit(bp, thread, hasException); else if (bp.SourceId == Guids.Source.FunctionTraceExit) traceDataItem.Tracer.OnExitBreakpointHit(bp, thread, hasException); } }
void IDkmRuntimeMonitorBreakpointHandler.EnableRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var instructionBreakpoint = (runtimeBreakpoint as DkmRuntimeInstructionBreakpoint); if (instructionBreakpoint != null) { var nativeInstructionAddress = instructionBreakpoint.InstructionAddress as DkmNativeInstructionAddress; if (nativeInstructionAddress == null) { Debug.WriteLine("Missing breakpoint address"); return; } ulong address = instructionBreakpoint.InstructionAddress.CPUInstructionPart.InstructionPointer; byte[] prevValue = new byte[1]; if (runtimeBreakpoint.Process.ReadMemory(address, DkmReadMemoryFlags.ExecutableOnly, prevValue) == 0) { Debug.WriteLine("Failed to read current instruction"); return; } var breakpointData = DebugHelpers.GetOrCreateDataItem <NullcBreakpointDataItem>(runtimeBreakpoint); breakpointData.instructionAddress = nativeInstructionAddress; breakpointData.prevValue = prevValue; // Write an 'int 3' instruction runtimeBreakpoint.Process.InvisibleWriteMemory(address, new byte[1] { 0xcc }); // Remember locations of the active user breakpoint instructions, skip internal breakpoints used in stepper if (runtimeBreakpoint.SourceId != DebugHelpers.NullcStepperBreakpointSourceId) { var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(instructionBreakpoint.Process); if (!processData.activeBreakpointLocations.Contains(address)) { processData.activeBreakpointLocations.Add(address); } } return; } Debug.WriteLine("Failed to enable the breakpoint"); }
public static void VscxOnRuntimeBreakpointReceived( this DkmProcess process, DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { RuntimeBreakpointHandler handler = process.GetDataItem <RuntimeBreakpointHandler>(); if (handler == null) { return; } handler.OnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor); }
public void RemoveBreakpoint(DkmRuntimeBreakpoint bp) { var loc = bp.GetDataItem <SourceLocation>(); if (!_breakpoints.TryGetValue(loc, out List <DkmRuntimeBreakpoint> bpsAtLoc)) { return; } if (!bpsAtLoc.Remove(bp)) { return; } if (bpsAtLoc.Count == 0) { _breakpoints.Remove(loc); } WriteBreakpoints(); }
public void OnRuntimeBreakpointReceived( DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { FunctionTraceDataItem traceDataItem = bp.GetDataItem <FunctionTraceDataItem>(); if (traceDataItem != null && traceDataItem.Tracer != null) { if (bp.SourceId == Guids.Source.FunctionTraceEnter) { traceDataItem.Tracer.OnEntryBreakpointHit(bp, thread, hasException); } else if (bp.SourceId == Guids.Source.FunctionTraceExit) { traceDataItem.Tracer.OnExitBreakpointHit(bp, thread, hasException); } } }
void IDkmRuntimeMonitorBreakpointHandler.TestRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var runtimeInstructionBreakpoint = runtimeBreakpoint as DkmRuntimeInstructionBreakpoint; if (runtimeInstructionBreakpoint != null) { var customInstructionAddress = runtimeInstructionBreakpoint.InstructionAddress as DkmCustomInstructionAddress; if (customInstructionAddress != null) { LuaBreakpointAdditionalData additionalData = new LuaBreakpointAdditionalData(); additionalData.ReadFrom(customInstructionAddress.AdditionalData.ToArray()); if (additionalData.line == 0) { throw new Exception("Invalid instruction breakpoint location"); } } } }
void IFunctionTracer.OnExitBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) { FunctionTraceEntryDataItem traceDataItem = bp.GetDataItem<FunctionTraceEntryDataItem>(); if (OnFunctionExited != null) { DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance); StackFrameAnalyzer exitAnalyzer = null; if (traceDataItem != null) { DkmSystemInformationFlags systemInformationFlags = frame.ModuleInstance.Process.SystemInformation.Flags; bool isTarget64Bit = systemInformationFlags.HasFlag(DkmSystemInformationFlags.Is64Bit); int pointerSize = (isTarget64Bit) ? 8 : 4; exitAnalyzer = new CachedFrameAnalyzer( frameAnalyzer.Parameters, traceDataItem.EntryArgumentValues, pointerSize); } OnFunctionExited(frame, exitAnalyzer); } // Since this was a one-shot breakpoint, it is unconditionally closed. bp.Close(); }
public void OnNativeBreakpointHit(DkmRuntimeBreakpoint nativeBP, DkmThread thread) { if (nativeBP == _onBreakpointHitBP) { OnBreakpointHit(thread); } else if (nativeBP == _onStepCompleteBP) { OnStepComplete(thread); } else if (nativeBP == _onStepFallThroughBP) { OnStepFallThrough(thread); } else if (nativeBP.SourceId == Guids.PythonStepTargetSourceGuid) { OnStepTargetBreakpoint(thread); } else { Debug.Fail("BreakpointManager notified about a native breakpoint that it didn't create."); } }
public override void Handle(DkmProcess process) { if (process.LivePart == null) { // When debugging dumps, there's no stepping or live expression evaluation. Hence, we don't // need the helper DLL nor _ctypes.pyd for anything, and even if they are loaded in the dump, // we don't care about them at all. return; } var pyrtInfo = process.GetPythonRuntimeInfo(); var moduleInstance = process.GetNativeRuntimeInstance().GetNativeModuleInstances().Single(mi => mi.UniqueId == ModuleInstanceId); if (pyrtInfo.DLLs.CTypes == null && PythonDLLs.CTypesNames.Contains(moduleInstance.Name)) { moduleInstance.TryLoadSymbols(); if (moduleInstance.HasSymbols()) { pyrtInfo.DLLs.CTypes = moduleInstance; var traceHelper = process.GetDataItem <TraceManagerLocalHelper>(); if (traceHelper != null) { traceHelper.OnCTypesLoaded(moduleInstance); } } } if (process.GetPythonRuntimeInstance() != null) { return; } if (PythonDLLs.GetPythonLanguageVersion(moduleInstance) != PythonLanguageVersion.None) { pyrtInfo.DLLs.Python = moduleInstance; for (int i = 0; i < 2; ++i) { if (moduleInstance.HasSymbols()) { if (IsModuleCompiledWithPGO(moduleInstance)) { pyrtInfo.DLLs.Python = null; var pgoWarnMsg = DkmCustomMessage.Create(process.Connection, process, Guid.Empty, (int)VsPackageMessage.WarnAboutPGO, moduleInstance.Name, null); pgoWarnMsg.SendToVsService(Guids.CustomDebuggerEventHandlerGuid, IsBlocking: true); return; } if (process.LivePart == null) { // If debugging crash dumps, runtime can be created as soon as Python symbols are resolved. CreatePythonRuntimeInstance(process); } else { // If not, we need to check for debugger helper DLL as well, and inject it if it isn't there yet. if (pyrtInfo.DLLs.DebuggerHelper != null) { CreatePythonRuntimeInstance(process); } else { InjectHelperDll(process); } } return; } moduleInstance.TryLoadSymbols(); } var symWarnMsg = DkmCustomMessage.Create(process.Connection, process, Guid.Empty, (int)VsPackageMessage.WarnAboutPythonSymbols, moduleInstance.Name, null); symWarnMsg.SendToVsService(Guids.CustomDebuggerEventHandlerGuid, IsBlocking: true); } else if (PythonDLLs.DebuggerHelperNames.Contains(moduleInstance.Name)) { moduleInstance.TryLoadSymbols(); // When the module is reported is loaded, it is not necessarily fully initialized yet - it is possible to get into a state // where its import table is not processed yet. If we register TraceFunc and it gets called by Python when in that state, // we'll get a crash as soon as any imported WinAPI function is called. So check whether DllMain has already run - if it // is, we're good to go, and if not, set a breakpoint on a hook that will be called once it is run, and defer runtime // creation until that breakpoint is hit. bool isInitialized = moduleInstance.GetExportedStaticVariable <ByteProxy>("isInitialized").Read() != 0; if (isInitialized) { OnHelperDllInitialized(moduleInstance); } else { DkmRuntimeBreakpoint initBP = null; initBP = CreateRuntimeDllExportedFunctionBreakpoint(moduleInstance, "OnInitialized", (thread, frameBase, vFrame) => { initBP.Close(); OnHelperDllInitialized(moduleInstance); }); initBP.Enable(); } } }
void IDkmRuntimeMonitorBreakpointHandler.TestRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { // Don't undestand what is expected here, there is no return value and no completion handler }
void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint runtimeBreakpoint, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { var process = thread.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process); if (runtimeBreakpoint.SourceId == Guids.luaSupportBreakpointGuid) { if (processData.locations != null) { if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperBreakpointHit) { // Breakpoint can get hit again after expression evaluation 'slips' the thread if (processData.pauseBreakpoints) { return; } eventDescriptor.Suppress(); var breakpointPos = DebugHelpers.ReadUintVariable(process, processData.locations.helperBreakHitIdAddress); if (!breakpointPos.HasValue) { return; } if (breakpointPos.Value < processData.activeBreakpoints.Count) { try { var breakpoint = processData.activeBreakpoints[(int)breakpointPos.Value]; if (breakpoint.runtimeBreakpoint != null) { breakpoint.runtimeBreakpoint.OnHit(thread, false); } } catch (System.ObjectDisposedException) { // Breakpoint was implicitly closed processData.activeBreakpoints.RemoveAt((int)breakpointPos.Value); } catch (DkmException) { // In case another component evaluates a function } } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepComplete) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepInto) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepOut) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } } thread.GetCurrentFrameInfo(out ulong retAddr, out ulong frameBase, out ulong vframe); var data = new SupportBreakpointHitMessage { breakpointId = runtimeBreakpoint.UniqueId, threadId = thread.UniqueId, retAddr = retAddr, frameBase = frameBase, vframe = vframe }; var message = DkmCustomMessage.Create(process.Connection, process, MessageToLocal.guid, MessageToLocal.luaSupportBreakpointHit, data.Encode(), null); var response = message.SendHigher(); if (response?.MessageCode == MessageToRemote.throwException) { if (runtimeBreakpoint is DkmRuntimeInstructionBreakpoint runtimeInstructionBreakpoint) { var exceptionInformation = DkmCustomExceptionInformation.Create(processData.runtimeInstance, Guids.luaExceptionGuid, thread, runtimeInstructionBreakpoint.InstructionAddress, "LuaError", 0, DkmExceptionProcessingStage.Thrown | DkmExceptionProcessingStage.UserVisible | DkmExceptionProcessingStage.Unhandled, null, new ReadOnlyCollection <byte>(response.Parameter1 as byte[])); exceptionInformation.OnDebugMonitorException(); } } } }
void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { DkmProcess process = bp.Process; process.VscxOnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor); }