/// <summary> /// See <see cref="StepIn"/>. /// If there's a call as next instruction, it'll be skipped. /// </summary> public void StepOver(DebugThread th) { var code = APIIntermediate.ReadArray <byte>(th.OwnerProcess.Handle, th.CurrentInstruction, DisAsm86.MaximumInstructionLength); int instructionLength = 0; var instrType = DisAsm86.GetInstructionType(code, false, out instructionLength); /* * If there's a call, set a breakpoint right after the call to skip the called subroutine */ if (instrType == InstructionType.Call) { var bpAddr = IntPtr.Add(th.CurrentInstruction, instructionLength); var tempBreakPoint = Breakpoints.ByAddress(bpAddr); bool keepBpAfterStepComplete = false; if (keepBpAfterStepComplete = tempBreakPoint == null) { tempBreakPoint = Breakpoints.CreateBreakpoint(bpAddr); } th.ContinueDebugging(); Debuggee.WaitForDebugEvent(); if (!keepBpAfterStepComplete) { Breakpoints.Remove(tempBreakPoint); } } else { StepIn(th); } }
internal DebugFrame CreateFrameForGenerator(FunctionInfo func) { DebugThread thread = GetCurrentThread(); DebugFrame frame = new DebugFrame(thread, func); return(frame); }
/// <summary> /// Executes the next single code instruction. /// Returns false if the single step could be executed but wasn't completed due to a breakpoint or an other exception/debug event. /// </summary> bool StepToNextInstruction(DebugThread th) { if (!Debuggee.IsAlive) { return(false); } if (lastUnhandledBreakpoint != null) { SkipAndRestoreLastBreakpoint(false); } bool lastStepState = th.Context.TrapFlagSet; if (!lastStepState) { th.Context.TrapFlagSet = true; } th.ContinueDebugging(); expectsSingleStep = true; Debuggee.WaitForDebugEvent(); //TODO: What if there's a non-ss exception? // Answer: return false if (!lastStepState) { th.Context.TrapFlagSet = false; } return(!expectsSingleStep); }
void SkipAndRestoreLastBreakpoint(bool resetStepFlag = true) { if (lastUnhandledBreakpoint == null) { throw new Exception("lastUnhandledBreakpoint must not be null"); } if (!lastUnhandledBreakpoint.temporarilyDisabled) { throw new Exception("breakpoint must be marked as temporarily disabled!"); } if (lastUnhandledBreakpointThread == null) { throw new Exception("lastUnhandledBreakpointThread must not be null"); } if (postBreakpointResetStepCompleted) { throw new Exception("why is postBreakpointResetStepCompleted set to true?"); } // Immediately after the breakpoint was hit, the bp code was taken out of the code // and the instruction pointer was decreased, so the original instruction will be executed then afterwards. // 1) Enable single-stepping (SS flag) // 2) Step one forward (execute original instruction) // 3) Re-enable breakpoint // 4) (optionally) disable single-stepping again // 1) lastUnhandledBreakpointThread.Context.TrapFlagSet = true; // 2) lastUnhandledBreakpointThread.ContinueDebugging(); postBreakpointResetStepCompleted = false; Debuggee.WaitForDebugEvent(); if (!postBreakpointResetStepCompleted) { return; } // 3) lastUnhandledBreakpoint.Enable(); // 4) if (resetStepFlag) { lastUnhandledBreakpointThread.Context.TrapFlagSet = false; } lastUnhandledBreakpointThread = null; lastUnhandledBreakpoint = null; postBreakpointResetStepCompleted = false; }
internal void DispatchDebugEvent(DebugThread thread, int debugMarker, TraceEventKind eventKind, object payload) { DebugFrame leafFrame = null; bool hasFrameObject = false; FunctionInfo functionInfo; int stackDepth; if (eventKind != TraceEventKind.ThreadExit) { functionInfo = thread.GetLeafFrameFunctionInfo(out stackDepth); } else { stackDepth = Int32.MaxValue; functionInfo = null; } if (eventKind == TraceEventKind.Exception || eventKind == TraceEventKind.ExceptionUnwind) { thread.ThrownException = (Exception)payload; } thread.IsInTraceback = true; try { // Fire the event IDebugCallback traceHook = _traceHook; if (traceHook != null) { traceHook.OnDebugEvent(eventKind, thread, functionInfo, debugMarker, stackDepth, payload); } // Check if the frame object is created after the traceback. If it's created - then we need // to check if we need to remap hasFrameObject = thread.TryGetLeafFrame(ref leafFrame); if (hasFrameObject) { Debug.Assert(!leafFrame.InGeneratorLoop || (leafFrame.InGeneratorLoop && !leafFrame.ForceSwitchToGeneratorLoop)); if (leafFrame.ForceSwitchToGeneratorLoop && !leafFrame.InGeneratorLoop) { throw new ForceToGeneratorLoopException(); } } } finally { if (hasFrameObject) { leafFrame.IsInTraceback = false; } thread.IsInTraceback = false; thread.ThrownException = null; } }
void DoSingleStep(DebugThread th) { if (SourceBoundStepping) { StepToNextSrcLine(th); } else { StepToNextInstruction(th); } }
/// <summary> /// Steps until there's an associated code location for the currently executed instruction /// or if there aren't any debug information. /// </summary> void StepToNextSrcLine(DebugThread th) { string file = null; ushort line = 0; var mainMod = Debuggee.MainProcess.MainModule; var modMetaInfo = mainMod.ModuleMetaInfo; do { StepToNextInstruction(th); }while(Debuggee.IsAlive && mainMod.ContainsSymbolData && !modMetaInfo.TryDetermineCodeLocation((uint)Debuggee.CurrentThread.CurrentInstruction.ToInt32(), out file, out line)); }
internal DebugThread GetCurrentThread() { DebugThread thread = _cachedThread; if (thread == null || !thread.IsCurrentThread) { thread = _thread.Value; if (thread == null) { thread = _threadFactory.CreateDebugThread(this); _thread.Value = thread; } Interlocked.Exchange(ref _cachedThread, thread); } return(thread); }
/// <summary> /// Executes until the currently executed method's point of return has been reached. /// </summary> public void StepOut(DebugThread th) { var returnPtr = APIIntermediate.Read <IntPtr>(th.OwnerProcess.Handle, new IntPtr(th.Context.lastReadCtxt.ebp + 4)); var tempBreakPoint = Breakpoints.ByAddress(returnPtr); bool keepBpAfterStepComplete = false; if (keepBpAfterStepComplete = tempBreakPoint == null) { tempBreakPoint = Breakpoints.CreateBreakpoint(returnPtr); } th.ContinueDebugging(); Debuggee.WaitForDebugEvent(); if (!keepBpAfterStepComplete) { Breakpoints.Remove(tempBreakPoint); } }
void HighlightCurrentInstruction(DebugThread th) { if (currentFrameMarker != null) { currentFrameMarker.Delete(); } ushort line = 0; string file = null; if (th.OwnerProcess.MainModule.ContainsSymbolData && th.OwnerProcess.MainModule.ModuleMetaInfo.TryDetermineCodeLocation((uint)th.CurrentInstruction.ToInt32(), out file, out line)) { LoadSourceFileIntoEditor(file); currentFrameMarker = new CurrentFrameMarker(MarkerStrategy, editor.Document, line); MarkerStrategy.Add(currentFrameMarker); currentFrameMarker.Redraw(); } }
public override void OnBreakpoint(DebugThread thread, DDebugger.Breakpoints.Breakpoint breakpoint) { form.HighlightCurrentInstruction(thread); }
public override void OnDebugOutput(DebugThread thread, string outputString) { base.OnDebugOutput(thread, outputString); }
public override void OnException(DebugThread thread, DebugException exception) { form.HighlightCurrentInstruction(thread); }
internal ThreadWrapper(DebugThread thread) { this.thread = thread; }
public override void OnStepComplete(DebugThread thread) { form.HighlightCurrentInstruction(thread); }
public override void OnThreadExit(DebugThread thread, uint exitCode) { base.OnThreadExit(thread, exitCode); }
/// <summary> /// Executes the next instruction. /// </summary> public void StepIn(DebugThread th) { DoSingleStep(th); }
public override void OnCreateThread(DebugThread newThread) { base.OnCreateThread(newThread); }