void IDkmDebugMonitorExceptionNotification.OnDebugMonitorException(DkmExceptionInformation exception, DkmWorkList workList, DkmEventDescriptorS eventDescriptor) { var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(exception.Process); if (exception.InstructionAddress == null) { return; } ulong address = exception.InstructionAddress.CPUInstructionPart.InstructionPointer; // Breakpoint if (exception.Code == 0x80000003) { // Internal stepper breakpoints are silenced but te debugger is notified to break the process if (processData.stepBreakpoint != null && processData.stepBreakpoint.InstructionAddress.CPUInstructionPart.InstructionPointer == address) { eventDescriptor.Suppress(); exception.Thread.OnEmbeddedBreakpointHit(exception.InstructionAddress, false); } if (processData.secondaryStepBreakpoint != null && processData.secondaryStepBreakpoint.InstructionAddress.CPUInstructionPart.InstructionPointer == address) { eventDescriptor.Suppress(); exception.Thread.OnEmbeddedBreakpointHit(exception.InstructionAddress, false); } // Second stage of breakpoint handling - supress exception, notify debugger to break the process and remember what breakpoint has to be resotred later if (processData.activeBreakpointLocations.Contains(address)) { eventDescriptor.Suppress(); exception.Thread.OnEmbeddedBreakpointHit(exception.InstructionAddress, false); // Schedule restore of this breakpoint when process continues processData.lastHitBreakpointLocation = address; processData.singleStepThread = exception.Thread; } } }
void IDkmExceptionTriggerHitNotification.OnExceptionTriggerHit(DkmExceptionTriggerHit hit, DkmEventDescriptorS eventDescriptor) { ThreadHelper.JoinableTaskFactory.Run(async() => { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); var exceptionInfo = hit.Exception as VisualStudio.Debugger.Native.DkmWin32ExceptionInformation; if (exceptionInfo.Code == RemoteDebugStartExceptionCode) { // Parameters expected are the flag to indicate the debugger is present and JSON to write to the target for configuration // of the debugger const int exceptionParameterCount = 3; if (exceptionInfo.ExceptionParameters.Count == exceptionParameterCount) { // If we have a port and debug id, we'll go ahead and tell the client we are present if (Instance.AttachRemoteProcessFunction != null && Instance.RemoteDebugCommandInfo != null) { if (Instance.RemoteDebugCommandInfo.Length <= (int)exceptionInfo.ExceptionParameters[2]) { // Write back that debugger is present hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[0], BitConverter.GetBytes(true)); // Write back the details of the debugger arguments hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[1], Instance.RemoteDebugCommandInfo); } } } } else if (exceptionInfo.Code == RemoteDebugAttachExceptionCode) { // Parameters expected are the flag to indicate the debugger is present and XML to write to the target for configuration // of the debugger const int exceptionAttachParameterCount = 1; if (exceptionInfo.ExceptionParameters.Count == exceptionAttachParameterCount) { // If we have a port and debug id, we'll go ahead and tell the client we are present if (Instance.AttachRemoteProcessFunction != null) { // Write back that debugger is present hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[0], BitConverter.GetBytes(true)); // Start the task to attach to the remote Python debugger session StartAttachRemoteProcess(); } } } }); eventDescriptor.Suppress(); }
void IDkmSingleStepCompleteReceived.OnSingleStepCompleteReceived(DkmSingleStepRequest singleStepRequest, DkmEventDescriptorS eventDescriptor) { var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(singleStepRequest.Thread.Process); // Last stage of breakpoint handling - restore debug break instruction now that we have moved from the breakpoint location if (processData.lastHitBreakpointLocation != 0) { // Restore breakpoint instruction singleStepRequest.Thread.Process.InvisibleWriteMemory(processData.lastHitBreakpointLocation, new byte[1] { 0xcc }); processData.lastHitBreakpointLocation = 0; eventDescriptor.Suppress(); } }
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 IDkmExceptionTriggerHitNotification.OnExceptionTriggerHit(DkmExceptionTriggerHit hit, DkmEventDescriptorS eventDescriptor) { ThreadHelper.Generic.Invoke(() => { var exceptionInfo = hit.Exception as VisualStudio.Debugger.Native.DkmWin32ExceptionInformation; if (exceptionInfo.Code == RemoteDebugStartExceptionCode) { // Parameters expected are the flag to indicate the debugger is present and JSON to write to the target for configuration // of the debugger const int exceptionParameterCount = 3; if (exceptionInfo.ExceptionParameters.Count == exceptionParameterCount) { // If we have a port and debug id, we'll go ahead and tell the client we are present if (Instance.AttachRemoteProcessFunction != null && Instance.RemoteDebugCommandInfo != null) { if (Instance.RemoteDebugCommandInfo.Length <= (int)exceptionInfo.ExceptionParameters[2]) { // Write back that debugger is present hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[0], BitConverter.GetBytes(true)); // Write back the details of the debugger arguments hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[1], Instance.RemoteDebugCommandInfo); } } } } else if (exceptionInfo.Code == RemoteDebugAttachExceptionCode) { // Parameters expected are the flag to indicate the debugger is present and XML to write to the target for configuration // of the debugger const int exceptionAttachParameterCount = 1; if (exceptionInfo.ExceptionParameters.Count == exceptionAttachParameterCount) { // If we have a port and debug id, we'll go ahead and tell the client we are present if (Instance.AttachRemoteProcessFunction != null) { // Write back that debugger is present hit.Process.WriteMemory(exceptionInfo.ExceptionParameters[0], BitConverter.GetBytes(true)); // Start the task to attach to the remote Python debugger session System.Threading.Tasks.Task.Factory.StartNew(Instance.AttachRemoteProcessFunction); } } } }); eventDescriptor.Suppress(); }