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); } } } }
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); }
public ulong GetThreadEnvironmentBlockAddress(uint threadId) { return(ExecuteOnDkmInitializedThread(() => { DkmThread thread = GetThread(threadId); return thread.TebAddress; })); }
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); }
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); }
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); } }
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"); } }
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"); } }
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); }
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"); } }
/// <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); } }
/// <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); } }
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"); } }
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); }
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 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 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"); } }
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); }
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"); } }
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); }
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(); }
public void OnAsyncBreakComplete(DkmThread thread) { var e = _evalAbortedEvent; if (e != null) { new RemoteComponent.EndFuncEvalExecutionRequest { ThreadId = thread.UniqueId }.SendLower(thread.Process); e.Set(); } }
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(); } }
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); }
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); }
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); }
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); }
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); }
public void do_raise(DkmThread thread, ulong frameBase, ulong vframe) { _owner.OnException(thread); }
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); }
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); }
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); }
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); } }