示例#1
0
    void IFunctionTracer.OnEntryBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) {
      // The function was just entered.  Install the exit breakpoint on the calling thread at the
      // return address, and notify any listeners.
      DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance);

      bool suppressExitBreakpoint = false;
      if (OnFunctionEntered != null)
        OnFunctionEntered(frame, frameAnalyzer, out suppressExitBreakpoint);

      if (!suppressExitBreakpoint) {
        ulong ret = frame.VscxGetReturnAddress();

        DkmInstructionAddress retAddr = thread.Process.CreateNativeInstructionAddress(ret);
        DkmRuntimeInstructionBreakpoint exitBp = DkmRuntimeInstructionBreakpoint.Create(
            Guids.Source.FunctionTraceExit, thread, retAddr, false, null);
        // Capture the value of every argument now, since when the exit breakpoint gets hit, the
        // target function will have already returned and its frame will be cleaned up.
        exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways,
            new FunctionTraceEntryDataItem { 
                EntryArgumentValues = frameAnalyzer.GetAllArgumentValues(frame) 
            });
        exitBp.SetDataItem(DkmDataCreationDisposition.CreateAlways,
            new FunctionTraceDataItem { Tracer = this });
        exitBp.Enable();
      }
    }
        // Sets a breakpoint on a given function pointer, that represents some code outside of the Python DLL that can potentially
        // be invoked as a result of the current step-in operation (in which case it is the step-in target).
        private void OnPotentialRuntimeExit(DkmThread thread, ulong funcPtr)
        {
            if (funcPtr == 0)
            {
                return;
            }

            if (_pyrtInfo.DLLs.Python.ContainsAddress(funcPtr))
            {
                return;
            }
            else if (_pyrtInfo.DLLs.DebuggerHelper != null && _pyrtInfo.DLLs.DebuggerHelper.ContainsAddress(funcPtr))
            {
                return;
            }
            else if (_pyrtInfo.DLLs.CTypes != null && _pyrtInfo.DLLs.CTypes.ContainsAddress(funcPtr))
            {
                return;
            }

            var bp = _process.CreateBreakpoint(Guids.PythonStepTargetSourceGuid, funcPtr);

            bp.Enable();

            _stepInTargetBreakpoints.Add(bp);
        }
            // This step-in gate is not marked [StepInGate] because it doesn't live in pythonXX.dll, and so we register it manually.
            public void _call_function_pointer(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var   cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
                ulong pProc   = cppEval.EvaluateUInt64(useRegisters ? "@rdx" : "pProc");

                _owner.OnPotentialRuntimeExit(thread, pProc);
            }
        public void OnBeginStepIn(DkmThread thread)
        {
            var frameInfo = new RemoteComponent.GetCurrentFrameInfoRequest {
                ThreadId = thread.UniqueId
            }.SendLower(thread.Process);

            var workList = DkmWorkList.Create(null);
            var topFrame = thread.GetTopStackFrame();
            var curAddr  = (topFrame != null) ? topFrame.InstructionAddress as DkmNativeInstructionAddress : null;

            foreach (var gate in _stepInGates)
            {
                gate.Breakpoint.Enable();

                // A step-in may happen when we are stopped inside a step-in gate function. For example, when the gate function
                // calls out to user code more than once, and the user then steps out from the first call; we're now inside the
                // gate, but the runtime exit breakpoints for that gate have been cleared after the previous step-in completed.
                // To correctly handle this scenario, we need to check whether we're inside a gate with multiple exit points, and
                // if so, call the associated gate handler (as it the entry breakpoint for the gate is hit) so that it re-enables
                // the runtime exit breakpoints for that gate.
                if (gate.HasMultipleExitPoints && curAddr != null)
                {
                    var addr = (DkmNativeInstructionAddress)gate.Breakpoint.InstructionAddress;
                    if (addr.IsInSameFunction(curAddr))
                    {
                        gate.Handler(thread, frameInfo.FrameBase, frameInfo.VFrame, useRegisters: false);
                    }
                }
            }
        }
示例#5
0
 private void OnStepFallThrough(DkmThread thread)
 {
     // Step fell through the end of the frame in which it began - time to register the breakpoint for the return address.
     new LocalStackWalkingComponent.BeginStepOutNotification
     {
         ThreadId = thread.UniqueId
     }.SendHigher(_process);
 }
