Esempio n. 1
0
        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);
        }
Esempio n. 2
0
            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();
                }
            }