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; }
void IDkmLanguageConditionEvaluator.ParseCondition(DkmEvaluationBreakpointCondition evaluationCondition, out string errorText) { // This place could be used to typecheck of pre-compile the expression errorText = null; }