示例#6
0
        public ulong GetThreadEnvironmentBlockAddress(uint threadId)
        {
            return(ExecuteOnDkmInitializedThread(() =>
            {
                DkmThread thread = GetThread(threadId);

                return thread.TebAddress;
            }));
        }
示例#7
0
        public unsafe void GetThreadContext(uint threadId, IntPtr contextBufferPointer, int contextBufferSize)
        {
            ExecuteOnDkmInitializedThread(() =>
            {
                DkmThread thread = GetThread(threadId);

                thread.GetContext(-1, contextBufferPointer.ToPointer(), contextBufferSize);
            });
        }
            public void PyType_GenericNew(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string typeVar = useRegisters ? "((PyTypeObject*)@rcx)" : "type";

                ulong tp_alloc = cppEval.EvaluateUInt64(typeVar + "->tp_alloc");

                _owner.OnPotentialRuntimeExit(thread, tp_alloc);
            }
            public void builtin_next(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string argsVar = useRegisters ? "((PyTupleObject*)@rdx)" : "((PyTupleObject*)args)";

                ulong tp_iternext = cppEval.EvaluateUInt64(argsVar + "->ob_item[0]->ob_type->tp_iternext");

                _owner.OnPotentialRuntimeExit(thread, tp_iternext);
            }
            public void PyObject_Print(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                CppExpressionEvaluator cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string opVar = useRegisters ? "((PyObject*)@rcx)" : "op";

                ulong tp_print = cppEval.EvaluateUInt64(opVar + "->ob_type->tp_print");

                _owner.OnPotentialRuntimeExit(thread, tp_print);
            }
            public void PyCFunction_Call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                ulong ml_meth = cppEval.EvaluateUInt64(
                    "((PyObject*){0})->ob_type == &PyCFunction_Type ? ((PyCFunctionObject*){0})->m_ml->ml_meth : 0",
                    useRegisters ? "@rcx" : "func");

                _owner.OnPotentialRuntimeExit(thread, ml_meth);
            }
            public void getset_set(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string descrVar = useRegisters ? "((PyGetSetDescrObject*)@rcx)" : "descr";

                ulong set = cppEval.EvaluateUInt64(descrVar + "->d_getset->set");

                _owner.OnPotentialRuntimeExit(thread, set);
            }
示例#13
0
        private DkmStepper StepDone(DkmThread thread)
        {
            new LocalComponent.StepCompleteNotification().SendHigher(thread.Process);
            new LocalStackWalkingComponent.StepCompleteNotification().SendHigher(thread.Process);

            var stepper = _stepper;

            _stepper = null;
            _stepKind.Write(0);
            return(stepper);
        }
            public void PyObject_SetAttrString(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string vVar = useRegisters ? "((PyObject*)@rcx)" : "v";

                ulong tp_setattr = cppEval.EvaluateUInt64(vVar + "->ob_type->tp_setattr");

                _owner.OnPotentialRuntimeExit(thread, tp_setattr);
            }
            public void PyObject_Call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string funcVar = useRegisters ? "((PyObject*)@rcx)" : "func";

                ulong tp_call = cppEval.EvaluateUInt64(funcVar + "->ob_type->tp_call");

                _owner.OnPotentialRuntimeExit(thread, tp_call);
            }
            public void PyIter_Next(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string iterVar = useRegisters ? "((PyObject*)@rcx)" : "iter";

                ulong tp_iternext = cppEval.EvaluateUInt64(iterVar + "->ob_type->tp_iternext");

                _owner.OnPotentialRuntimeExit(thread, tp_iternext);
            }
示例#17
0
    public static void VscxOnRuntimeBreakpointReceived(
        this DkmProcess process,
        DkmRuntimeBreakpoint bp,
        DkmThread thread,
        bool hasException,
        DkmEventDescriptorS eventDescriptor) {
      RuntimeBreakpointHandler handler = process.GetDataItem<RuntimeBreakpointHandler>();
      if (handler == null)
        return;

      handler.OnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor);
    }
 public void OnRuntimeBreakpointReceived(
     DkmRuntimeBreakpoint bp,
     DkmThread thread,
     bool hasException,
     DkmEventDescriptorS eventDescriptor) {
   FunctionTraceDataItem traceDataItem = bp.GetDataItem<FunctionTraceDataItem>();
   if (traceDataItem != null && traceDataItem.Tracer != null) {
     if (bp.SourceId == Guids.Source.FunctionTraceEnter)
       traceDataItem.Tracer.OnEntryBreakpointHit(bp, thread, hasException);
     else if (bp.SourceId == Guids.Source.FunctionTraceExit)
       traceDataItem.Tracer.OnExitBreakpointHit(bp, thread, hasException);
   }
 }
