DbgEngineLocalsValueNodeInfo[] GetNodesCore(DbgEvaluationContext context, DbgStackFrame frame, DbgValueNodeEvaluationOptions options, DbgLocalsValueNodeEvaluationOptions localsOptions, CancellationToken cancellationToken) { DbgEngineLocalsValueNodeInfo[] valueNodes = null; try { var refsResult = dbgModuleReferenceProvider.GetModuleReferences(context.Runtime, frame); if (refsResult.ErrorMessage != null) { return(Array.Empty <DbgEngineLocalsValueNodeInfo>()); } var languageDebugInfo = context.TryGetLanguageDebugInfo(); if (languageDebugInfo == null) { return(Array.Empty <DbgEngineLocalsValueNodeInfo>()); } var methodDebugInfo = languageDebugInfo.MethodDebugInfo; var module = frame.Module ?? throw new InvalidOperationException(); // Since we attach this to the module, the module doesn't have to be part of Key var state = StateWithKey <GetNodesState> .GetOrCreate(module, this); var localsOptionsKey = localsOptions & ~(DbgLocalsValueNodeEvaluationOptions.ShowCompilerGeneratedVariables | DbgLocalsValueNodeEvaluationOptions.ShowDecompilerGeneratedVariables); var key = new GetNodesState.Key(methodDebugInfo.DecompilerOptionsVersion, methodDebugInfo.Method.MDToken.ToInt32(), languageDebugInfo.MethodVersion, refsResult.ModuleReferences, MethodDebugScopeUtils.GetScope(methodDebugInfo.Scope, languageDebugInfo.ILOffset), options, localsOptionsKey); var evalOptions = DbgEvaluationOptions.None; if ((options & DbgValueNodeEvaluationOptions.NoFuncEval) != 0) { evalOptions |= DbgEvaluationOptions.NoFuncEval; } ValueInfo[] valueInfos; byte[] assemblyBytes; int compilerGeneratedCount; int decompilerGeneratedCount; if (key.Equals(state.CachedKey)) { valueInfos = state.CachedValueInfos; assemblyBytes = state.CachedAssemblyBytes; decompilerGeneratedCount = state.CachedDecompilerGeneratedCount; compilerGeneratedCount = state.CachedCompilerGeneratedCount; } else { var compilationResult = expressionCompiler.CompileGetLocals(context, frame, refsResult.ModuleReferences, evalOptions, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); if (compilationResult.IsError) { return new[] { CreateInternalErrorNode(context, frame, compilationResult.ErrorMessage, cancellationToken) } } ; decompilerGeneratedCount = GetDecompilerGeneratedVariablesCount(methodDebugInfo.Scope, languageDebugInfo.ILOffset); valueInfos = new ValueInfo[compilationResult.CompiledExpressions.Length + decompilerGeneratedCount]; int valueInfosIndex = 0; compilerGeneratedCount = 0; for (int i = 0; i < compilationResult.CompiledExpressions.Length; i++, valueInfosIndex++) { if ((compilationResult.CompiledExpressions[i].ResultFlags & DbgDotNetCompiledExpressionResultFlags.CompilerGenerated) != 0) { compilerGeneratedCount++; } valueInfos[valueInfosIndex] = new CompiledExpressionValueInfo(compilationResult.CompiledExpressions, i); } if (decompilerGeneratedCount > 0) { var scope = methodDebugInfo.Scope; for (;;) { foreach (var local in scope.Locals) { if (local.IsDecompilerGenerated) { valueInfos[valueInfosIndex] = new DecompilerGeneratedVariableValueInfo(local.Name); valueInfosIndex++; } } bool found = false; foreach (var childScope in scope.Scopes) { if (childScope.Span.Start <= languageDebugInfo.ILOffset && languageDebugInfo.ILOffset < childScope.Span.End) { found = true; scope = childScope; break; } } if (!found) { break; } } } if (valueInfos.Length != valueInfosIndex) { throw new InvalidOperationException(); } assemblyBytes = compilationResult.Assembly; state.CachedKey = key; state.CachedValueInfos = valueInfos; state.CachedAssemblyBytes = assemblyBytes; state.CachedILInterpreterState = null; state.CachedDecompilerGeneratedCount = decompilerGeneratedCount; state.CachedCompilerGeneratedCount = compilerGeneratedCount; } int count = valueInfos.Length; if ((localsOptions & DbgLocalsValueNodeEvaluationOptions.ShowCompilerGeneratedVariables) == 0) { count -= compilerGeneratedCount; } if ((localsOptions & DbgLocalsValueNodeEvaluationOptions.ShowDecompilerGeneratedVariables) == 0) { count -= decompilerGeneratedCount; } valueNodes = count == 0 ? Array.Empty <DbgEngineLocalsValueNodeInfo>() : new DbgEngineLocalsValueNodeInfo[count]; var valueCreator = new DbgDotNetValueCreator(valueNodeFactory, dnILInterpreter, context, frame, options, evalOptions, assemblyBytes, cancellationToken); int w = 0; for (int i = 0; i < valueInfos.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var valueInfo = valueInfos[i]; DbgEngineLocalsValueNodeInfo valueNodeInfo; switch (valueInfo.Kind) { case ValueInfoKind.CompiledExpression: var compExpr = (CompiledExpressionValueInfo)valueInfo; if ((localsOptions & DbgLocalsValueNodeEvaluationOptions.ShowCompilerGeneratedVariables) == 0 && compExpr.IsCompilerGenerated) { continue; } valueNodeInfo = new DbgEngineLocalsValueNodeInfo( compExpr.IsParameter ? DbgLocalsValueNodeKind.Parameter : DbgLocalsValueNodeKind.Local, valueCreator.CreateValueNode(ref state.CachedILInterpreterState, ref compExpr.CompiledExpressionResult)); break; case ValueInfoKind.DecompilerGeneratedVariable: if ((localsOptions & DbgLocalsValueNodeEvaluationOptions.ShowDecompilerGeneratedVariables) == 0) { continue; } var decGen = (DecompilerGeneratedVariableValueInfo)valueInfo; valueNodeInfo = new DbgEngineLocalsValueNodeInfo(DbgLocalsValueNodeKind.Local, valueNodeFactory.CreateError(context, frame, new DbgDotNetText(new DbgDotNetTextPart(BoxedTextColor.Local, decGen.Name)), dnSpy_Debugger_DotNet_Resources.DecompilerGeneratedVariablesCanNotBeEvaluated, decGen.Name, false, cancellationToken)); break; default: throw new InvalidOperationException(); } valueNodes[w++] = valueNodeInfo; } if (w != valueNodes.Length) { throw new InvalidOperationException(); } return(valueNodes); } catch (Exception ex) { if (valueNodes != null) { frame.Process.DbgManager.Close(valueNodes.Select(a => a.ValueNode).Where(a => a != null)); } if (!ExceptionUtils.IsInternalDebuggerError(ex)) { throw; } return(new[] { CreateInternalErrorNode(context, frame, PredefinedEvaluationErrorMessages.InternalDebuggerError, cancellationToken) }); } }
DbgEngineLocalsValueNodeInfo[] GetNodesCore(DbgEvaluationInfo evalInfo, DbgValueNodeEvaluationOptions options, DbgLocalsValueNodeEvaluationOptions localsOptions) { DbgEngineLocalsValueNodeInfo[]? valueNodes = null; try { var module = evalInfo.Frame.Module; if (module is null) { return(Array.Empty <DbgEngineLocalsValueNodeInfo>()); } var languageDebugInfo = evalInfo.Context.TryGetLanguageDebugInfo(); if (languageDebugInfo is null) { return(Array.Empty <DbgEngineLocalsValueNodeInfo>()); } var methodDebugInfo = languageDebugInfo.MethodDebugInfo; // All the variables windows use the same cached module references so make sure we pass // in the same arguments so it won't get recreated every time the method gets called. var info = dbgAliasProvider.GetAliases(evalInfo); var refsResult = dbgModuleReferenceProvider.GetModuleReferences(evalInfo.Runtime, evalInfo.Frame, info.typeReferences); if (!(refsResult.ErrorMessage is null)) { return new[] { CreateInternalErrorNode(evalInfo, refsResult.ErrorMessage) } } ; Debug.Assert(!(refsResult.ModuleReferences is null)); // Since we attach this to the module, the module doesn't have to be part of Key var state = StateWithKey <GetNodesState> .GetOrCreate(module, this); var localsOptionsKey = localsOptions & ~(DbgLocalsValueNodeEvaluationOptions.ShowCompilerGeneratedVariables | DbgLocalsValueNodeEvaluationOptions.ShowDecompilerGeneratedVariables); var key = new GetNodesState.Key(methodDebugInfo.DebugInfoVersion, methodDebugInfo.Method.MDToken.ToInt32(), languageDebugInfo.MethodVersion, refsResult.ModuleReferences, MethodDebugScopeUtils.GetScope(methodDebugInfo.Scope, languageDebugInfo.ILOffset), options, localsOptionsKey); var evalOptions = DbgEvaluationOptions.None; if ((options & DbgValueNodeEvaluationOptions.NoFuncEval) != 0) { evalOptions |= DbgEvaluationOptions.NoFuncEval; } if ((localsOptions & DbgLocalsValueNodeEvaluationOptions.ShowRawLocals) != 0) { evalOptions |= DbgEvaluationOptions.RawLocals; } ValueInfo[] valueInfos; byte[] assemblyBytes; int compilerGeneratedCount; int decompilerGeneratedCount; if (key.Equals(state.CachedKey)) { valueInfos = state.CachedValueInfos; assemblyBytes = state.CachedAssemblyBytes; decompilerGeneratedCount = state.CachedDecompilerGeneratedCount; compilerGeneratedCount = state.CachedCompilerGeneratedCount; } else { var compilationResult = expressionCompiler.CompileGetLocals(evalInfo, refsResult.ModuleReferences, evalOptions); evalInfo.CancellationToken.ThrowIfCancellationRequested(); if (compilationResult.IsError) { return new[] { CreateInternalErrorNode(evalInfo, compilationResult.ErrorMessage !) }