public DkmStackWalkFrame[] FilterNextFrame(DkmStackContext stackContext, DkmStackWalkFrame nativeFrame) { PyFrameObject pythonFrame = null; var nativeModuleInstance = nativeFrame.ModuleInstance; if (nativeModuleInstance == _pyrtInfo.DLLs.DebuggerHelper) { if (_pyrtInfo.LanguageVersion < PythonLanguageVersion.V36 || (pythonFrame = PyFrameObject.TryCreate(nativeFrame)) == null) { return(DebuggerOptions.ShowNativePythonFrames ? new[] { nativeFrame } : new DkmStackWalkFrame[0]); } } var result = new List <DkmStackWalkFrame>(); if (pythonFrame == null) { var stackWalkData = stackContext.GetDataItem <StackWalkContextData>(); if (stackWalkData == null) { stackWalkData = new StackWalkContextData(); stackContext.SetDataItem(DkmDataCreationDisposition.CreateNew, stackWalkData); } bool?wasLastFrameNative = stackWalkData.IsLastFrameNative; if (nativeModuleInstance != _pyrtInfo.DLLs.Python && nativeModuleInstance != _pyrtInfo.DLLs.CTypes) { stackWalkData.IsLastFrameNative = true; if (wasLastFrameNative == false) { result.Add(DkmStackWalkFrame.Create(nativeFrame.Thread, null, nativeFrame.FrameBase, nativeFrame.FrameSize, DkmStackWalkFrameFlags.NonuserCode, Strings.DebugCallStackNativeToPythonTransition, null, null)); } else { stackWalkData.IsLastFrameNative = true; } result.Add(nativeFrame); return(result.ToArray()); } else { stackWalkData.IsLastFrameNative = false; if (wasLastFrameNative == true) { result.Add(DkmStackWalkFrame.Create(nativeFrame.Thread, null, nativeFrame.FrameBase, nativeFrame.FrameSize, DkmStackWalkFrameFlags.NonuserCode, Strings.DebugCallStackPythonToNativeTransition, null, null)); } } pythonFrame = PyFrameObject.TryCreate(nativeFrame); } if (pythonFrame == null) { if (DebuggerOptions.ShowNativePythonFrames) { result.Add(nativeFrame); } return(result.ToArray()); } PyCodeObject code = pythonFrame.f_code.Read(); var loc = new SourceLocation( code.co_filename.Read().ToStringOrNull(), pythonFrame.f_lineno.Read(), code.co_name.Read().ToStringOrNull(), nativeFrame.InstructionAddress as DkmNativeInstructionAddress); var pythonRuntime = _process.GetPythonRuntimeInstance(); var pythonModuleInstances = pythonRuntime.GetModuleInstances().OfType <DkmCustomModuleInstance>(); var pyModuleInstance = pythonModuleInstances.Where(m => m.FullName == loc.FileName).FirstOrDefault(); if (pyModuleInstance == null) { pyModuleInstance = pythonModuleInstances.Single(m => m.Module.Id.Mvid == Guids.UnknownPythonModuleGuid); } var encodedLocation = loc.Encode(); var instrAddr = DkmCustomInstructionAddress.Create(pythonRuntime, pyModuleInstance, encodedLocation, 0, encodedLocation, null); var frame = DkmStackWalkFrame.Create( nativeFrame.Thread, instrAddr, nativeFrame.FrameBase, nativeFrame.FrameSize, DkmStackWalkFrameFlags.None, null, nativeFrame.Registers, nativeFrame.Annotations); result.Add(frame); if (DebuggerOptions.ShowNativePythonFrames) { result.Add(nativeFrame); } return(result.ToArray()); }
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); }