示例#19
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "CClosure", ref available);

                functionAddress = Helper.Read(inspectionSession, thread, frame, "CClosure", "f", ref available, ref success, ref failure);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaExternalClosureData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#20
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "Udata", ref available);

                metaTableDataAddress = Helper.Read(inspectionSession, thread, frame, "Udata", new[] { "uv.metatable", "metatable" }, ref available, ref success, ref failure);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaUserDataData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#21
0
        public CppExpressionEvaluator(DkmThread thread, ulong frameBase, ulong vframe) {
            _process = thread.Process;

            var inspectionSession = DkmInspectionSession.Create(_process, null);
            _cppInspectionContext = DkmInspectionContext.Create(inspectionSession, _process.GetNativeRuntimeInstance(), thread, Timeout,
                DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects, DkmFuncEvalFlags.None, 10, CppLanguage, null);

            const int CV_ALLREG_VFRAME = 0x00007536;
            var vframeReg = DkmUnwoundRegister.Create(CV_ALLREG_VFRAME, new ReadOnlyCollection<byte>(BitConverter.GetBytes(vframe)));
            var regs = thread.GetCurrentRegisters(new[] { vframeReg });
            var iaddr = _process.CreateNativeInstructionAddress(regs.GetInstructionPointer());
            _nativeFrame = DkmStackWalkFrame.Create(thread, iaddr, frameBase, 0, DkmStackWalkFrameFlags.None, null, regs, null);
        }
示例#22
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "TString", ref available);

                offsetToContent_5_4 = Helper.ReadOptional(inspectionSession, thread, frame, "TString", "contents", "used in 5.4", ref optional);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaStringData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#23
0
        /// <summary>
        /// Gets the thread context for the given thread.
        /// </summary>
        /// <param name="threadID">The OS thread ID to read the context from.</param>
        /// <param name="contextFlags">The requested context flags, or 0 for default flags.</param>
        /// <param name="contextSize">The size (in bytes) of the context parameter.</param>
        /// <param name="context">A pointer to the buffer to write to.</param>
        public unsafe bool GetThreadContext(uint threadID, uint contextFlags, uint contextSize, IntPtr context)
        {
            try
            {
                DkmThread thread = Process.GetThreads().Concat(Process.GetSystemThreads()).First(t => t.SystemPart.Id == threadID);

                thread.GetContext((int)contextFlags, context.ToPointer(), (int)contextSize);
                return(true);
            }
            catch
            {
                return(false);
            }
        }
示例#24
0
        /// <summary>
        /// Gets the thread context for the given thread.
        /// </summary>
        /// <param name="threadID">The OS thread ID to read the context from.</param>
        /// <param name="contextFlags">The requested context flags, or 0 for default flags.</param>
        /// <param name="contextSize">The size (in bytes) of the context parameter.</param>
        /// <param name="context">A pointer to the buffer to write to.</param>
        public bool GetThreadContext(uint threadID, uint contextFlags, uint contextSize, byte[] context)
        {
            try
            {
                DkmThread thread = Process.GetThreads().Concat(Process.GetSystemThreads()).First(t => t.SystemPart.Id == threadID);

                thread.GetContext((int)contextFlags, context);
                return(true);
            }
            catch
            {
                return(false);
            }
        }
示例#25
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "LocVar", ref available);

                nameAddress = Helper.Read(inspectionSession, thread, frame, "LocVar", "varname", ref available, ref success, ref failure);
                lifetimeStartInstruction = Helper.Read(inspectionSession, thread, frame, "LocVar", "startpc", ref available, ref success, ref failure);
                lifetimeEndInstruction   = Helper.Read(inspectionSession, thread, frame, "LocVar", "endpc", ref available, ref success, ref failure);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaLocalVariableData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#26
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "TValue", ref available);

                valueAddress  = Helper.Read(inspectionSession, thread, frame, "TValue", new[] { "u.i.v__", "value_", "value" }, ref available, ref success, ref failure);
                typeAddress   = Helper.Read(inspectionSession, thread, frame, "TValue", new[] { "u.i.tt__", "tt_", "tt" }, ref available, ref success, ref failure);
                doubleAddress = Helper.ReadOptional(inspectionSession, thread, frame, "TValue", "u.d__", "used in NAN trick", ref optional);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaValueData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
            public void type_call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                CppExpressionEvaluator cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string typeVar = useRegisters ? "((PyTypeObject*)@rcx)" : "type";

                ulong tp_new = cppEval.EvaluateUInt64(typeVar + "->tp_new");

                _owner.OnPotentialRuntimeExit(thread, tp_new);

                ulong tp_init = cppEval.EvaluateUInt64(typeVar + "->tp_init");

                _owner.OnPotentialRuntimeExit(thread, tp_init);
            }
            public void new_threadstate(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                // Addressing this local by name does not work for release builds, so read the return value directly from the register instead.
                var tstate = PyThreadState.TryCreate(process, cppEval.EvaluateReturnValueUInt64());

                if (tstate == null)
                {
                    return;
                }

                _owner.RegisterTracing(tstate);
            }
