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);
        }
Example #2
0
        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;
            }));
        }