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)); }
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 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; }
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; })); }