示例#29
0
        public static void VscxOnRuntimeBreakpointReceived(
            this DkmProcess process,
            DkmRuntimeBreakpoint bp,
            DkmThread thread,
            bool hasException,
            DkmEventDescriptorS eventDescriptor)
        {
            RuntimeBreakpointHandler handler = process.GetDataItem <RuntimeBreakpointHandler>();

            if (handler == null)
            {
                return;
            }

            handler.OnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor);
        }
示例#30
0
 public static DkmInspectionContext Create(
     DkmInspectionSession InspectionSession,
     DkmRuntimeInstance RuntimeInstance,
     DkmThread Thread,
     uint Timeout,
     DkmEvaluationFlags EvaluationFlags,
     DkmFuncEvalFlags FuncEvalFlags,
     uint Radix,
     DkmLanguage Language,
     DkmRawReturnValue ReturnValue,
     DkmCompiledVisualizationData AdditionalVisualizationData,
     DkmCompiledVisualizationDataPriority AdditionalVisualizationDataPriority,
     ReadOnlyCollection <DkmRawReturnValueContainer> ReturnValues)
 {
     return(new DkmInspectionContext(InspectionSession, EvaluationFlags, Radix, RuntimeInstance));
 }
示例#31
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "lua_State", ref available);

                globalStateAddress_opt             = Helper.ReadOptional(inspectionSession, thread, frame, "lua_State", "l_G", "used in Locals Window", ref optional);
                callInfoAddress                    = Helper.Read(inspectionSession, thread, frame, "lua_State", "ci", ref available, ref success, ref failure);
                savedProgramCounterAddress_5_1_opt = Helper.ReadOptional(inspectionSession, thread, frame, "lua_State", "savedpc", "used in 5.1 (*)", ref optional);
                baseCallInfoAddress_5_1            = Helper.ReadOptional(inspectionSession, thread, frame, "lua_State", "base_ci", "used in 5.1", ref optional);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaStateData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#32
0
 public static DkmInspectionContext Create(
     DkmInspectionSession InspectionSession,
     DkmRuntimeInstance RuntimeInstance,
     DkmThread Thread,
     uint Timeout,
     DkmEvaluationFlags EvaluationFlags,
     DkmFuncEvalFlags FuncEvalFlags,
     uint Radix,
     DkmLanguage Language,
     DkmRawReturnValue ReturnValue,
     DkmCompiledVisualizationData AdditionalVisualizationData,
     DkmCompiledVisualizationDataPriority AdditionalVisualizationDataPriority,
     ReadOnlyCollection<DkmRawReturnValueContainer> ReturnValues)
 {
     return new DkmInspectionContext(InspectionSession, EvaluationFlags, Radix, RuntimeInstance);
 }
            public void do_richcompare(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters)
            {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string vVar = useRegisters ? "((PyObject*)@rcx)" : "v";
                string wVar = useRegisters ? "((PyObject*)@rdx)" : "w";

                ulong tp_richcompare1 = cppEval.EvaluateUInt64(vVar + "->ob_type->tp_richcompare");

                _owner.OnPotentialRuntimeExit(thread, tp_richcompare1);

                ulong tp_richcompare2 = cppEval.EvaluateUInt64(wVar + "->ob_type->tp_richcompare");

                _owner.OnPotentialRuntimeExit(thread, tp_richcompare2);
            }
