public void Step(DkmStepper stepper, DkmStepArbitrationReason reason) { var thread = stepper.Thread; var process = thread.Process; if (stepper.StepKind == DkmStepKind.StepIntoSpecific) { throw new NotSupportedException(); } else if (_stepper != null) { _stepper.CancelStepper(process.GetPythonRuntimeInstance()); _stepper = null; } // Check if this was a step out (or step over/in that fell through) from native to Python. // If so, we consider the step done, since we can report the correct callstack at this point. if (reason == DkmStepArbitrationReason.TransitionModule) { var beginState = stepper.GetDataItem <StepBeginState>(); if (beginState != null) { thread.GetCurrentFrameInfo(out global::System.UInt64 retAddr, out global::System.UInt64 frameBase, out global::System.UInt64 vframe); if (frameBase >= beginState.FrameBase) { stepper.OnStepComplete(thread, false); return; } } } if (stepper.StepKind == DkmStepKind.Into) { new LocalComponent.BeginStepInNotification { ThreadId = thread.UniqueId }.SendHigher(process); } _stepper = stepper; _stepKind.Write((int)stepper.StepKind + 1); _stepThreadId.Write((uint)thread.SystemPart.Id); _steppingStackDepth.Write(0); }
void IDkmRuntimeStepper.TakeStepControl(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, bool leaveGuardsInPlace, DkmStepArbitrationReason reason, DkmRuntimeInstance callingRuntimeInstance) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); ClearStepperData(process, processData); }
bool IDkmRuntimeStepper.StepControlRequested(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance callingRuntimeInstance) { return(true); }
void IDkmRuntimeStepper.OnNewControllingRuntimeInstance(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance controllingRuntimeInstance) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); ClearStepperData(process, processData); }
void IDkmRuntimeStepper.AfterSteppingArbitration(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance newControllingRuntimeInstance) { // Don't have anything to do here right now }
void IDkmRuntimeStepper.Step(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); if (stepper.StepKind == DkmStepKind.StepIntoSpecific) { throw new NotSupportedException(); } if (processData.activeStepper != null) { processData.activeStepper.CancelStepper(processData.runtimeInstance); processData.activeStepper = null; } if (stepper.StepKind == DkmStepKind.Over) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOverAddress, 1); } else if (stepper.StepKind == DkmStepKind.Into) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOverAddress, 1); DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepIntoAddress, 1); } else if (stepper.StepKind == DkmStepKind.Out) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOutAddress, 1); } processData.activeStepper = stepper; processData.hadActiveStepper = true; UpdateHooks(process, processData); }
bool IDkmRuntimeStepper.OwnsCurrentExecutionLocation(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); // Can't handle steps without an address if (stepper.StartingAddress == null) { return(false); } // Stepping can be performed if we are inside the debug helper or inside luaV_execute var instructionAddress = stepper.StartingAddress.CPUInstructionPart.InstructionPointer; if (processData.locations == null) { return(false); } if (instructionAddress >= processData.locations.helperStartAddress && instructionAddress < processData.locations.helperEndAddress) { return(true); } if (instructionAddress >= processData.locations.executionStartAddress && instructionAddress < processData.locations.executionEndAddress) { return(true); } return(false); }
void IDkmRuntimeStepper.TakeStepControl(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, bool leaveGuardsInPlace, DkmStepArbitrationReason reason, DkmRuntimeInstance callingRuntimeInstance) { var traceManager = runtimeInstance.Process.GetDataItem <TraceManager>(); if (traceManager == null) { Debug.Fail("TakeStepControl called before TraceMananger is initialized."); throw new InvalidOperationException(); } traceManager.CancelStep(stepper); }
void IDkmRuntimeStepper.Step(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var traceManager = runtimeInstance.Process.GetDataItem <TraceManager>(); if (traceManager == null) { Debug.Fail("Step called before TraceMananger is initialized."); throw new InvalidOperationException(); } traceManager.Step(stepper, reason); }
bool IDkmRuntimeStepper.OwnsCurrentExecutionLocation(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { if (!DebuggerOptions.UsePythonStepping) { return(false); } var process = runtimeInstance.Process; var pyrtInfo = process.GetPythonRuntimeInfo(); if (pyrtInfo.DLLs.Python == null) { return(false); } var thread = stepper.Thread; var ip = thread.GetCurrentRegisters(new DkmUnwoundRegister[0]).GetInstructionPointer(); return(pyrtInfo.DLLs.Python.ContainsAddress(ip) || (pyrtInfo.DLLs.DebuggerHelper != null && pyrtInfo.DLLs.DebuggerHelper.ContainsAddress(ip)) || (pyrtInfo.DLLs.CTypes != null && pyrtInfo.DLLs.CTypes.ContainsAddress(ip))); }
void IDkmRuntimeStepper.AfterSteppingArbitration(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance newControllingRuntimeInstance) { }
void IDkmRuntimeStepper.TakeStepControl(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, bool leaveGuardsInPlace, DkmStepArbitrationReason reason, DkmRuntimeInstance callingRuntimeInstance) { runtimeInstance.StopStep(stepper); }
void IDkmRuntimeStepper.OnNewControllingRuntimeInstance(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance controllingRuntimeInstance) { // Don't have anything to do here }
void IDkmRuntimeStepper.Step(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { if (!(this as IDkmRuntimeStepper).OwnsCurrentExecutionLocation(runtimeInstance, stepper, reason)) { runtimeInstance.Step(stepper, reason); return; } var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(runtimeInstance.Process); if (stepper.StepKind == DkmStepKind.StepIntoSpecific) { throw new NotSupportedException(); } if (stepper.StepKind == DkmStepKind.Over || stepper.StepKind == DkmStepKind.Into) { ClearStepBreakpoints(processData); int nullcInstruction = processData.bytecode.ConvertNativeAddressToInstruction(stepper.StartingAddress.CPUInstructionPart.InstructionPointer); int line = processData.bytecode.GetInstructionSourceLocationLine(nullcInstruction, out int moduleIndex); // Instruction based stepping int nextNullcInstruction = nullcInstruction; int secondaryNullcInstruction = 0; while (nextNullcInstruction < processData.bytecode.instructions.Count) { // Walk forward until an instruction with a different line is hit if (processData.bytecode.GetInstructionSourceLocationLine(nextNullcInstruction, out _) != line) { break; } var nextInstruction = processData.bytecode.instructions[nextNullcInstruction]; // If there is a jump, place a breakpoint at the target (even if it's on the same line) if (nextInstruction.code == NullcInstructionCode.rviJmp) { nextNullcInstruction = (int)nextInstruction.argument; break; } // If there is a conditional jump, place two breakpoints - one after it and one at the target (even if either of them is on the same line) if (nextInstruction.code == NullcInstructionCode.rviJmpz || nextInstruction.code == NullcInstructionCode.rviJmpnz) { secondaryNullcInstruction = nextNullcInstruction + 1; nextNullcInstruction = (int)nextInstruction.argument; break; } // If there is a return, I wish I could just fallback to parent runtime to handle it, may be required to place a breakpoint at the call site if (nextInstruction.code == NullcInstructionCode.rviReturn) { ulong address = GetReturnAddress(stepper.Thread); // Address must be within nullc module or we will have to cancel the step if (address >= processData.nativeModuleInstance.BaseAddress && address < processData.nativeModuleInstance.BaseAddress + processData.nativeModuleInstance.Size) { processData.stepBreakpoint = PlaceBreakpointAtAddress(processData, stepper.Thread, address); } else { stepper.OnStepComplete(stepper.Thread, false); } return; } if (stepper.StepKind == DkmStepKind.Into) { if (nextInstruction.code == NullcInstructionCode.rviCall && stepper.StepKind == DkmStepKind.Into) { NullcFuncInfo function = processData.bytecode.functions[(int)nextInstruction.argument]; if (function.regVmAddress != ~0u) { secondaryNullcInstruction = nextNullcInstruction + 1; nextNullcInstruction = (int)function.regVmAddress; break; } else if (function.funcPtrWrap != 0 || function.funcPtrRaw != 0) { // TODO: Step into an external function // I've tryied placing a breakpoint at the external call target but it's not getting handled correctly // Maybe the solution is to single step the process until the stack frame changes } } else if (nextInstruction.code == NullcInstructionCode.rviCallPtr) { // TODO: Step into a function pointer call } } nextNullcInstruction++; } if (nextNullcInstruction != 0) { ulong instructionAddress = processData.bytecode.ConvertInstructionToNativeAddress(nextNullcInstruction); processData.stepBreakpoint = PlaceBreakpointAtAddress(processData, stepper.Thread, instructionAddress); } if (secondaryNullcInstruction != 0) { ulong instructionAddress = processData.bytecode.ConvertInstructionToNativeAddress(secondaryNullcInstruction); processData.secondaryStepBreakpoint = PlaceBreakpointAtAddress(processData, stepper.Thread, instructionAddress); } } else if (stepper.StepKind == DkmStepKind.Out) { ulong address = GetReturnAddress(stepper.Thread); processData.stepBreakpoint = PlaceBreakpointAtAddress(processData, stepper.Thread, address); } else { throw new NotImplementedException(); } }
bool IDkmRuntimeStepper.OwnsCurrentExecutionLocation(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var processData = DebugHelpers.GetOrCreateDataItem <NullcRemoteProcessDataItem>(runtimeInstance.Process); // Can't handle steps without an address if (stepper.StartingAddress == null) { return(false); } var instructionAddress = stepper.StartingAddress.CPUInstructionPart.InstructionPointer; if (DebugHelpers.useNativeInterfaces) { if (processData.nativeModuleInstance != null) { if (instructionAddress >= processData.nativeModuleInstance.BaseAddress && instructionAddress < processData.nativeModuleInstance.BaseAddress + processData.nativeModuleInstance.Size) { return(processData.bytecode.ConvertNativeAddressToInstruction(instructionAddress) != 0); } } } else { if (processData.moduleInstance != null) { if (instructionAddress >= processData.moduleInstance.BaseAddress && instructionAddress < processData.moduleInstance.BaseAddress + processData.moduleInstance.Size) { return(processData.bytecode.ConvertNativeAddressToInstruction(instructionAddress) != 0); } } } return(false); }