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;
        }
Пример #2
0
 public ExpressionEvaluation(DkmProcess process, DkmStackWalkFrame stackFrame, DkmInspectionSession inspectionSession, LuaFunctionData functionData, ulong frameBaseAddress, LuaClosureData luaClosure)
 {
     this.process           = process;
     this.stackFrame        = stackFrame;
     this.inspectionSession = inspectionSession;
     this.functionData      = functionData;
     this.frameBaseAddress  = frameBaseAddress;
     this.luaClosure        = luaClosure;
 }
Пример #3
0
        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);
        }
Пример #4
0
 public ExpressionEvaluation(DkmProcess process, LuaFunctionData functionData, ulong frameBaseAddress, LuaClosureData luaClosure)
 {
     this.process          = process;
     this.functionData     = functionData;
     this.frameBaseAddress = frameBaseAddress;
     this.luaClosure       = luaClosure;
 }