示例#34
0
            public static void LoadSchema(DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame frame)
            {
                available = true;
                success   = 0;
                failure   = 0;
                optional  = 0;

                structSize = Helper.GetSize(inspectionSession, thread, frame, "Upvaldesc", ref available);

                nameAddress = Helper.Read(inspectionSession, thread, frame, "Upvaldesc", "name", ref available, ref success, ref failure);

                if (Log.instance != null)
                {
                    Log.instance.Debug($"LuaUpvalueDescriptionData schema {(available ? "available" : "not available")} with {success} successes and {failure} failures and {optional} optional");
                }
            }
示例#35
0
        public CppExpressionEvaluator(DkmThread thread, ulong frameBase, ulong vframe)
        {
            _process = thread.Process;

            var inspectionSession = DkmInspectionSession.Create(_process, null);

            _cppInspectionContext = DkmInspectionContext.Create(inspectionSession, _process.GetNativeRuntimeInstance(), thread, Timeout,
                                                                DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects, DkmFuncEvalFlags.None, 10, CppLanguage, null);

            const int CV_ALLREG_VFRAME = 0x00007536;
            var       vframeReg        = DkmUnwoundRegister.Create(CV_ALLREG_VFRAME, new ReadOnlyCollection <byte>(BitConverter.GetBytes(vframe)));
            var       regs             = thread.GetCurrentRegisters(new[] { vframeReg });
            var       iaddr            = _process.CreateNativeInstructionAddress(regs.GetInstructionPointer());

            _nativeFrame = DkmStackWalkFrame.Create(thread, iaddr, frameBase, 0, DkmStackWalkFrameFlags.None, null, regs, null);
        }
示例#36
0
    void IFunctionTracer.OnExitBreakpointHit(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException) {
      FunctionTraceEntryDataItem traceDataItem = bp.GetDataItem<FunctionTraceEntryDataItem>();

      if (OnFunctionExited != null) {
        DkmStackWalkFrame frame = thread.GetTopStackWalkFrame(bp.RuntimeInstance);
        StackFrameAnalyzer exitAnalyzer = null;
        if (traceDataItem != null) {
          DkmSystemInformationFlags systemInformationFlags = 
              frame.ModuleInstance.Process.SystemInformation.Flags;
          bool isTarget64Bit = systemInformationFlags.HasFlag(DkmSystemInformationFlags.Is64Bit);
          int pointerSize = (isTarget64Bit) ? 8 : 4;
          exitAnalyzer = new CachedFrameAnalyzer(
              frameAnalyzer.Parameters, 
              traceDataItem.EntryArgumentValues, 
              pointerSize);
        }
        OnFunctionExited(frame, exitAnalyzer);
      }

      // Since this was a one-shot breakpoint, it is unconditionally closed.
      bp.Close();
    }
示例#37
0
 public void OnAsyncBreakComplete(DkmThread thread) {
     var e = _evalAbortedEvent;
     if (e != null) {
         new RemoteComponent.EndFuncEvalExecutionRequest { ThreadId = thread.UniqueId }.SendLower(thread.Process);
         e.Set();
     }
 }
示例#38
0
 private void OnEvalComplete(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
     var e = _evalCompleteEvent;
     if (e != null) {
         new RemoteComponent.EndFuncEvalExecutionRequest { ThreadId = thread.UniqueId }.SendLower(thread.Process);
         e.Set();
     }
 }
示例#39
0
            public void builtin_next(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string argsVar = useRegisters ? "((PyTupleObject*)@rdx)" : "((PyTupleObject*)args)";

                ulong tp_iternext = cppEval.EvaluateUInt64(argsVar + "->ob_item[0]->ob_type->tp_iternext");
                _owner.OnPotentialRuntimeExit(thread, tp_iternext);
            }
示例#40
0
            public void PyIter_Next(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string iterVar = useRegisters ? "((PyObject*)@rcx)" : "iter";

                ulong tp_iternext = cppEval.EvaluateUInt64(iterVar + "->ob_type->tp_iternext");
                _owner.OnPotentialRuntimeExit(thread, tp_iternext);
            }
示例#41
0
            public void do_richcompare(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string vVar = useRegisters ? "((PyObject*)@rcx)" : "v";
                string wVar = useRegisters ? "((PyObject*)@rdx)" : "w";

                ulong tp_richcompare1 = cppEval.EvaluateUInt64(vVar + "->ob_type->tp_richcompare");
                _owner.OnPotentialRuntimeExit(thread, tp_richcompare1);

                ulong tp_richcompare2 = cppEval.EvaluateUInt64(wVar + "->ob_type->tp_richcompare");
                _owner.OnPotentialRuntimeExit(thread, tp_richcompare2);
            }
