bool IDkmRuntimeStepper.OwnsCurrentExecutionLocation(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); // Can't handle steps without an address if (stepper.StartingAddress == null) { return(false); } // Stepping can be performed if we are inside the debug helper or inside luaV_execute var instructionAddress = stepper.StartingAddress.CPUInstructionPart.InstructionPointer; if (processData.locations == null) { return(false); } if (instructionAddress >= processData.locations.helperStartAddress && instructionAddress < processData.locations.helperEndAddress) { return(true); } if (instructionAddress >= processData.locations.executionStartAddress && instructionAddress < processData.locations.executionEndAddress) { return(true); } return(false); }
void IDkmRuntimeMonitorBreakpointHandler.EnableRuntimeBreakpoint(DkmRuntimeBreakpoint runtimeBreakpoint) { var process = runtimeBreakpoint.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process); var runtimeInstructionBreakpoint = runtimeBreakpoint as DkmRuntimeInstructionBreakpoint; if (runtimeInstructionBreakpoint != null) { var customInstructionAddress = runtimeInstructionBreakpoint.InstructionAddress as DkmCustomInstructionAddress; if (customInstructionAddress != null) { LuaAddressEntityData entityData = new LuaAddressEntityData(); entityData.ReadFrom(customInstructionAddress.EntityId.ToArray()); var breakpoint = new LuaBreakpoint { source = entityData.source, line = entityData.line, functionAddress = entityData.functionAddress, runtimeBreakpoint = runtimeBreakpoint }; processData.activeBreakpoints.Add(breakpoint); UpdateBreakpoints(process, processData); } } }
void IDkmRuntimeStepper.TakeStepControl(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, bool leaveGuardsInPlace, DkmStepArbitrationReason reason, DkmRuntimeInstance callingRuntimeInstance) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); ClearStepperData(process, processData); }
void IDkmRuntimeStepper.OnNewControllingRuntimeInstance(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason, DkmRuntimeInstance controllingRuntimeInstance) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); ClearStepperData(process, processData); }
void IDkmRuntimeStepper.StopStep(DkmRuntimeInstance runtimeInstance, DkmStepper stepper) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); ClearStepperData(process, processData); }
internal static DkmEvaluationResult GetLuaFunctionChildAtIndex(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame, string fullName, LuaClosureData value, int index) { var process = stackFrame.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaLocalProcessData>(process); if (index == 0) { if (value == null) { return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "null", DkmEvaluationResultFlags.Invalid, null)); } var functionData = value.ReadFunction(process); if (functionData == null) { return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "[internal error: failed to read Proto]", DkmEvaluationResultFlags.Invalid, null)); } string source = functionData.ReadSource(process); if (source == null) { return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "[internal error: failed to read source]", DkmEvaluationResultFlags.Invalid, null)); } int line = functionData.definitionStartLine_opt; DkmEvaluationResultCategory category = DkmEvaluationResultCategory.Method; DkmEvaluationResultTypeModifierFlags typeModifiers = DkmEvaluationResultTypeModifierFlags.None; DkmEvaluationResultAccessType access = DkmEvaluationResultAccessType.Public; DkmEvaluationResultStorageType storage = DkmEvaluationResultStorageType.Global; LuaAddressEntityData entityData = new LuaAddressEntityData { source = source, line = line, functionAddress = 0, functionInstructionPointer = 0, }; var entityDataBytes = entityData.Encode(); DkmInstructionAddress instructionAddress = DkmCustomInstructionAddress.Create(processData.runtimeInstance, processData.moduleInstance, entityDataBytes, (ulong)((line << 16) + 0), null, null); DkmDataAddress dataAddress = DkmDataAddress.Create(processData.runtimeInstance, value.functionAddress, instructionAddress); return(DkmSuccessEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Address, $"{source}:{line}", null, "Proto*", category, access, storage, typeModifiers, dataAddress, null, null, null)); } Debug.Assert(false, "Invalid child index"); return(null); }
void IDkmRuntimeStepper.Step(DkmRuntimeInstance runtimeInstance, DkmStepper stepper, DkmStepArbitrationReason reason) { var process = runtimeInstance.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(runtimeInstance.Process); if (stepper.StepKind == DkmStepKind.StepIntoSpecific) { throw new NotSupportedException(); } if (processData.activeStepper != null) { processData.activeStepper.CancelStepper(processData.runtimeInstance); processData.activeStepper = null; } if (stepper.StepKind == DkmStepKind.Over) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOverAddress, 1); } else if (stepper.StepKind == DkmStepKind.Into) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOverAddress, 1); DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepIntoAddress, 1); } else if (stepper.StepKind == DkmStepKind.Out) { DebugHelpers.TryWriteIntVariable(process, processData.locations.helperStepOutAddress, 1); } processData.activeStepper = stepper; processData.hadActiveStepper = true; UpdateHooks(process, processData); }
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; }
DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage) { var process = customMessage.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process); if (customMessage.MessageCode == MessageToRemote.createRuntime) { if (processData.language == null) { processData.compilerId = new DkmCompilerId(Guids.luaCompilerGuid, Guids.luaLanguageGuid); processData.language = DkmLanguage.Create("Lua", processData.compilerId); } if (processData.runtimeInstance == null) { DkmRuntimeInstanceId runtimeId = new DkmRuntimeInstanceId(Guids.luaRuntimeGuid, 0); processData.runtimeInstance = DkmCustomRuntimeInstance.Create(process, runtimeId, null); } if (processData.module == null) { DkmModuleId moduleId = new DkmModuleId(Guid.NewGuid(), Guids.luaSymbolProviderGuid); processData.module = DkmModule.Create(moduleId, "lua.vm.code", processData.compilerId, process.Connection, null); } if (processData.moduleInstance == null) { DkmDynamicSymbolFileId symbolFileId = DkmDynamicSymbolFileId.Create(Guids.luaSymbolProviderGuid); processData.moduleInstance = DkmCustomModuleInstance.Create("lua_vm", "lua.vm.code", 0, processData.runtimeInstance, null, symbolFileId, DkmModuleFlags.None, DkmModuleMemoryLayout.Unknown, 0, 1, 0, "Lua vm code", false, null, null, null); processData.moduleInstance.SetModule(processData.module, true); // Can use reload? } } else if (customMessage.MessageCode == MessageToRemote.luaHelperDataLocations) { var data = new HelperLocationsMessage(); data.ReadFrom(customMessage.Parameter1 as byte[]); processData.locations = data; } else if (customMessage.MessageCode == MessageToRemote.pauseBreakpoints) { processData.pauseBreakpoints = true; } else if (customMessage.MessageCode == MessageToRemote.resumeBreakpoints) { processData.pauseBreakpoints = false; } else if (customMessage.MessageCode == MessageToRemote.luaVersionInfo) { processData.luaVersion = (customMessage.Parameter1 as int?).GetValueOrDefault(0); LuaHelpers.luaVersion = processData.luaVersion; } else if (customMessage.MessageCode == MessageToRemote.registerLuaState) { var data = new RegisterStateMessage(); data.ReadFrom(customMessage.Parameter1 as byte[]); Debug.Assert(processData.knownStates.ContainsKey(data.stateAddress) == false); if (processData.knownStates.ContainsKey(data.stateAddress)) { Debug.WriteLine("IDkmCustomMessageForwardReceiver.SendLower() Duplicate Lua state registration, destruction was probably missed!"); } else { processData.knownStates.Add(data.stateAddress, data); if (processData.hooksEnabled) { SetupHooks(process, processData); } } } else if (customMessage.MessageCode == MessageToRemote.unregisterLuaState) { var data = new UnregisterStateMessage(); data.ReadFrom(customMessage.Parameter1 as byte[]); // Registration is called only for states that can be hooked, unregistration is always called if (processData.knownStates.ContainsKey(data.stateAddress)) { processData.knownStates.Remove(data.stateAddress); } } return(null); }
void IDkmRuntimeBreakpointReceived.OnRuntimeBreakpointReceived(DkmRuntimeBreakpoint runtimeBreakpoint, DkmThread thread, bool hasException, DkmEventDescriptorS eventDescriptor) { var process = thread.Process; var processData = DebugHelpers.GetOrCreateDataItem <LuaRemoteProcessData>(process); if (runtimeBreakpoint.SourceId == Guids.luaSupportBreakpointGuid) { if (processData.locations != null) { if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperBreakpointHit) { // Breakpoint can get hit again after expression evaluation 'slips' the thread if (processData.pauseBreakpoints) { return; } eventDescriptor.Suppress(); var breakpointPos = DebugHelpers.ReadUintVariable(process, processData.locations.helperBreakHitIdAddress); if (!breakpointPos.HasValue) { return; } if (breakpointPos.Value < processData.activeBreakpoints.Count) { try { var breakpoint = processData.activeBreakpoints[(int)breakpointPos.Value]; if (breakpoint.runtimeBreakpoint != null) { breakpoint.runtimeBreakpoint.OnHit(thread, false); } } catch (System.ObjectDisposedException) { // Breakpoint was implicitly closed processData.activeBreakpoints.RemoveAt((int)breakpointPos.Value); } catch (DkmException) { // In case another component evaluates a function } } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepComplete) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepInto) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } else if (runtimeBreakpoint.UniqueId == processData.locations.breakpointLuaHelperStepOut) { if (processData.activeStepper != null) { var activeStepper = processData.activeStepper; ClearStepperData(process, processData); activeStepper.OnStepComplete(thread, false); } return; } } thread.GetCurrentFrameInfo(out ulong retAddr, out ulong frameBase, out ulong vframe); var data = new SupportBreakpointHitMessage { breakpointId = runtimeBreakpoint.UniqueId, threadId = thread.UniqueId, retAddr = retAddr, frameBase = frameBase, vframe = vframe }; var message = DkmCustomMessage.Create(process.Connection, process, MessageToLocal.guid, MessageToLocal.luaSupportBreakpointHit, data.Encode(), null); var response = message.SendHigher(); if (response?.MessageCode == MessageToRemote.throwException) { if (runtimeBreakpoint is DkmRuntimeInstructionBreakpoint runtimeInstructionBreakpoint) { var exceptionInformation = DkmCustomExceptionInformation.Create(processData.runtimeInstance, Guids.luaExceptionGuid, thread, runtimeInstructionBreakpoint.InstructionAddress, "LuaError", 0, DkmExceptionProcessingStage.Thrown | DkmExceptionProcessingStage.UserVisible | DkmExceptionProcessingStage.Unhandled, null, new ReadOnlyCollection <byte>(response.Parameter1 as byte[])); exceptionInformation.OnDebugMonitorException(); } } } }