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 Tuple <ulong, ulong, ulong>[] GetThreadStackTrace(uint threadId, byte[] threadContextBytes) { return(ExecuteOnDkmInitializedThread(() => { DkmThread thread = GetThread(threadId); List <DkmStackFrame> frames = new List <DkmStackFrame>(); DkmProcess process = thread.Process; using (DkmInspectionSession dkmInspectionSession = DkmInspectionSession.Create(process, null)) { using (DkmStackContext dkmStackContext = DkmStackContext.Create(dkmInspectionSession, thread, DkmCallStackFilterOptions.None, new DkmFrameFormatOptions(), new System.Collections.ObjectModel.ReadOnlyCollection <byte>(threadContextBytes), null)) { bool done = false; while (!done) { DkmWorkList dkmWorkList = DkmWorkList.Create(null); dkmStackContext.GetNextFrames(dkmWorkList, int.MaxValue, (ar) => { frames.AddRange(ar.Frames); done = ar.Frames.Length == 0; }); dkmWorkList.Execute(); } } } threads[(int)threadId].Frames.Value = frames.ToArray(); Tuple <ulong, ulong, ulong>[] result = new Tuple <ulong, ulong, ulong> [frames.Count]; for (int i = 0; i < result.Length; i++) { ulong stackOffset, instructionOffset; switch (frames[i].Registers.TagValue) { case DkmFrameRegisters.Tag.X64Registers: { DkmX64FrameRegisters registers = (DkmX64FrameRegisters)frames[i].Registers; instructionOffset = registers.Rip; stackOffset = registers.Rsp; } break; case DkmFrameRegisters.Tag.X86Registers: { DkmX86FrameRegisters registers = (DkmX86FrameRegisters)frames[i].Registers; instructionOffset = registers.Eip; stackOffset = registers.Esp; } break; default: throw new NotImplementedException("Unexpected DkmFrameRegisters.Tag"); } bool found = false; ulong frameOffset = 0; for (int j = 0; !found && j < frames[i].Registers.UnwoundRegisters.Count; j++) { switch ((Dia2Lib.CV_HREG_e)frames[i].Registers.UnwoundRegisters[j].Identifier) { case Dia2Lib.CV_HREG_e.CV_AMD64_EBP: case Dia2Lib.CV_HREG_e.CV_AMD64_RBP: { byte[] bytes = frames[i].Registers.UnwoundRegisters[j].Value.ToArray(); found = true; frameOffset = bytes.Length == 8 ? BitConverter.ToUInt64(bytes, 0) : BitConverter.ToUInt32(bytes, 0); break; } } } if (instructionOffset != frames[i].InstructionAddress.CPUInstructionPart.InstructionPointer) { throw new Exception("Instruction offset is not the same?"); } result[i] = Tuple.Create(instructionOffset, stackOffset, frameOffset); } return result; })); }