示例#42
0
            public void PyObject_Call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string funcVar = useRegisters ? "((PyObject*)@rcx)" : "func";

                ulong tp_call = cppEval.EvaluateUInt64(funcVar + "->ob_type->tp_call");
                _owner.OnPotentialRuntimeExit(thread, tp_call);
            }
示例#43
0
            public void PyObject_SetAttr(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string vVar = useRegisters ? "((PyObject*)@rcx)" : "v";

                ulong tp_setattr = cppEval.EvaluateUInt64(vVar + "->ob_type->tp_setattr");
                _owner.OnPotentialRuntimeExit(thread, tp_setattr);

                ulong tp_setattro = cppEval.EvaluateUInt64(vVar + "->ob_type->tp_setattro");
                _owner.OnPotentialRuntimeExit(thread, tp_setattro);
            }
示例#44
0
            public static void PyCode_NewEmpty(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                ulong filenamePtr = cppEval.EvaluateUInt64("filename");
                if (filenamePtr == 0) {
                    return;
                }

                string filename = new CStringProxy(process, filenamePtr).ReadUnicode();
                if (process.GetPythonRuntimeInstance().GetModuleInstances().Any(mi => mi.FullName == filename)) {
                    return;
                }

                new RemoteComponent.CreateModuleRequest {
                    ModuleId = Guid.NewGuid(),
                    FileName = filename
                }.SendLower(process);
            }
示例#45
0
        public void OnException(DkmThread thread) {
            if (thread.SystemPart == null) {
                Debug.Fail("OnException couldn't obtain system thread ID.");
                return;
            }
            var tid = thread.SystemPart.Id;

            var process = thread.Process;
            PyThreadState tstate = PyThreadState.GetThreadStates(process).FirstOrDefault(ts => ts.thread_id.Read() == tid);
            if (tstate == null) {
                Debug.Fail("OnException couldn't find PyThreadState corresponding to system thread " + tid);
                return;
            }

            var exc_type = tstate.curexc_type.TryRead();
            var exc_value = tstate.curexc_value.TryRead();
            if (exc_type == null || exc_type.IsNone) {
                return;
            }

            var reprOptions = new ReprOptions(process);

            string typeName = "<unknown exception type>";
            string additionalInfo = "";
            try {
                var typeObject = exc_type as PyTypeObject;
                if (typeObject != null) {
                    var mod = typeObject.__module__;
                    var ver = _process.GetPythonRuntimeInfo().LanguageVersion;
                    if ((mod == "builtins" && ver >= PythonLanguageVersion.V30) ||
                        (mod == "exceptions" && ver < PythonLanguageVersion.V30)) {

                        typeName = typeObject.__name__;
                    } else {
                        typeName = mod + "." + typeObject.__name__;
                    }
                }

                var exc = exc_value as PyBaseExceptionObject;
                if (exc != null) {
                    var args = exc.args.TryRead();
                    if (args != null) {
                        additionalInfo = args.Repr(reprOptions);
                    }
                } else {
                    var str = exc_value as IPyBaseStringObject;
                    if (str != null) {
                        additionalInfo = str.ToString();
                    } else if (exc_value != null) {
                        additionalInfo = exc_value.Repr(reprOptions);
                    }
                }
            } catch {
            }

            new RemoteComponent.RaiseExceptionRequest
            {
                ThreadId = thread.UniqueId,
                Name = typeName,
                AdditionalInformation = Encoding.Unicode.GetBytes(additionalInfo)
            }.SendLower(process);
        }
示例#46
0
            public void new_threadstate(DkmThread thread, ulong frameBase, ulong vframe) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                // Addressing this local by name does not work for release builds, so read the return value directly from the register instead.
                var tstate = new PyThreadState(thread.Process, cppEval.EvaluateReturnValueUInt64());
                if (tstate == null) {
                    return;
                }

                _owner.RegisterTracing(tstate);
            }
