private void OnHalted(HaltArguments args) { switch(args.Reason) { case HaltReason.Breakpoint: switch(args.BreakpointType) { case BreakpointType.AccessWatchpoint: case BreakpointType.WriteWatchpoint: case BreakpointType.ReadWatchpoint: beforeCommand += cmd => { commandsCounter++; if(commandsCounter > 15) { // this is a hack! // I noticed that GDB will send `step` command after receiving // information about watchpoint being hit. // As a result cpu would execute next instruction and stop again. // To prevent this situation we wait for `step` and ignore it, but // only in small time window (15 - instructions, value choosen at random) // and only after sending watchpoint-related stop reply. this.Log(LogLevel.Error, "Expected step command after watchpoint. Further debugging might not work properly"); beforeCommand = null; commandsCounter = 0; return false; } if((cmd is SingleStepCommand)) { SendPacket(new Packet(PacketData.StopReply(TrapSignal))); beforeCommand = null; commandsCounter = 0; return true; } return false; }; goto case BreakpointType.HardwareBreakpoint; case BreakpointType.HardwareBreakpoint: case BreakpointType.MemoryBreakpoint: SendPacket(new Packet(PacketData.StopReply(args.BreakpointType.Value, args.Address))); break; } return; case HaltReason.Step: case HaltReason.Pause: SendPacket(new Packet(PacketData.StopReply(TrapSignal))); return; case HaltReason.Abort: SendPacket(new Packet(PacketData.AbortReply(AbortSignal))); return; default: throw new ArgumentException("Unexpected halt reason"); } }
private void InnerPause(HaltArguments haltArgs) { if(PauseEvent.WaitOne(0)) { // cpu is already paused return; } lock(pauseLock) { PauseEvent.Set(); TlibSetPaused(); if(Thread.CurrentThread.ManagedThreadId != cpuThread.ManagedThreadId) { this.NoisyLog("Waiting for thread to pause."); sync.Pass(); cpuThread.Join(); this.NoisyLog("Paused."); cpuThread = null; TlibClearPaused(); } else { pauseGuard.OrderPause(); } } InvokeHalted(haltArgs); }
private void InvokeHalted(HaltArguments arguments) { var halted = Halted; if(halted != null) { halted(arguments); } }
public void EnterSingleStepModeSafely(HaltArguments args) { // this method should only be called from CPU thread, // but we should check it anyway CheckCpuThreadId(); TlibSetPaused(); InvokeInCpuThreadSafely(() => { ExecutionMode = ExecutionMode.SingleStep; TlibClearPaused(); if(args != null) { InvokeHalted(args); } }); }