void IDkmClrExpressionCompilerCallback.CompileDisplayAttribute( DkmLanguageExpression expression, DkmClrModuleInstance moduleInstance, int token, out string error, out DkmCompiledClrInspectionQuery result) { try { var runtimeInstance = moduleInstance.RuntimeInstance; var appDomain = moduleInstance.AppDomain; var compileResult = this.CompileWithRetry( moduleInstance, runtimeInstance.GetMetadataBlocks(appDomain), (blocks, useReferencedModulesOnly) => CreateTypeContext(appDomain, blocks, moduleInstance.Mvid, token, useReferencedModulesOnly), (context, diagnostics) => { ResultProperties unusedResultProperties; return(context.CompileExpression( expression.Text, DkmEvaluationFlags.TreatAsExpression, ImmutableArray <Alias> .Empty, diagnostics, out unusedResultProperties, testData: null)); }, out error); result = compileResult.ToQueryResult(this.CompilerId, default(ResultProperties), runtimeInstance); } catch (Exception e) when(ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
private DkmLanguageExpression AddFuncEval( DkmWorkList workList, string funcEval, Action <DkmEvaluationResult> evalResult) { Debug.Assert(workList != null && !string.IsNullOrEmpty(funcEval), "Arguments should not be null"); Debug.WriteLine($"Creating func-eval: '{funcEval}'"); // Create the evaluation to add var langExpr = DkmLanguageExpression.Create( this.inspectionContext.Language, DkmEvaluationFlags.None, funcEval, null); this.inspectionContext.EvaluateExpression( workList, langExpr, this.inspectionContext.Thread.GetTopStackFrame(), delegate(DkmEvaluateExpressionAsyncResult asyncResult) { evalResult(asyncResult.ResultObject); }); return(langExpr); }
/// <summary> /// This method is called by the debug engine to compile an expression that the user wants /// to evaluate. Before the call, we have the text of the expression and information about /// the context we want to evaluate in (code location, evaluation flags, etc.). The result /// of the call is a "query" containing IL the debugger will execute to get the /// result of the expression. /// </summary> /// <param name="expression">This is the raw expression to compile</param> /// <param name="instructionAddress">Instruction address or code location to use as the /// context of the compilation.</param> /// <param name="inspectionContext">Context of the evaluation. This contains options/flags /// to be used during compilation. It also contains the InspectionSession. The inspection /// session is the object that provides lifetime management for our objects. When the user /// steps or continues the process, the debug engine will dispose of the inspection session</param> /// <param name="error">[Out] If the there are any compile errors, this parameter is set to /// the error message to display to the user</param> /// <param name="result">[Out] If compilation was successful, this is the output query.</param> void IDkmClrExpressionCompiler.CompileExpression( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmInspectionContext inspectionContext, out string error, out DkmCompiledClrInspectionQuery result) { error = null; result = null; using (DebugCompilerContext context = ContextFactory.CreateExpressionContext(inspectionContext, instructionAddress, expression.Text)) { context.GenerateQuery(); error = context.FirstError; if (string.IsNullOrEmpty(error)) { result = DkmCompiledClrInspectionQuery.Create( instructionAddress.RuntimeInstance, null, expression.Language.Id, new ReadOnlyCollection<byte>(context.GetPeBytes()), context.ClassName, context.MethodName, new ReadOnlyCollection<string>(context.FormatSpecifiers), context.ResultFlags, DkmEvaluationResultCategory.Data, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, null); } } }
/// <summary> /// This method is called by the debug engine when the user modifies the result of a /// previous evaluation. The result of this call will be a query containing the IL code /// necessary to assign the value. /// </summary> /// <param name="expression">The text the user entered as the new value</param> /// <param name="instructionAddress">Instruction address or code location to use as the /// context of the compilation.</param> /// <param name="lValue">The L-Value of the assigment. This is a previous evaluation result.</param> /// <param name="error">[Out] If the there are any compile errors, this parameter is set to /// the error message to display to the user</param> /// <param name="result">[Out] If compilation was successful, this is the output query to /// execute to perform the assignment.</param> void IDkmClrExpressionCompiler.CompileAssignment(DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmEvaluationResult lValue, out string error, out DkmCompiledClrInspectionQuery result) { // when the user assigns a value in the debugger then this method is called. // we may want to change an expression like "{1,2,3}" to "new object[] {1,2,3}" // and "2020.12.03" to "XSharp.RT.Functions.ConDate(2020,12,03)" error = null; result = null; expression.CompileAssignment(instructionAddress, lValue, out error, out result); }
public static DkmEvaluationResult Evaluate(DkmVisualizedExpression expr, DkmEvaluationFlags flags, string text, DkmDataItem data) { using (DkmLanguageExpression vexpr = DkmLanguageExpression.Create(CppLanguage, flags, text, data)) { DkmEvaluationResult result = null; expr.EvaluateExpressionCallback(expr.InspectionContext, vexpr, expr.StackFrame, out result); return(result); } }
public DkmEvaluationResult TryEvaluate(string expr) { using (var cppExpr = DkmLanguageExpression.Create(CppLanguage, DkmEvaluationFlags.NoSideEffects, expr, null)) { DkmEvaluationResult cppEvalResult = null; var cppWorkList = DkmWorkList.Create(null); _cppInspectionContext.EvaluateExpression(cppWorkList, cppExpr, _nativeFrame, (result) => { cppEvalResult = result.ResultObject; }); cppWorkList.Execute(); return(cppEvalResult); } }
/// <summary> /// This method is called by the debug engine to compile an expression that the user wants /// to evaluate. Before the call, we have the text of the expression and information about /// the context we want to evaluate in (code location, evaluation flags, etc.). The result /// of the call is a "query" containing IL the debugger will execute to get the /// result of the expression. /// </summary> /// <param name="expression">This is the raw expression to compile</param> /// <param name="instructionAddress">Instruction address or code location to use as the /// context of the compilation.</param> /// <param name="inspectionContext">Context of the evaluation. This contains options/flags /// to be used during compilation. It also contains the InspectionSession. The inspection /// session is the object that provides lifetime management for our objects. When the user /// steps or continues the process, the debug engine will dispose of the inspection session</param> /// <param name="error">[Out] If the there are any compile errors, this parameter is set to /// the error message to display to the user</param> /// <param name="result">[Out] If compilation was successful, this is the output query.</param> void IDkmClrExpressionCompiler.CompileExpression( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmInspectionContext inspectionContext, out string error, out DkmCompiledClrInspectionQuery result) { error = null; result = null; expression.CompileExpression(instructionAddress, inspectionContext, out error, out result); return; }
internal static string ExecuteExpression(string expression, DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame input, DkmEvaluationFlags flags, bool allowZero, out ulong address) { if (Log.instance != null) { Log.instance.Verbose($"ExecuteExpression begin evaluation of '{expression}'"); } var compilerId = new DkmCompilerId(DkmVendorId.Microsoft, DkmLanguageId.Cpp); var language = DkmLanguage.Create("C++", compilerId); var languageExpression = DkmLanguageExpression.Create(language, DkmEvaluationFlags.None, expression, null); var inspectionContext = DkmInspectionContext.Create(inspectionSession, input.RuntimeInstance, thread, 200, flags, DkmFuncEvalFlags.None, 10, language, null, null, DkmCompiledVisualizationDataPriority.None, null, workerConnection); var workList = DkmWorkList.Create(null); try { string resultText = null; ulong resultAddress = 0; inspectionContext.EvaluateExpression(workList, languageExpression, input, res => { if (res.ErrorCode == 0) { var result = res.ResultObject as DkmSuccessEvaluationResult; if (result != null && result.TagValue == DkmEvaluationResult.Tag.SuccessResult && (allowZero || result.Address.Value != 0)) { resultText = result.Value; resultAddress = result.Address.Value; } res.ResultObject.Close(); } }); workList.Execute(); if (Log.instance != null) { Log.instance.Verbose($"ExecuteExpression completed"); } address = resultAddress; return(resultText); } catch (OperationCanceledException) { address = 0; return(null); } }
/// <summary> /// This method is called by the debug engine to compile an expression that the user wants /// to evaluate. Before the call, we have the text of the expression and information about /// the context we want to evaluate in (code location, evaluation flags, etc.). The result /// of the call is a "query" containing IL the debugger will execute to get the /// result of the expression. /// </summary> /// <param name="expression">This is the raw expression to compile</param> /// <param name="instructionAddress">Instruction address or code location to use as the /// context of the compilation.</param> /// <param name="inspectionContext">Context of the evaluation. This contains options/flags /// to be used during compilation. It also contains the InspectionSession. The inspection /// session is the object that provides lifetime management for our objects. When the user /// steps or continues the process, the debug engine will dispose of the inspection session</param> /// <param name="error">[Out] If the there are any compile errors, this parameter is set to /// the error message to display to the user</param> /// <param name="result">[Out] If compilation was successful, this is the output query.</param> void IDkmClrExpressionCompiler.CompileExpression( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmInspectionContext inspectionContext, out string error, out DkmCompiledClrInspectionQuery result) { error = null; result = null; bool changed = false; string originalExpr = expression.Text; // We use a trick to change the Text when sending it to C#, by retrieveing the field info. // This field has a property get but not a property set. var fi = typeof(DkmLanguageExpression).GetField("m_Text", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); if (fi != null) { var newexpr = originalExpr; if (expression.Text.StartsWith("SELF", System.StringComparison.OrdinalIgnoreCase)) { changed = true; newexpr = "this" + originalExpr.Substring(4); } else if (expression.Text.StartsWith("SUPER", System.StringComparison.OrdinalIgnoreCase)) { changed = true; newexpr = "base" + originalExpr.Substring(5); } if (newexpr.Contains(":")) { newexpr = newexpr.Replace(':', '.'); changed = true; } // check for literal array //var lbrkt = newexpr.IndexOf('['); //var rbrkt = newexpr.IndexOf(']'); //if (lbrkt > 0 && rbrkt > 0 && lbrkt < rbrkt) //{ // newexpr = AdjustArrayIndices(newexpr, ref changed); //} if (changed && fi != null) { fi.SetValue(expression, newexpr); } } expression.CompileExpression(instructionAddress, inspectionContext, out error, out result); if (changed && fi != null) { fi.SetValue(expression, originalExpr); } return; }
internal static DkmEvaluationResult ExecuteRawExpression(string expression, DkmInspectionSession inspectionSession, DkmThread thread, DkmStackWalkFrame input, DkmRuntimeInstance runtimeInstance, DkmEvaluationFlags flags) { var compilerId = new DkmCompilerId(DkmVendorId.Microsoft, DkmLanguageId.Cpp); var language = DkmLanguage.Create("C++", compilerId); var languageExpression = DkmLanguageExpression.Create(language, DkmEvaluationFlags.None, expression, null); DkmInspectionContext inspectionContext; LuaWorkerConnectionWrapper workerConnectionWrapper = inspectionSession.Process.GetDataItem <LuaWorkerConnectionWrapper>(); if (workerConnectionWrapper != null) { inspectionContext = workerConnectionWrapper.CreateInspectionSession(inspectionSession, runtimeInstance, thread, flags, language); } else { inspectionContext = DkmInspectionContext.Create(inspectionSession, runtimeInstance, thread, 200, flags, DkmFuncEvalFlags.None, 10, language, null); } var workList = DkmWorkList.Create(null); try { DkmEvaluationResult result = null; inspectionContext.EvaluateExpression(workList, languageExpression, input, res => { if (res.ErrorCode == 0) { result = res.ResultObject; } }); workList.Execute(); return(result); } catch (OperationCanceledException) { return(null); } }
private int QueryColumnCount() { int columnCount = 0; DkmLanguageExpression expr = null; try { DkmWorkList workList = DkmWorkList.Create(null); SqliteVisualizerException ex = null; expr = this.AddFuncEval( workList, $"sqlite3_column_count(*(sqlite3_stmt **){this.procMemForQuery})", (r) => { DkmSuccessEvaluationResult suc; if (!this.VerifySuccess(r, out suc)) { ex = new SqliteVisualizerException(Resources.ErrMsg_FuncEvalFailed, r.FullName); return; } columnCount = (int)suc.Address.Value; }); workList.Execute(); if (ex != null) { throw ex; } } finally { if (expr != null) { expr.Close(); } } return(columnCount); }
void IDkmClrExpressionCompiler.CompileAssignment( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmEvaluationResult lValue, out string error, out DkmCompiledClrInspectionQuery result) { try { var moduleInstance = instructionAddress.ModuleInstance; var runtimeInstance = instructionAddress.RuntimeInstance; var aliases = GetAliases(runtimeInstance, lValue.InspectionContext); // NB: Not affected by retrying. var r = this.CompileWithRetry( moduleInstance.AppDomain, runtimeInstance, (blocks, useReferencedModulesOnly) => CreateMethodContext(instructionAddress, blocks, useReferencedModulesOnly), (context, diagnostics) => { ResultProperties resultProperties; var compileResult = context.CompileAssignment( lValue.FullName, expression.Text, aliases, diagnostics, out resultProperties, testData: null); return(new CompileExpressionResult(compileResult, resultProperties)); }, out error); Debug.Assert( r.CompileResult == null && r.ResultProperties.Flags == default || (r.ResultProperties.Flags & DkmClrCompilationResultFlags.PotentialSideEffect) == DkmClrCompilationResultFlags.PotentialSideEffect); result = r.CompileResult.ToQueryResult(this.CompilerId, r.ResultProperties, runtimeInstance); } catch (Exception e) when(ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
void IDkmClrExpressionCompiler.CompileAssignment( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmEvaluationResult lValue, out string error, out DkmCompiledClrInspectionQuery result) { try { var appDomain = instructionAddress.ModuleInstance.AppDomain; var references = instructionAddress.Process.GetMetadataBlocks(appDomain); ResultProperties resultProperties; ImmutableArray <AssemblyIdentity> missingAssemblyIdentities; CompileResult compileResult; do { var context = this.CreateMethodContext(instructionAddress, references); compileResult = context.CompileAssignment( RuntimeInspectionContext.Create(lValue.InspectionContext), lValue.FullName, expression.Text, this.DiagnosticFormatter, out resultProperties, out error, out missingAssemblyIdentities, preferredUICulture: null, testData: null); } while (ShouldTryAgainWithMoreMetadataBlocks(appDomain, missingAssemblyIdentities, ref references)); Debug.Assert((resultProperties.Flags & DkmClrCompilationResultFlags.PotentialSideEffect) == DkmClrCompilationResultFlags.PotentialSideEffect); result = compileResult.ToQueryResult(this.CompilerId, resultProperties, instructionAddress.RuntimeInstance); } catch (Exception e) when(ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
void IDkmClrExpressionCompiler.CompileExpression( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmInspectionContext inspectionContext, out string error, out DkmCompiledClrInspectionQuery result) { try { var appDomain = instructionAddress.ModuleInstance.AppDomain; var references = instructionAddress.Process.GetMetadataBlocks(appDomain); ImmutableArray<AssemblyIdentity> missingAssemblyIdentities; ResultProperties resultProperties; CompileResult compileResult; do { var context = this.CreateMethodContext(instructionAddress, references); compileResult = context.CompileExpression( RuntimeInspectionContext.Create(inspectionContext), expression.Text, expression.CompilationFlags, this.DiagnosticFormatter, out resultProperties, out error, out missingAssemblyIdentities, preferredUICulture: null, testData: null); } while (ShouldTryAgainWithMoreMetadataBlocks(appDomain, missingAssemblyIdentities, ref references)); result = compileResult.ToQueryResult(this.CompilerId, resultProperties, instructionAddress.RuntimeInstance); } catch (Exception e) when (ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
void IDkmClrExpressionCompilerCallback.CompileDisplayAttribute( DkmLanguageExpression expression, DkmClrModuleInstance moduleInstance, int token, out string error, out DkmCompiledClrInspectionQuery result) { try { var appDomain = moduleInstance.AppDomain; var references = moduleInstance.Process.GetMetadataBlocks(appDomain); ResultProperties unusedResultProperties; ImmutableArray <AssemblyIdentity> missingAssemblyIdentities; CompileResult compileResult; do { var context = this.CreateTypeContext(moduleInstance, references, token); compileResult = context.CompileExpression( RuntimeInspectionContext.Empty, expression.Text, DkmEvaluationFlags.TreatAsExpression, this.DiagnosticFormatter, out unusedResultProperties, out error, out missingAssemblyIdentities, preferredUICulture: null, testData: null); } while (ShouldTryAgainWithMoreMetadataBlocks(appDomain, missingAssemblyIdentities, ref references)); result = compileResult.ToQueryResult(this.CompilerId, default(ResultProperties), moduleInstance.RuntimeInstance); } catch (Exception e) when(ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
void IDkmClrExpressionCompiler.CompileExpression( DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmInspectionContext inspectionContext, out string error, out DkmCompiledClrInspectionQuery result) { try { var moduleInstance = instructionAddress.ModuleInstance; var runtimeInstance = instructionAddress.RuntimeInstance; var runtimeInspectionContext = RuntimeInspectionContext.Create(inspectionContext); var r = this.CompileWithRetry( moduleInstance, runtimeInstance.GetMetadataBlocks(moduleInstance.AppDomain), (blocks, useReferencedModulesOnly) => CreateMethodContext(instructionAddress, blocks, useReferencedModulesOnly), (context, diagnostics) => { ResultProperties resultProperties; var compileResult = context.CompileExpression( runtimeInspectionContext, expression.Text, expression.CompilationFlags, diagnostics, out resultProperties, testData: null); return(new CompileExpressionResult(compileResult, resultProperties)); }, out error); result = r.CompileResult.ToQueryResult(this.CompilerId, r.ResultProperties, runtimeInstance); } catch (Exception e) when(ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
private void FinalizeQuery() { DkmLanguageExpression expr = null; try { SqliteVisualizerException ex = null; DkmWorkList workList = DkmWorkList.Create(null); expr = this.AddFuncEval( workList, $"sqlite3_finalize(*(sqlite3_stmt **){this.procMemForQuery})", (r) => { DkmSuccessEvaluationResult suc; if (!this.VerifySuccess(r, out suc)) { ex = new SqliteVisualizerException(Resources.ErrMsg_FuncEvalFailed, r.FullName); return; } }); workList.Execute(); if (ex != null) { throw ex; } } finally { if (expr != null) { expr.Close(); } } }
private void PrepareQuery() { DkmLanguageExpression expr = null; try { SqliteVisualizerException ex = null; DkmWorkList workList = DkmWorkList.Create(null); expr = this.AddFuncEval( workList, $"sqlite3_prepare({sqliteInstanceName}, \"{query}\", {query.Length + 1}, (sqlite3_stmt **){this.procMemForQuery}, nullptr)", (r) => { DkmSuccessEvaluationResult suc; if (!this.VerifySuccess(r, out suc)) { ex = new SqliteVisualizerException(Resources.ErrMsg_PrepareFailed, r.FullName); return; } }); workList.Execute(); if (ex != null) { throw ex; } } finally { if (expr != null) { expr.Close(); } } }
/// <summary> /// Tries to evaluate the given expression by treating it as a chain of member access and indexing operations (e.g. <c>fob[0].oar.baz['abc'].blah</c>), /// and looking up the corresponding members in data model provided by <see cref="GetFrameLocals"/>. /// </summary> /// <param name="vars">List of variables, in the context of which the expression is evaluated.</param> /// <returns> /// <c>true</c> if evaluation was successful, or if it failed and no fallback is possible (e.g. expression is invalid). /// <c>false</c> if evaluation was not successful due to the limitations of this evaluator, and it may be possible to evaluate it correctly by other means. /// </returns> private bool EvaluateExpressionByWalkingObjects(IEnumerable<DkmSuccessEvaluationResult> vars, DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine<DkmEvaluateExpressionAsyncResult> completionRoutine) { var pyrtInfo = stackFrame.Thread.Process.GetPythonRuntimeInfo(); var parserOptions = new ParserOptions { ErrorSink = new StringErrorSink() }; var parser = Parser.CreateParser(new StringReader(expression.Text), pyrtInfo.LanguageVersion, parserOptions); var expr = ((ReturnStatement)parser.ParseTopExpression().Body).Expression; string errorText = parserOptions.ErrorSink.ToString(); if (!string.IsNullOrEmpty(errorText)) { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, errorText, DkmEvaluationResultFlags.Invalid, null))); return true; } // Unroll the AST into a sequence of member access and indexing operations, if possible. var path = new Stack<string>(); var reprBuilder = new ReprBuilder(new ReprOptions(stackFrame.Thread.Process)); while (true) { var memberExpr = expr as MemberExpression; if (memberExpr != null) { path.Push(memberExpr.Name); expr = memberExpr.Target; continue; } var indexingExpr = expr as IndexExpression; if (indexingExpr != null) { var indexExpr = indexingExpr.Index as ConstantExpression; if (indexExpr != null) { reprBuilder.Clear(); reprBuilder.AppendFormat("[{0:PY}]", indexExpr.Value); path.Push(reprBuilder.ToString()); expr = indexingExpr.Target; continue; } } break; } var varExpr = expr as NameExpression; if (varExpr == null) { return false; } path.Push(varExpr.Name); // Walk the path through Locals while (true) { var name = path.Pop(); var evalResult = vars.FirstOrDefault(er => er.Name == name); if (evalResult == null) { return false; } if (path.Count == 0) { // Clone the evaluation result, but use expression text as its name. DkmDataItem dataItem = (DkmDataItem)evalResult.GetDataItem<PyObjectEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<GlobalsEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<CppViewEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<RawEvaluationResult>(); evalResult = DkmSuccessEvaluationResult.Create( evalResult.InspectionContext, evalResult.StackFrame, expression.Text, expression.Text, evalResult.Flags, evalResult.Value, evalResult.EditableValue, evalResult.Type, evalResult.Category, evalResult.Access, evalResult.StorageType, evalResult.TypeModifierFlags, evalResult.Address, evalResult.CustomUIVisualizers, evalResult.ExternalModules, dataItem); completionRoutine(new DkmEvaluateExpressionAsyncResult(evalResult)); return true; } var childWorkList = DkmWorkList.Create(null); evalResult.GetChildren(childWorkList, 0, inspectionContext, getChildrenResult => getChildrenResult.EnumContext.GetItems(childWorkList, 0, int.MaxValue, getItemsResult => vars = getItemsResult.Items.OfType<DkmSuccessEvaluationResult>())); childWorkList.Execute(); } }
private bool TryGetRow(out string[] row) { // Move to the next row bool moreRows = false; var exprs = new List <DkmLanguageExpression>(); try { const int SQLITE_ROW = 100; SqliteVisualizerException ex = null; DkmWorkList workList = DkmWorkList.Create(null); DkmLanguageExpression expr = this.AddFuncEval( workList, $"sqlite3_step(*(sqlite3_stmt **){this.procMemForQuery})", (r) => { DkmSuccessEvaluationResult suc; if (!this.VerifySuccess(r, out suc)) { ex = new SqliteVisualizerException(Resources.ErrMsg_FuncEvalFailed, r.FullName); return; } moreRows = SQLITE_ROW == (int)suc.Address.Value; }); exprs.Add(expr); workList.Execute(); if (ex != null) { throw ex; } } finally { foreach (var e in exprs) { e.Close(); } exprs.Clear(); } if (!moreRows) { row = new string[0]; return(false); } // Read each column in the row var rowLocal = new string[ColumnNames.Count()]; try { SqliteVisualizerException ex = null; DkmProcess process = this.inspectionContext.Thread.Process; DkmWorkList workList = DkmWorkList.Create(null); for (int i = 0; i < rowLocal.Length; i++) { var i_local = i; var e = this.AddFuncEval( workList, $"sqlite3_column_text(*(sqlite3_stmt **){this.procMemForQuery}, {i})", (r) => { DkmSuccessEvaluationResult suc; if (!this.VerifySuccess(r, out suc)) { ex = ex ?? new SqliteVisualizerException(Resources.ErrMsg_FuncEvalFailed, r.FullName); return; } ulong address = suc.Address.Value; byte[] stringMaybe = process.ReadMemoryString(address, DkmReadMemoryFlags.None, 1, 1024); int len = stringMaybe.Length; if (len > 0) { // The debugger null terminates all strings, but encoding doesn't strip null when creating a string len--; rowLocal[i_local] = Encoding.UTF8.GetString(stringMaybe, 0, len); } }); exprs.Add(e); } workList.Execute(); if (ex != null) { throw ex; } } finally { foreach (var e in exprs) { e.Close(); } } row = rowLocal; return(true); }
public void EvaluateExpression(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine<DkmEvaluateExpressionAsyncResult> completionRoutine) { var name = expression.Text; GetFrameLocals(inspectionContext, workList, stackFrame, getFrameLocalsResult => { getFrameLocalsResult.EnumContext.GetItems(workList, 0, int.MaxValue, localGetItemsResult => { var vars = localGetItemsResult.Items.OfType<DkmSuccessEvaluationResult>(); var globals = vars.FirstOrDefault(er => er.Name == "[Globals]"); if (globals == null) { if (!EvaluateExpressionByWalkingObjects(vars, inspectionContext, workList, expression, stackFrame, completionRoutine)) { EvaluateExpressionViaInterpreter(inspectionContext, workList, expression, stackFrame, completionRoutine); } } else { globals.GetChildren(workList, 0, inspectionContext, globalsGetChildrenResult => { globalsGetChildrenResult.EnumContext.GetItems(workList, 0, int.MaxValue, globalsGetItemsResult => { vars = vars.Concat(globalsGetItemsResult.Items.OfType<DkmSuccessEvaluationResult>()); if (!EvaluateExpressionByWalkingObjects(vars, inspectionContext, workList, expression, stackFrame, completionRoutine)) { EvaluateExpressionViaInterpreter(inspectionContext, workList, expression, stackFrame, completionRoutine); } }); }); } }); }); }
/// <summary> /// This method is called by the debug engine when the user modifies the result of a /// previous evaluation. The result of this call will be a query containing the IL code /// necessary to assign the value. /// </summary> /// <param name="expression">The text the user entered as the new value</param> /// <param name="instructionAddress">Instruction address or code location to use as the /// context of the compilation.</param> /// <param name="lValue">The L-Value of the assigment. This is a previous evaluation result.</param> /// <param name="error">[Out] If the there are any compile errors, this parameter is set to /// the error message to display to the user</param> /// <param name="result">[Out] If compilation was successful, this is the output query to /// execute to perform the assignment.</param> void IDkmClrExpressionCompiler.CompileAssignment(DkmLanguageExpression expression, DkmClrInstructionAddress instructionAddress, DkmEvaluationResult lValue, out string error, out DkmCompiledClrInspectionQuery result) { error = null; result = null; expression.CompileAssignment(instructionAddress, lValue, out error, out result); }
void IDkmClrExpressionCompilerCallback.CompileDisplayAttribute( DkmLanguageExpression expression, DkmClrModuleInstance moduleInstance, int token, out string error, out DkmCompiledClrInspectionQuery result) { try { var appDomain = moduleInstance.AppDomain; var references = moduleInstance.Process.GetMetadataBlocks(appDomain); ResultProperties unusedResultProperties; ImmutableArray<AssemblyIdentity> missingAssemblyIdentities; CompileResult compileResult; do { var context = this.CreateTypeContext(moduleInstance, references, token); compileResult = context.CompileExpression( RuntimeInspectionContext.Empty, expression.Text, DkmEvaluationFlags.TreatAsExpression, this.DiagnosticFormatter, out unusedResultProperties, out error, out missingAssemblyIdentities, preferredUICulture: null, testData: null); } while (ShouldTryAgainWithMoreMetadataBlocks(appDomain, missingAssemblyIdentities, ref references)); result = compileResult.ToQueryResult(this.CompilerId, default(ResultProperties), moduleInstance.RuntimeInstance); } catch (Exception e) when (ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Returns child elements of previous evaluation. /// </summary> public void GetItems(DkmVisualizedExpression visualizedExpression, DkmEvaluationResultEnumContext enumContext, int startIndex, int count, out DkmChildVisualizedExpression[] items) { // Check if we want to use passthrough visualizer PassThroughVisualizer passThroughVisualizer = enumContext.GetDataItem <PassThroughVisualizer>(); if (passThroughVisualizer != null) { passThroughVisualizer.GetItems(visualizedExpression, enumContext, startIndex, count, out items); return; } // Execute our regular visualizer VSCustomVisualizerEvaluator evaluator = visualizedExpression.GetDataItem <VSCustomVisualizerEvaluator>(); IResultVisualizer[] itemsAsResults = evaluator.ResultVisualizer.Children.Skip(startIndex).Take(count).ToArray(); items = new DkmChildVisualizedExpression[itemsAsResults.Length]; for (int i = 0; i < items.Length; i++) { IResultVisualizer item = itemsAsResults[i]; DkmEvaluationResultCategory category; switch (item.DataType) { case CompletionDataType.Class: category = DkmEvaluationResultCategory.Class; break; case CompletionDataType.Property: case CompletionDataType.StaticProperty: category = DkmEvaluationResultCategory.Property; break; case CompletionDataType.Event: category = DkmEvaluationResultCategory.Event; break; case CompletionDataType.Method: category = DkmEvaluationResultCategory.Method; break; case CompletionDataType.Enum: case CompletionDataType.EnumValue: case CompletionDataType.Keyword: case CompletionDataType.Namespace: case CompletionDataType.StaticClass: case CompletionDataType.StaticEvent: case CompletionDataType.StaticMethod: case CompletionDataType.StaticVariable: case CompletionDataType.Unknown: case CompletionDataType.Variable: default: category = DkmEvaluationResultCategory.Data; break; } DkmExpressionValueHome valueHome = visualizedExpression.ValueHome; ulong address = 0; string fullName = string.Empty; string typeName = null; try { if (item.Value is Variable variable) { address = variable.GetPointerAddress(); typeName = variable.GetCodeType().Name; fullName = $"*(({typeName}*)0x{address:X})"; valueHome = DkmPointerValueHome.Create(address); } } catch { } DkmEvaluationResult result; DkmDataItem dataItem = null; if (item.ShouldForceDefaultVisualizer && !string.IsNullOrEmpty(fullName)) { using (DkmLanguageExpression languageExpression = DkmLanguageExpression.Create(visualizedExpression.InspectionContext.Language, DkmEvaluationFlags.TreatAsExpression, fullName, null)) { visualizedExpression.EvaluateExpressionCallback(visualizedExpression.InspectionContext, languageExpression, visualizedExpression.StackFrame, out result); } if (result is DkmSuccessEvaluationResult successResult) { dataItem = new PassThroughVisualizer(successResult); result = DkmSuccessEvaluationResult.Create( successResult.InspectionContext, successResult.StackFrame, item.Name, // Name - Left column successResult.FullName, successResult.Flags, successResult.Value, // Value - Middle column successResult.EditableValue, successResult.Type, // Type - Right column category, successResult.Access, successResult.StorageType, successResult.TypeModifierFlags, successResult.Address, successResult.CustomUIVisualizers, successResult.ExternalModules, successResult.RefreshButtonText, dataItem); } } else { result = DkmSuccessEvaluationResult.Create( visualizedExpression.InspectionContext, visualizedExpression.StackFrame, item.Name, // Name - Left column fullName, // FullName - What is being copied when "Add to watch" DkmEvaluationResultFlags.ReadOnly | (item.IsExpandable ? DkmEvaluationResultFlags.Expandable : DkmEvaluationResultFlags.None), item.ValueString, // Value - Middle column "", item.Type ?? "", // Type - Right column category, DkmEvaluationResultAccessType.None, DkmEvaluationResultStorageType.None, DkmEvaluationResultTypeModifierFlags.None, null, VSUIVisualizerService.GetUIVisualizers(item), null, null); dataItem = new VSCustomVisualizerEvaluator(result, item); } items[i] = DkmChildVisualizedExpression.Create( visualizedExpression.InspectionContext, visualizedExpression.VisualizerId, visualizedExpression.SourceId, visualizedExpression.StackFrame, valueHome, result, visualizedExpression, (uint)(startIndex + i), dataItem); } }
private void EvaluateExpressionViaInterpreter(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine<DkmEvaluateExpressionAsyncResult> completionRoutine) { var thread = stackFrame.Thread; var process = thread.Process; if (_evalLoopThreadId.Read() != (ulong)thread.SystemPart.Id) { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, "Arbitrary Python expressions can only be evaluated on a thread which is stopped in Python code at a breakpoint or " + "after a step-in or a step-over operation. Only expressions involving global and local variables, object field access, " + "and indexing of built-in collection types with literals can be evaluated in the current context.", DkmEvaluationResultFlags.Invalid, null))); return; } var pythonFrame = PyFrameObject.TryCreate(stackFrame); if (pythonFrame == null) { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, "Could not obtain a Python frame object for the current frame.", DkmEvaluationResultFlags.Invalid, null))); return; } byte[] input = Encoding.UTF8.GetBytes(expression.Text + "\0"); if (input.Length > ExpressionEvaluationBufferSize) { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, "Expression is too long.", DkmEvaluationResultFlags.Invalid, null))); return; } _evalLoopFrame.Write(pythonFrame.Address); process.WriteMemory(_evalLoopInput.Address, input); bool timedOut; using (_evalCompleteEvent = new AutoResetEvent(false)) { thread.BeginFuncEvalExecution(DkmFuncEvalFlags.None); timedOut = !_evalCompleteEvent.WaitOne(ExpressionEvaluationTimeout); _evalCompleteEvent = null; } if (timedOut) { new RemoteComponent.AbortingEvalExecutionRequest().SendLower(process); // We need to stop the process before we can report end of func eval completion using (_evalAbortedEvent = new AutoResetEvent(false)) { process.AsyncBreak(false); if (!_evalAbortedEvent.WaitOne(20000)) { // This is a catastrophic error, since we can't report func eval completion unless we can stop the process, // and VS will hang until we do report completion. At this point we can only kill the debuggee so that the // VS at least gets back to a reasonable state. _evalAbortedEvent = null; process.Terminate(1); completionRoutine(DkmEvaluateExpressionAsyncResult.CreateErrorResult(new Exception("Couldn't abort a failed expression evaluation."))); return; } _evalAbortedEvent = null; } completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, "Evaluation timed out.", DkmEvaluationResultFlags.Invalid, null))); return; } ulong objPtr = _evalLoopResult.Read(); var obj = PyObject.FromAddress(process, objPtr); var exc_type = PyObject.FromAddress(process, _evalLoopExcType.Read()); var exc_value = PyObject.FromAddress(process, _evalLoopExcValue.Read()); var exc_str = (PyObject.FromAddress(process, _evalLoopExcStr.Read()) as IPyBaseStringObject).ToStringOrNull(); var sehCode = _evalLoopSEHCode.Read(); if (obj != null) { var cppEval = new CppExpressionEvaluator(inspectionContext, stackFrame); var pyEvalResult = new PythonEvaluationResult(obj, expression.Text) { Flags = DkmEvaluationResultFlags.SideEffect }; var evalResult = CreatePyObjectEvaluationResult(inspectionContext, stackFrame, null, pyEvalResult, cppEval, null, hasCppView: true, isOwned: true); _evalLoopResult.Write(0); // don't let the eval loop decref the object - we will do it ourselves later, when eval result is closed completionRoutine(new DkmEvaluateExpressionAsyncResult(evalResult)); } else if (sehCode != 0) { string errorText = string.Format("Structured exception {0:x08} ", sehCode); if (Enum.IsDefined(typeof(EXCEPTION_CODE), sehCode)) { errorText += "(" + (EXCEPTION_CODE)sehCode + ") "; } errorText += "raised while evaluating expression"; completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, errorText, DkmEvaluationResultFlags.Invalid, null))); } else if (exc_type != null) { string typeName; var typeObject = exc_type as PyTypeObject; if (typeObject != null) { typeName = typeObject.tp_name.Read().ReadUnicode(); } else { typeName = "<unknown exception type>"; } completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, typeName + " raised while evaluating expression: " + exc_str, DkmEvaluationResultFlags.Invalid, null))); } else { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, "Unknown error occurred while evaluating expression.", DkmEvaluationResultFlags.Invalid, null))); } }
public void EvaluateVisualizedExpression(DkmVisualizedExpression visualizedExpression, out DkmEvaluationResult resultObject) { var rootExpr = visualizedExpression as DkmRootVisualizedExpression; if (rootExpr == null) { Debug.Fail("PythonViewNativeVisualizer.EvaluateVisualizedExpression was given a visualized expression that is not a DkmRootVisualizedExpression."); throw new NotSupportedException(); } DkmEvaluationResult rawResult; RawEvaluationResultHolder rawResultHolder; using (var rawExpr = DkmLanguageExpression.Create(CppExpressionEvaluator.CppLanguage, DkmEvaluationFlags.ShowValueRaw, rootExpr.FullName + ",!", null)) { rootExpr.EvaluateExpressionCallback(rootExpr.InspectionContext, rawExpr, rootExpr.StackFrame, out rawResult); rawResultHolder = new RawEvaluationResultHolder { RawResult = rawResult }; rootExpr.SetDataItem(DkmDataCreationDisposition.CreateAlways, rawResultHolder); } var rawSuccessResult = rawResult as DkmSuccessEvaluationResult; if (rawSuccessResult != null) { resultObject = DkmSuccessEvaluationResult.Create( rawResult.InspectionContext, rawResult.StackFrame, rootExpr.Name, rawSuccessResult.FullName, rawSuccessResult.Flags, rawSuccessResult.Value, rawSuccessResult.EditableValue, rawSuccessResult.Type, rawSuccessResult.Category, rawSuccessResult.Access, rawSuccessResult.StorageType, rawSuccessResult.TypeModifierFlags, rawSuccessResult.Address, rawSuccessResult.CustomUIVisualizers, rawSuccessResult.ExternalModules, rawResultHolder); return; } var rawFailedResult = rawResult as DkmFailedEvaluationResult; if (rawFailedResult != null) { resultObject = DkmFailedEvaluationResult.Create( rawResult.InspectionContext, rawResult.StackFrame, rootExpr.Name, rootExpr.FullName, rawFailedResult.ErrorMessage, rawFailedResult.Flags, rawResultHolder); return; } Debug.Fail("Raw evaluation result was neither DkmSuccessEvaluationResult nor DkmFailedEvaluationResult."); throw new NotSupportedException(); }
void IDkmLanguageExpressionEvaluator.EvaluateExpression(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine <DkmEvaluateExpressionAsyncResult> completionRoutine) { if (stackFrame.RuntimeInstance.Id.RuntimeType != Guids.PythonRuntimeTypeGuid) { Debug.Fail("EvaluateExpression called on a non-Python frame."); throw new NotSupportedException(); } var ee = stackFrame.Process.GetDataItem <ExpressionEvaluator>(); if (ee == null) { Debug.Fail("EvaluateExpression called, but no instance of ExpressionEvaluator exists in this DkmProcess to handle it."); throw new InvalidOperationException(); } ee.EvaluateExpression(inspectionContext, workList, expression, stackFrame, completionRoutine); }
private static DkmLanguageExpression CppExpression(string expression) { return(DkmLanguageExpression.Create(CppLanguage, DkmEvaluationFlags.None, expression, null)); }