示例#47
0
        // Sets a breakpoint on a given function pointer, that represents some code outside of the Python DLL that can potentially
        // be invoked as a result of the current step-in operation (in which case it is the step-in target).
        private void OnPotentialRuntimeExit(DkmThread thread, ulong funcPtr) {
            if (funcPtr == 0) {
                return;
            }

            if (_pyrtInfo.DLLs.Python.ContainsAddress(funcPtr)) {
                return;
            } else if (_pyrtInfo.DLLs.DebuggerHelper != null && _pyrtInfo.DLLs.DebuggerHelper.ContainsAddress(funcPtr)) {
                return;
            } else if (_pyrtInfo.DLLs.CTypes != null && _pyrtInfo.DLLs.CTypes.ContainsAddress(funcPtr)) {
                return;
            }

            var bp = _process.CreateBreakpoint(Guids.PythonStepTargetSourceGuid, funcPtr);
            bp.Enable();

            _stepInTargetBreakpoints.Add(bp);
        }
示例#48
0
        public void OnBeginStepOut(DkmThread thread) {
            // When we're stepping out while in Python code, there are two possibilities. Either the stack looks like this:
            //
            //   PythonFrame1
            //   PythonFrame2
            //
            // or else it looks like this:
            //
            //   PythonFrame
            //   [Native to Python transition]
            //   NativeFrame
            //
            // In both cases, we use native breakpoints on the return address to catch the end of step-out operation.
            // For Python-to-native step-out, this is the only option. For Python-to-Python, it would seem that TraceFunc
            // can detect it via PyTrace_RETURN, but it doesn't actually know whether the return is to Python or to
            // native at the point where it's reported - and, in any case, we need to let PyEval_EvalFrameEx to return
            // before reporting the completion of that step-out (otherwise we will show the returning frame in call stack).

            // Find the destination for step-out by walking the call stack and finding either the first native frame
            // outside of Python and helper DLLs, or the second Python frame.
            var inspectionSession = DkmInspectionSession.Create(_process, null);
            var frameFormatOptions = new DkmFrameFormatOptions(DkmVariableInfoFlags.None, DkmFrameNameFormatOptions.None, DkmEvaluationFlags.None, 10000, 10);
            var stackContext = DkmStackContext.Create(inspectionSession, thread, DkmCallStackFilterOptions.None, frameFormatOptions, null, null);
            DkmStackFrame frame = null;
            for (int pyFrameCount = 0; pyFrameCount != 2; ) {
                DkmStackFrame[] frames = null;
                var workList = DkmWorkList.Create(null);
                stackContext.GetNextFrames(workList, 1, (result) => { frames = result.Frames; });
                workList.Execute();
                if (frames == null || frames.Length != 1) {
                    return;
                }
                frame = frames[0];

                var frameModuleInstance = frame.ModuleInstance;
                if (frameModuleInstance is DkmNativeModuleInstance &&
                    frameModuleInstance != _pyrtInfo.DLLs.Python &&
                    frameModuleInstance != _pyrtInfo.DLLs.DebuggerHelper &&
                    frameModuleInstance != _pyrtInfo.DLLs.CTypes) {
                    break;
                } else if (frame.RuntimeInstance != null && frame.RuntimeInstance.Id.RuntimeType == Guids.PythonRuntimeTypeGuid) {
                    ++pyFrameCount;
                }
            }

            var nativeAddr = frame.InstructionAddress as DkmNativeInstructionAddress;
            if (nativeAddr == null) {
                var customAddr = frame.InstructionAddress as DkmCustomInstructionAddress;
                if (customAddr == null) {
                    return;
                }

                var loc = new SourceLocation(customAddr.AdditionalData, thread.Process);
                nativeAddr = loc.NativeAddress;
                if (nativeAddr == null) {
                    return;
                }
            }

            var bp = DkmRuntimeInstructionBreakpoint.Create(Guids.PythonStepTargetSourceGuid, thread, nativeAddr, false, null);
            bp.Enable();

            _stepOutTargetBreakpoints.Add(bp);
        }
示例#49
0
        public void OnBeginStepIn(DkmThread thread) {
            var frameInfo = new RemoteComponent.GetCurrentFrameInfoRequest { ThreadId = thread.UniqueId }.SendLower(thread.Process);

            var workList = DkmWorkList.Create(null);
            var topFrame = thread.GetTopStackFrame();
            var curAddr = (topFrame != null) ? topFrame.InstructionAddress as DkmNativeInstructionAddress : null;

            foreach (var gate in _stepInGates) {
                gate.Breakpoint.Enable();

                // A step-in may happen when we are stopped inside a step-in gate function. For example, when the gate function
                // calls out to user code more than once, and the user then steps out from the first call; we're now inside the
                // gate, but the runtime exit breakpoints for that gate have been cleared after the previous step-in completed. 
                // To correctly handle this scenario, we need to check whether we're inside a gate with multiple exit points, and
                // if so, call the associated gate handler (as it the entry breakpoint for the gate is hit) so that it re-enables
                // the runtime exit breakpoints for that gate.
                if (gate.HasMultipleExitPoints && curAddr != null) {
                    var addr = (DkmNativeInstructionAddress)gate.Breakpoint.InstructionAddress;
                    if (addr.IsInSameFunction(curAddr)) {
                        gate.Handler(thread, frameInfo.FrameBase, frameInfo.VFrame, useRegisters: false);
                    }
                }
            }
        }
