Esempio n. 1
0
        internal static DkmInspectionSession CreateInspectionSession(DkmProcess process, DkmThread thread, SupportBreakpointHitMessage data, out DkmStackWalkFrame frame)
        {
            const int CV_ALLREG_VFRAME   = 0x00007536;
            var       vFrameRegister     = DkmUnwoundRegister.Create(CV_ALLREG_VFRAME, new ReadOnlyCollection <byte>(BitConverter.GetBytes(data.vframe)));
            var       registers          = thread.GetCurrentRegisters(new[] { vFrameRegister });
            var       instructionAddress = process.CreateNativeInstructionAddress(registers.GetInstructionPointer());

            frame = DkmStackWalkFrame.Create(thread, instructionAddress, data.frameBase, 0, DkmStackWalkFrameFlags.None, null, registers, null);

            return(DkmInspectionSession.Create(process, null));
        }
Esempio n. 2
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);
        }
Esempio n. 3
0
        public static unsafe PyFrameObject TryCreate(DkmStackWalkFrame frame)
        {
            var process = frame.Process;

            if (frame.InstructionAddress == null)
            {
                return(null);
            }
            if (frame.RuntimeInstance.Id.RuntimeType != Guids.PythonRuntimeTypeGuid && !IsInEvalFrame(frame))
            {
                return(null);
            }

            var cppLanguage       = DkmLanguage.Create("C++", new DkmCompilerId(Guids.MicrosoftVendorGuid, Guids.CppLanguageGuid));
            var inspectionSession = DkmInspectionSession.Create(process, null);
            var inspectionContext = DkmInspectionContext.Create(inspectionSession, process.GetNativeRuntimeInstance(), frame.Thread, 0,
                                                                DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects, DkmFuncEvalFlags.None, 10, cppLanguage, null);

            CppExpressionEvaluator cppEval;

            try
            {
                cppEval = new CppExpressionEvaluator(inspectionContext, frame);
            }
            catch (ArgumentException)
            {
                Debug.Fail("Failed to create C++ expression evaluator while obtaining PyFrameObject from a native frame.");
                return(null);
            }

            ulong framePtr;

            try
            {
                framePtr = cppEval.EvaluateUInt64("f");
            }
            catch (CppEvaluationException)
            {
                Debug.Fail("Failed to evaluate the 'f' parameter to PyEval_EvalFrameEx while obtaining PyFrameObject from a native frame.");
                return(null);
            }

            return(new PyFrameObject(frame.Process, framePtr));
        }
        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);
        }
        void IDkmLanguageConditionEvaluator.EvaluateCondition(DkmEvaluationBreakpointCondition evaluationCondition, DkmStackWalkFrame stackFrame, out bool stop, out string errorText)
        {
            DkmProcess process = stackFrame.Process;

            var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process);

            if (processData.locations == null)
            {
                stop      = true;
                errorText = "Debug helper data for conditional breakpoint is missing";
                return;
            }

            DkmInspectionSession inspectionSession = DkmInspectionSession.Create(process, null);

            ulong stateAddress = DebugHelpers.ReadPointerVariable(process, processData.locations.helperBreakHitLuaStateAddress).GetValueOrDefault(0);

            if (stateAddress == 0)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = "Failed to evaluate current Lua state address";
                return;
            }

            ulong callInfoAddress = 0;

            // Read lua_State
            ulong temp = stateAddress;

            ulong?savedProgramCounterAddress = null;

            // CommonHeader
            DebugHelpers.SkipStructPointer(process, ref temp);
            DebugHelpers.SkipStructByte(process, ref temp);
            DebugHelpers.SkipStructByte(process, ref temp);

            if (processData.luaVersion == 501)
            {
                DebugHelpers.SkipStructByte(process, ref temp);    // status
                DebugHelpers.SkipStructPointer(process, ref temp); // top
                DebugHelpers.SkipStructPointer(process, ref temp); // base
                DebugHelpers.SkipStructPointer(process, ref temp); // l_G
                callInfoAddress            = DebugHelpers.ReadStructPointer(process, ref temp).GetValueOrDefault(0);
                savedProgramCounterAddress = DebugHelpers.ReadStructPointer(process, ref temp).GetValueOrDefault(0);
            }
            else if (processData.luaVersion == 502)
            {
                DebugHelpers.SkipStructByte(process, ref temp);    // status
                DebugHelpers.SkipStructPointer(process, ref temp); // top
                DebugHelpers.SkipStructPointer(process, ref temp); // l_G
                callInfoAddress = DebugHelpers.ReadStructPointer(process, ref temp).GetValueOrDefault(0);
            }
            else if (processData.luaVersion == 503)
            {
                DebugHelpers.SkipStructShort(process, ref temp);   // nci
                DebugHelpers.SkipStructByte(process, ref temp);    // status
                DebugHelpers.SkipStructPointer(process, ref temp); // top
                DebugHelpers.SkipStructPointer(process, ref temp); // l_G
                callInfoAddress = DebugHelpers.ReadStructPointer(process, ref temp).GetValueOrDefault(0);
            }
            else if (processData.luaVersion == 504)
            {
                DebugHelpers.SkipStructByte(process, ref temp);    // status
                DebugHelpers.SkipStructByte(process, ref temp);    // allowhook
                DebugHelpers.SkipStructShort(process, ref temp);   // nci
                DebugHelpers.SkipStructPointer(process, ref temp); // top
                DebugHelpers.SkipStructPointer(process, ref temp); // l_G
                callInfoAddress = DebugHelpers.ReadStructPointer(process, ref temp).GetValueOrDefault(0);
            }

            if (callInfoAddress == 0)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = $"Failed to evaluate current Lua call frame (Lua version {processData.luaVersion})";
                return;
            }

            // Load call info data (to get base stack address)
            LuaFunctionCallInfoData callInfoData = new LuaFunctionCallInfoData();

            callInfoData.ReadFrom(process, callInfoAddress); // TODO: cache?

            callInfoData.ReadFunction(process);

            if (callInfoData.func == null)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = $"Failed to evaluate current Lua call frame function (Lua version {processData.luaVersion})";
                return;
            }

            if (callInfoData.func.extendedType != LuaExtendedType.LuaFunction)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = "Breakpoint location has to be inside a Lua function";
                return;
            }

            LuaValueDataLuaFunction currCallLuaFunction = callInfoData.func as LuaValueDataLuaFunction;

            LuaClosureData closureData = currCallLuaFunction.value;

            LuaFunctionData functionData = null;

            if (processData.functionDataCache.ContainsKey(closureData.functionAddress))
            {
                functionData = processData.functionDataCache[closureData.functionAddress];
            }
            else
            {
                functionData = closureData.ReadFunction(process);

                functionData.ReadUpvalues(process);
                functionData.ReadLocals(process, -1);

                processData.functionDataCache.Add(closureData.functionAddress, functionData);
            }

            if (!savedProgramCounterAddress.HasValue)
            {
                savedProgramCounterAddress = callInfoData.savedInstructionPointerAddress;
            }

            // Possible in bad break locations
            if (savedProgramCounterAddress < functionData.codeDataAddress)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = "Invalid saved program counter";
                return;
            }

            long currInstructionPointer = ((long)savedProgramCounterAddress - (long)functionData.codeDataAddress) / 4; // unsigned size instructions

            // If the call was already made, savedpc will be offset by 1 (return location)
            int prevInstructionPointer = currInstructionPointer == 0 ? 0 : (int)currInstructionPointer - 1;

            functionData.UpdateLocals(process, prevInstructionPointer);

            ExpressionEvaluation evaluation = new ExpressionEvaluation(process, functionData, callInfoData.stackBaseAddress, closureData);

            var result = evaluation.Evaluate(evaluationCondition.Source.Text);

            if (result as LuaValueDataError != null)
            {
                var resultAsError = result as LuaValueDataError;

                inspectionSession.Close();

                stop      = true;
                errorText = resultAsError.value;
                return;
            }

            if (result.baseType == LuaBaseType.Nil)
            {
                inspectionSession.Close();

                stop      = false;
                errorText = null;
                return;
            }

            if (result is LuaValueDataBool resultBool)
            {
                inspectionSession.Close();

                stop      = resultBool.value;
                errorText = null;
                return;
            }

            var resultNumber = result as LuaValueDataNumber;

            if (resultNumber == null)
            {
                inspectionSession.Close();

                stop      = true;
                errorText = $"Value can't be used as condition: {result.AsSimpleDisplayString(10)}";
                return;
            }

            inspectionSession.Close();

            stop      = resultNumber.value != 0.0;
            errorText = null;
        }
Esempio n. 6
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;
            }));
        }