示例#50
0
 public void do_raise(DkmThread thread, ulong frameBase, ulong vframe) {
     _owner.OnException(thread);
 }
示例#51
0
 public void PyErr_SetObject(DkmThread thread, ulong frameBase, ulong vframe) {
     _owner.OnException(thread);
 }
 void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint bp, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor)
 {
     DkmProcess process = bp.Process;
       process.VscxOnRuntimeBreakpointReceived(bp, thread, hasException, eventDescriptor);
 }
示例#53
0
            public void PyCFunction_Call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                ulong ml_meth = cppEval.EvaluateUInt64(
                    "((PyObject*){0})->ob_type == &PyCFunction_Type ? ((PyCFunctionObject*){0})->m_ml->ml_meth : 0",
                    useRegisters ? "@rcx" : "func");
                _owner.OnPotentialRuntimeExit(thread, ml_meth);
            }
示例#54
0
            public static void PyCode_New(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                var filenamePtr = cppEval.EvaluateUInt64("filename");
                var filenameObj = PyObject.FromAddress(process, filenamePtr) as IPyBaseStringObject;
                if (filenameObj == null) {
                    return;
                }

                string filename = filenameObj.ToString();
                if (process.GetPythonRuntimeInstance().GetModuleInstances().Any(mi => mi.FullName == filename)) {
                    return;
                }

                new RemoteComponent.CreateModuleRequest {
                    ModuleId = Guid.NewGuid(),
                    FileName = filename
                }.SendLower(process);
            }
示例#55
0
            public void getset_set(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string descrVar = useRegisters ? "((PyGetSetDescrObject*)@rcx)" : "descr";

                ulong set = cppEval.EvaluateUInt64(descrVar + "->d_getset->set");
                _owner.OnPotentialRuntimeExit(thread, set);
            }
示例#56
0
 // This step-in gate is not marked [StepInGate] because it doesn't live in pythonXX.dll, and so we register it manually.
 public void _call_function_pointer(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
     var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
     ulong pProc = cppEval.EvaluateUInt64(useRegisters ? "@rdx" : "pProc");
     _owner.OnPotentialRuntimeExit(thread, pProc);
 }
示例#57
0
            public void PyType_GenericNew(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                string typeVar = useRegisters ? "((PyTypeObject*)@rcx)" : "type";

                ulong tp_alloc = cppEval.EvaluateUInt64(typeVar + "->tp_alloc");
                _owner.OnPotentialRuntimeExit(thread, tp_alloc);
            }
示例#58
0
            public void call_function(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                int oparg = cppEval.EvaluateInt32(useRegisters ? "@rdx" : "oparg");

                int na = oparg & 0xff;
                int nk = (oparg >> 8) & 0xff;
                int n = na + 2 * nk;

                ulong func = cppEval.EvaluateUInt64(
                    "*((*(PyObject***){0}) - {1} - 1)",
                    useRegisters ? "@rcx" : "pp_stack",
                    n);
                var obj = PyObject.FromAddress(process, func);
                ulong ml_meth = cppEval.EvaluateUInt64(
                    "((PyObject*){0})->ob_type == &PyCFunction_Type ? ((PyCFunctionObject*){0})->m_ml->ml_meth : 0",
                    func);

                _owner.OnPotentialRuntimeExit(thread, ml_meth);
            }
示例#59
0
            public void PyInterpreterState_New(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
                var process = thread.Process;
                var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);

                var istate = PyInterpreterState.TryCreate(process, cppEval.EvaluateReturnValueUInt64());
                if (istate == null) {
                    return;
                }

                if (process.GetPythonRuntimeInfo().LanguageVersion >= PythonLanguageVersion.V36) {
                    _owner.RegisterJITTracing(istate);
                }
            }