public async Task Build_ArrayCapsAtArraySizeAsync() { IVariableInformation varInfo = CreateVarInfo(_remoteValue, "10"); string result = await ValueStringBuilder.BuildAsync(varInfo); Assert.That(result, Is.EqualTo("{20, 21, 22, 23, 24}")); }
async Task InitAsync() { if (_initialized) { return; } _initialized = true; if (string.IsNullOrWhiteSpace(_smartPointerItem?.Value) || !NatvisViewsUtil.IsViewVisible(_variable.FormatSpecifier, _smartPointerItem.IncludeView, _smartPointerItem.ExcludeView)) { _adapter = _fallbackAdapter; return; } try { IVariableInformation expandInfo = await _evaluator.EvaluateExpressionAsync( _smartPointerItem.Value, _variable, _natvisScope, null); _adapter = expandInfo.GetChildAdapter(); } catch (ExpressionEvaluationFailed ex) { NatvisErrorUtils.LogExpandChildrenValidationError( NatvisLoggingLevel.WARNING, _logger, "<SmartPointer>", _variable.TypeName, ex.Message); _adapter = _fallbackAdapter; } }
/// <summary> /// Checks whether we are dealing with a pointer or not. /// For pointers, it assignes values as Native Visual Studio would do. /// If we have a pointer to a struct, it calls ExtractChildren(), /// since the childValue is an empty string. /// </summary> static async Task <string> UnwrapPointerValueAsync(IVariableInformation varInfo, int charactersLeft) { string value = await varInfo.ValueAsync(); if (!varInfo.IsPointer) { return(value); } // For pointers, the assignment value is equal to the memory address and the // value is the content stored at that location. string plainValue = varInfo.AssignmentValue; string memoryAddress = varInfo.GetMemoryAddressAsHex(); string addressPrefix = FormatSpecifierUtil.SuppressMemoryAddress(varInfo.FormatSpecifier) ? "" : memoryAddress + " "; if (value != "" && plainValue != value) { return(addressPrefix + value); } if (varInfo.IsNullPointer()) { return(addressPrefix + "<NULL>"); } return(addressPrefix + await FormatChildrenListAsync( varInfo, charactersLeft - $"{addressPrefix}{{}}".Length, "???")); }
public async Task Build_ArraySpecifiedNumberOfChildrenAsync() { IVariableInformation varInfo = CreateVarInfo(_remoteValue, "3"); string result = await ValueStringBuilder.BuildAsync(varInfo); Assert.That(result, Is.EqualTo("{20, 21, 22}")); }
async Task StoreNodeAndGetNextAsync() { if (_nodeError != null) { _store.SaveVariable(_lastIndex, _nodeError); } else if (_node.IsNullPointer()) { if (_sizeDefined) { int size = _store.ChildrenCount; _logger.Warning("<LinkedListItems> declared a size of " + $"{size} but only {_lastIndex} item(s) found."); _nodeError = new ErrorVariableInformation( "<Error>", $"Size declared as {size} but only {_lastIndex} item(s) found."); } else { _nodeError = new ErrorVariableInformation( "<Error>", $"Item {_lastIndex} is out of bound."); } _store.SaveVariable(_lastIndex, _nodeError); } else { _store.SaveVariable(_lastIndex, await GetDisplayVariableAsync(_lastIndex, _node)); _node = await GetNextAsync(_node); } _lastIndex++; }
public async Task CloneContextVariablesAsync(string expr, string transformedExpr, string expectedValue) { RemoteValueFake remoteValue = RemoteValueFakeUtil.CreateClass("MyType", "myType", "myValue"); RemoteValueFake exprResult = RemoteValueFakeUtil.CreateSimpleInt("x", 1); exprResult.SetClone(RemoteValueFakeUtil.CreateSimpleInt("y", 2)); remoteValue.AddValueFromExpression(transformedExpr, exprResult); IVariableInformation varInfo = _varInfoFactory.Create(remoteValue); var natvisScope = new NatvisScope(); natvisScope.AddScopedName("$i", "1U"); natvisScope.AddScopedName("var", "$var_0"); natvisScope.AddContextVariable("$var_0", exprResult); IVariableInformation result = await _evaluator.EvaluateExpressionAsync(expr, varInfo, natvisScope, "myVar"); Assert.That(await result.ValueAsync(), Is.EqualTo(expectedValue)); Assert.That(result.DisplayName, Is.EqualTo("myVar")); }
public void DeclareVariableWithErrorRemoteValue() { RemoteValueFake remoteValue = RemoteValueFakeUtil.CreateClass("MyType", "myType", "myValue"); remoteValue.AddValueFromExpression($"auto $test=5; $test", RemoteValueFakeUtil.CreateError("declaration error")); var natvisScope = new NatvisScope(); natvisScope.AddScopedName("test", "$test"); IVariableInformation varInfo = _varInfoFactory.Create(remoteValue); var exception = Assert.ThrowsAsync <ExpressionEvaluationFailed>( async() => await _evaluator.DeclareVariableAsync(varInfo, "test", "5", natvisScope)); Assert.That(exception.Message, Does.Contain("test")); Assert.That(exception.Message, Does.Contain("5")); Assert.That(exception.Message, Does.Contain("declaration error")); string logOutput = _nLogSpy.GetOutput(); Assert.That(logOutput, Does.Contain("test")); Assert.That(logOutput, Does.Contain("5")); Assert.That(logOutput, Does.Contain("declaration error")); }
public void GetPropertyInfoPointerValueEqualsAssignmentValue() { IVariableInformation mockVarInfoChild = Substitute.For <IVariableInformation>(); mockVarInfoChild.AssignmentValue.Returns("1"); mockVarInfoChild.ValueAsync().Returns("1"); mockVarInfoChild.GetCachedView().Returns(mockVarInfoChild); mockVarInfo.Error.Returns(false); mockVarInfo.MightHaveChildren().Returns(true); mockVarInfo.IsPointer.Returns(true); mockVarInfo.AssignmentValue.Returns("0xDEADBEEF"); mockVarInfo.ValueAsync().Returns("0xDEADBEEF"); mockVarInfo.GetMemoryAddressAsHex().Returns("0xDEADBEEF"); mockVarInfo.GetChildAdapter() .Returns(new ListChildAdapter.Factory().Create(new List <IVariableInformation>() { mockVarInfoChild })); DEBUG_PROPERTY_INFO propertyInfo; // Display both the pointer value and the value representation. GetPropertyInfo( enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE | enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE_AUTOEXPAND, out propertyInfo); Assert.That(propertyInfo.bstrValue, Is.EqualTo("0xDEADBEEF {1}")); // Display only the pointer. GetPropertyInfo(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_VALUE, out propertyInfo); Assert.That(propertyInfo.bstrValue, Is.EqualTo("0xDEADBEEF")); }
public static void AsyncErrorImpl(EngineCallback engineCallback, IVariableInformation var, IDebugProperty2 error) { Task.Run(() => { engineCallback.OnExpressionEvaluationComplete(var, error); }); }
/// <summary> /// Evaluates an LLDB expression. It decides which expression evaluation method to use /// (e.g. LLDB, lldb-eval, path expression, etc.) depending on the Stadia SDK settings and /// the input |expression|. It doesn't support format specifiers, only expressions that /// can be directly evaluated in the LLDB environment. /// </summary> /// <param name="expression">The expression to be evaluated.</param> /// <param name="variable">The evaluation context.</param> /// <param name="natvisScope">The Natvis tokens to be resolved before evaluation.</param> /// <param name="displayName">The display name given to the result. If null the underlying /// debugger's context specific name is used.</param> /// <returns>The expression result.</returns> async Task <IVariableInformation> EvaluateLldbExpressionAsync(VsExpression expression, IVariableInformation variable, NatvisScope natvisScope, string displayName) { ExpressionEvaluationStrategy strategy = _extensionOptions.ExpressionEvaluationStrategy; var stepsRecorder = new ExpressionEvaluationRecorder.StepsRecorder(_timeSource); long startTimestampUs = _timeSource.GetTimestampUs(); IVariableInformation variableInformation = await EvaluateLldbExpressionWithMetricsAsync( expression, variable, natvisScope, displayName, strategy, stepsRecorder); // Evaluating a context variable will just return the reference to it. Because of // deferred evaluation of display values, some values could be incorrectly displayed // (in the case a context variable was changed in between two expression evaluations). // In order to prevent this, we create a copy of result if the expression was simply // a context variable. if (natvisScope.IsContextVariable(expression.Value)) { variableInformation = variableInformation.Clone(expression.FormatSpecifier); } long endTimestampUs = _timeSource.GetTimestampUs(); _expressionEvaluationRecorder.Record(strategy, ExpressionEvaluationContext.VALUE, stepsRecorder, startTimestampUs, endTimestampUs, variable.Id); return(variableInformation); }
private Traverse GetTraverse(string direction, IVariableInformation node) { Traverse go; var val = node.FindChildByName(direction); if (val == null) { return(null); } if (val.TypeName == node.TypeName) { go = (v) => v.FindChildByName(direction); } else { go = (v) => { ulong addr = MICore.Debugger.ParseAddr(v.Value); if (addr != 0) { var next = v.FindChildByName(direction); next = new VariableInformation("(" + v.TypeName + ")" + next.Value, next, _process.Engine, ""); next.SyncEval(); return(next); } return(null); }; } return(go); }
private VisualizerInfo FindType(IVariableInformation variable) { if (variable is VisualizerWrapper) { return(((VisualizerWrapper)variable).Visualizer); } if (_vizCache.ContainsKey(variable.TypeName)) { return(_vizCache[variable.TypeName]); } TypeName parsedName = TypeName.Parse(variable.TypeName); IVariableInformation var = variable; while (parsedName != null) { var visualizer = Scan(parsedName, variable); if (visualizer == null && (parsedName.BaseName.EndsWith("*", StringComparison.Ordinal) || parsedName.BaseName.EndsWith("&", StringComparison.Ordinal))) { parsedName.BaseName = parsedName.BaseName.Substring(0, parsedName.BaseName.Length - 1); visualizer = Scan(parsedName, variable); } if (visualizer != null) { return(visualizer); } var = FindBaseClass(var); // TODO: handle more than one base class? if (var == null) { break; } parsedName = TypeName.Parse(var.TypeName); } return(null); }
private void TraverseList(IVariableInformation root, Traverse goNext, Traverse getValue, List <IVariableInformation> content, uint size, bool noValueInRoot) { uint i = 0; IVariableInformation node = root; ulong rootAddr = MICore.Debugger.ParseAddr(node.Value); ulong nextAddr = rootAddr; while (node != null && nextAddr != 0 && i < size) { if (!noValueInRoot || nextAddr != rootAddr) { IVariableInformation value = getValue(node); if (value != null) { content.Add(new SimpleWrapper("[" + i + "]", _process.Engine, value)); i++; } } if (i < size) { node = goNext(node); } nextAddr = MICore.Debugger.ParseAddr(node.Value); if (nextAddr == rootAddr) { // circular link, exit the loop break; } } }
public RightExpressionGivenParameter( ITypeInformation targetType, IVariableInformation symbolinformation, string expression = null) { this.TargetType = targetType; this.SymbolInformation = symbolinformation; this.Expression = expression; }
internal IVariableInformation[] Expand(IVariableInformation variable) { try { variable.EnsureChildren(); if (variable.IsVisualized) { return(ExpandVisualized(variable)); } IVariableInformation visView = GetVisualizationWrapper(variable); if (visView == null) { return(variable.Children); } List <IVariableInformation> children = new List <IVariableInformation>(); children.Add(visView); Array.ForEach(variable.Children, (c) => children.Add(c)); return(children.ToArray()); } catch (Exception e) { Logger.WriteLine("natvis Expand: " + e.Message); // TODO: add telemetry return(variable.Children); } }
public override async Task <IList <IVariableInformation> > GetChildrenAsync( int from, int count) { await InitAsync(); var result = new List <IVariableInformation>(); if (_store.ValidationError != null) { result.Add(_store.ValidationError); return(result.GetRange(from, count)); } for (int index = from; index < from + count; index++) { IVariableInformation varInfo = await _store.GetOrEvaluateAsync( index, async i => await _evaluator.GetExpressionValueOrErrorAsync( $"({_valuePointer.Value})[{i}]", _variable, _natvisScope, $"[{i}]", "ArrayItems")); result.Add(varInfo); } return(result); }
public async Task <EvaluationResult> EvaluateExpressionAsync() { VsExpression vsExpression = await _vsExpressionCreator.CreateAsync(_text, EvaluateSizeSpecifierExpressionAsync); IDebugProperty2 result; if (vsExpression.Value.StartsWith(".")) { EvaluateCommand(vsExpression.Value, out result); return(EvaluationResult.FromResult(result)); } RemoteValue remoteValue = await CreateValueFromExpressionAsync(vsExpression.Value); if (remoteValue == null) { return(EvaluationResult.Fail()); } string displayName = vsExpression.ToString(); IVariableInformation varInfo = _varInfoBuilder.Create(remoteValue, displayName, vsExpression.FormatSpecifier); result = _createPropertyDelegate.Invoke(varInfo); return(EvaluationResult.FromResult(result)); }
public UnsupportedNatvisEntity(IVariableInformation variable, Type entityType, NatvisDiagnosticLogger logger) { _variable = variable; _entityType = entityType; _logger = logger; }
public async Task GetChildrenReturnsMoreElementWhenMoreThanRangeSizeRequestedAsync() { remoteValue.AddChild(RemoteValueFakeUtil.CreateSimpleString("child5", "value5")); int _countPerRange = 2; var childAdapter = new RemoteValueChildAdapter.Factory().CreateForTesting( remoteValue, RemoteValueFormat.Default, varInfoBuilder, noFormatSpecifier, _countPerRange); IList <IVariableInformation> children = await childAdapter.GetChildrenAsync(0, 5); Assert.That(children.Count, Is.EqualTo(3)); Assert.That(children[2].DisplayName, Is.EqualTo("[More]")); IVariableInformation more = children[2]; CollectionAssert.AreEqual(new[] { "child3", "child4", "[More]" }, await GetAllChildNamesAsync(more.GetChildAdapter())); IVariableInformation nextMore = (await more.GetChildAdapter().GetChildrenAsync(2, 1))[0]; CollectionAssert.AreEqual(new[] { "child5" }, await GetAllChildNamesAsync(nextMore.GetChildAdapter())); }
// TODO: handle the situation when raw and expand formatter are both present public virtual IVariableInformation Create( RemoteValue remoteValue, string displayName = null, FormatSpecifier formatSpecifier = null, CustomVisualizer customVisualizer = CustomVisualizer.None) { IVariableInformation varInfo = _varInfoFactory.Create(remoteValue, displayName, formatSpecifier, customVisualizer); // Don't use Natvis for raw format specifier (!), e.g. "myvar,!". if (FormatSpecifierUtil.HasRawFormatSpecifier(varInfo.FormatSpecifier)) { return(new CachingVariableInformation(varInfo)); } var natvisVarInfo = new NatvisVariableInformation(_natvisExpander, varInfo); if (ExpandFormatSpecifierUtil.TryParseExpandFormatSpecifier( natvisVarInfo.FormatSpecifier, out int expandedIndex)) { return(new CachingVariableInformation( _expandVariableFactory.Create(natvisVarInfo, expandedIndex))); } return(new CachingVariableInformation(natvisVarInfo)); }
/// <summary> /// Returns a context value containing StringElements constructed from the TElement types /// that get found, plus a SmartPointerElement if the corresponding SmartPointerType is /// present, and the Natvis tokens to resolve in expressions involving those. /// </summary> FormatStringContext BuildFormatStringContext <TElement>( IVariableInformation variable, Func <TElement, IStringElement> stringElementConstructor) where TElement : class { VisualizerInfo visualizer = _visualizerScanner.FindType(variable); if (visualizer?.Visualizer.Items == null) { return(new FormatStringContext()); } object[] items = visualizer.Visualizer.Items; IEnumerable <IStringElement> stringElements = items.OfType <TElement>().Select(e => stringElementConstructor((TElement)e)); // Fall back to the smart pointee. stringElements = stringElements.Concat( items.OfType <SmartPointerType>() .Take(1) .Where(e => !string.IsNullOrWhiteSpace(e.Value)) .Select(e => new SmartPointerStringElement(e))); return(new FormatStringContext { StringElements = stringElements, NatvisScope = visualizer.NatvisScope }); }
internal IVariableInformation[] Expand(IVariableInformation variable) { try { variable.EnsureChildren(); if (variable.IsVisualized || ((ShowDisplayStrings == DisplayStringsState.On) && !(variable is VisualizerWrapper))) // visualize right away if DisplayStringsState.On, but only if not dummy var ([Raw View]) { return(ExpandVisualized(variable)); } IVariableInformation visView = GetVisualizationWrapper(variable); if (visView == null) { return(variable.Children); } List <IVariableInformation> children = new List <IVariableInformation>(); children.Add(visView); children.AddRange(variable.Children); return(children.ToArray()); } catch (Exception e) { _process.Logger.WriteLine("natvis Expand: " + e.Message); // TODO: add telemetry return(variable.Children); } }
/// <summary> /// Tries to resolve the given expression assuming it is a member of the given variable. If /// the expression is not a member of the given variable, null is returned. Otherwise, a /// variable resulting from evaluating the expression is returned. /// </summary> IVariableInformation GetValueForMemberAccessExpression(IVariableInformation variable, VsExpression vsExpression, string displayName) { if (!vsExpression.Value.StartsWith("[")) { vsExpression = vsExpression.Clone((variable.IsPointer ? "->" : ".") + vsExpression.Value); } if (!NatvisTextMatcher.IsExpressionPath(vsExpression.Value)) { return(null); } var value = variable.GetValueForExpressionPath(vsExpression); if (value == null || value.Error) { return(null); } if (displayName != null) { return(new NamedVariableInformation(value, displayName)); } return(value); }
DebugProperty(ITaskExecutor taskExecutor, IChildrenProviderFactory childrenProviderFactory, IVariableInformationEnumFactory varInfoEnumFactory, IVariableInformation varInfo, DebugCodeContext.Factory codeContextFactory, VsExpressionCreator vsExpressionCreator) : base( taskExecutor, childrenProviderFactory, varInfoEnumFactory, varInfo, codeContextFactory, vsExpressionCreator) { }
protected LeafEntity(IVariableInformation variable, NatvisDiagnosticLogger logger, NatvisExpressionEvaluator evaluator, NatvisScope natvisScope) { _variable = variable; _logger = logger; _evaluator = evaluator; _natvisScope = natvisScope; }
private string GetExpressionValue(string expression, IVariableInformation variable, IDictionary <string, string> scopedNames) { string processedExpr = ReplaceNamesInExpression(expression, variable, scopedNames); IVariableInformation expressionVariable = new VariableInformation(processedExpr, variable, _process.Engine, null); expressionVariable.SyncEval(); return(FormatDisplayString(expressionVariable)); }
internal VariableInformation(string expr, VariableInformation parent) { Name = expr; _parent = parent; _ctx = parent._ctx; _engine = parent._engine; Client = parent.Client; }
public static async Task <IVariableInformation[]> GetAllChildrenAsync( this IVariableInformation varInfo) { IChildAdapter childAdapter = varInfo.GetChildAdapter(); return((await childAdapter.GetChildrenAsync(0, await childAdapter.CountChildrenAsync())) .ToArray()); }
/// <summary> /// Replace child field names in the expression with the childs full expression. /// Then evaluate the new expression. /// </summary> /// <param name="expression"></param> /// <param name="variable"></param> /// <returns></returns> private IVariableInformation GetExpression(string expression, IVariableInformation variable, IDictionary <string, string> scopedNames, string displayName = null) { string processedExpr = ReplaceNamesInExpression(expression, variable, scopedNames); IVariableInformation expressionVariable = new VariableInformation(processedExpr, variable, _process.Engine, displayName); expressionVariable.SyncEval(); return(expressionVariable); }
/// <summary> /// Returns false if |variable| does not have a Natvis visualizer or the visualizer defines /// IncludeView/ExcludeView attributes and the view should be hidden based on /// |variable.FormatSpecifier|. Returns true in all other cases. /// </summary> internal bool IsTypeViewVisible(IVariableInformation variable) { VisualizerType visualizer = VisualizerScanner.FindType(variable)?.Visualizer; return(visualizer != null && NatvisViewsUtil.IsViewVisible(variable.FormatSpecifier, visualizer.IncludeView, visualizer.ExcludeView)); }
// This method evaluates the expression synchronously. int IDebugExpression2.EvaluateSync(enum_EVALFLAGS dwFlags, uint dwTimeout, IDebugEventCallback2 pExprCallback, out IDebugProperty2 ppResult) { ppResult = null; if ((dwFlags & enum_EVALFLAGS.EVAL_NOSIDEEFFECTS) != 0 && _var.IsVisualized) { IVariableInformation variable = _engine.DebuggedProcess.Natvis.Cache.Lookup(_var); if (variable == null) { ppResult = new AD7ErrorProperty(_var.Name, ResourceStrings.NoSideEffectsVisualizerMessage); } else { _var = variable; ppResult = new AD7Property(_engine, _var); } return Constants.S_OK; } _var.SyncEval(); ppResult = new AD7Property(_engine, _var); return Constants.S_OK; }
// This method evaluates the expression asynchronously. // This method should return immediately after it has started the expression evaluation. // When the expression is successfully evaluated, an IDebugExpressionEvaluationCompleteEvent2 // must be sent to the IDebugEventCallback2 event callback // // This is primarily used for the immediate window int IDebugExpression2.EvaluateAsync(enum_EVALFLAGS dwFlags, IDebugEventCallback2 pExprCallback) { if (((dwFlags & enum_EVALFLAGS.EVAL_NOSIDEEFFECTS) != 0 && (dwFlags & enum_EVALFLAGS.EVAL_ALLOWBPS) == 0) && _var.IsVisualized) { IVariableInformation variable = DebuggedProcess.g_Process.Natvis.Cache.Lookup(_var); if (variable == null) { _var.AsyncError(pExprCallback, new AD7ErrorProperty(_var.Name, ResourceStrings.NoSideEffectsVisualizerMessage)); } else { _var = variable; // use the old value Task.Run(() => { new EngineCallback(DebuggedProcess.g_Process.Engine, pExprCallback).OnExpressionEvaluationComplete(variable); }); } } else { _var.AsyncEval(pExprCallback); } return Constants.S_OK; }
public void OnExpressionEvaluationComplete(IVariableInformation var, IDebugProperty2 prop = null) { AD7ExpressionCompleteEvent eventObject = new AD7ExpressionCompleteEvent(_engine, var, prop); Send(eventObject, AD7ExpressionCompleteEvent.IID, var.Client); }
public AD7ExpressionCompleteEvent(AD7Engine engine, IVariableInformation var, IDebugProperty2 prop = null) { _engine = engine; _var = var; _prop = prop; }
private void TraverseTree(IVariableInformation root, Traverse goLeft, Traverse goRight, Traverse getValue, List<IVariableInformation> content, uint size) { uint i = 0; var nodes = new Stack<Node>(); nodes.Push(new Node(root)); while (nodes.Count > 0 && i < size) { switch (nodes.Peek().State) { case Node.ScanState.left: nodes.Peek().State = Node.ScanState.value; var leftVal = goLeft(nodes.Peek().Content); if (leftVal != null) { ulong left = MICore.Debugger.ParseAddr(leftVal.Value); if (left != 0) { nodes.Push(new Node(leftVal)); } } break; case Node.ScanState.value: nodes.Peek().State = Node.ScanState.right; IVariableInformation value = getValue(nodes.Peek().Content); if (value != null) { content.Add(new SimpleWrapper("[" + i + "]", _process.Engine, value)); i++; } break; case Node.ScanState.right: Node n = nodes.Pop(); var rightVal = goRight(n.Content); if (rightVal != null) { ulong right = MICore.Debugger.ParseAddr(rightVal.Value); if (right != 0) { nodes.Push(new Node(rightVal)); } } break; } } }
private void TraverseList(IVariableInformation root, Traverse goNext, Traverse getValue, List<IVariableInformation> content, uint size, bool noValueInRoot) { uint i = 0; IVariableInformation node = root; ulong rootAddr = MICore.Debugger.ParseAddr(node.Value); ulong nextAddr = rootAddr; while (node != null && nextAddr != 0 && i < size) { if (!noValueInRoot || nextAddr != rootAddr) { IVariableInformation value = getValue(node); if (value != null) { content.Add(new SimpleWrapper("[" + i + "]", _process.Engine, value)); i++; } } if (i < size) { node = goNext(node); } nextAddr = MICore.Debugger.ParseAddr(node.Value); if (nextAddr == rootAddr) { // circular link, exit the loop break; } } }
private VisualizerInfo Scan(TypeName name, IVariableInformation variable) { int aliasChain = 0; tryAgain: foreach (var autoVis in _typeVisualizers) { var visualizer = autoVis.Visualizers.Find((v) => v.ParsedName.Match(name)); // TODO: match on View, version, etc if (visualizer != null) { _vizCache[variable.TypeName] = new VisualizerInfo(visualizer.Visualizer, name); return _vizCache[variable.TypeName]; } } // failed to find a visualizer for the type, try looking for a typedef foreach (var autoVis in _typeVisualizers) { var alias = autoVis.Aliases.Find((v) => v.ParsedName.Match(name)); // TODO: match on View, version, etc if (alias != null) { // add the template parameter macro values var scopedNames = new Dictionary<string, string>(); int t = 1; for (int i = 0; i < name.Qualifiers.Count; ++i) { for (int j = 0; j < name.Qualifiers[i].Args.Count; ++j) { scopedNames["$T" + t] = name.Qualifiers[i].Args[j].FullyQualifiedName; t++; } } string newName = ReplaceNamesInExpression(alias.Alias.Value, null, scopedNames); name = TypeName.Parse(newName); aliasChain++; if (aliasChain > MAX_ALIAS_CHAIN) { break; } goto tryAgain; } } return null; }
public Node(IVariableInformation v) { Content = v; State = ScanState.left; }
public AD7ExpressionCompleteEvent(IVariableInformation var, IDebugProperty2 prop = null) { _var = var; _prop = prop; }
/// <summary> /// Replace child field names in the expression with the childs full expression. /// Then evaluate the new expression. /// </summary> /// <param name="expression"></param> /// <param name="variable"></param> /// <returns></returns> private IVariableInformation GetExpression(string expression, IVariableInformation variable, IDictionary<string, string> scopedNames, string displayName = null) { string processedExpr = ReplaceNamesInExpression(expression, variable, scopedNames); IVariableInformation expressionVariable = new VariableInformation(processedExpr, variable, _process.Engine, displayName); expressionVariable.SyncEval(); return expressionVariable; }
private string GetExpressionValue(string expression, IVariableInformation variable, IDictionary<string, string> scopedNames) { string processedExpr = ReplaceNamesInExpression(expression, variable, scopedNames); IVariableInformation expressionVariable = new VariableInformation(processedExpr, variable, _process.Engine, null); expressionVariable.SyncEval(); return FormatDisplayString(expressionVariable); }
private string FormatValue(string format, IVariableInformation variable, IDictionary<string, string> scopedNames) { if (String.IsNullOrWhiteSpace(format)) { return String.Empty; } StringBuilder value = new StringBuilder(); for (int i = 0; i < format.Length; ++i) { if (format[i] == '{') { if (i + 1 < format.Length && format[i + 1] == '{') { value.Append('{'); i++; continue; } // start of expression Match m = s_expression.Match(format.Substring(i)); if (m.Success) { string exprValue = GetExpressionValue(format.Substring(i + 1, m.Length - 2), variable, scopedNames); value.Append(exprValue); i += m.Length - 1; } } else if (format[i] == '}') { if (i + 1 < format.Length && format[i + 1] == '}') { value.Append('}'); i++; continue; } // error, unmatched closing brace return variable.Value; // TODO: return an error indication } else { value.Append(format[i]); } } return value.ToString(); }
internal string FormatDisplayString(IVariableInformation variable) { try { _depth++; if (_depth < MAX_FORMAT_DEPTH) { if (!(variable is VisualizerWrapper) && //no displaystring for dummy vars ([Raw View]) (ShowDisplayStrings == DisplayStringsState.On || (ShowDisplayStrings == DisplayStringsState.ForVisualizedItems && variable.IsVisualized))) { VisualizerInfo visualizer = FindType(variable); if (visualizer == null) { return variable.Value; } Cache.Add(variable); // vizualized value has been displayed foreach (var item in visualizer.Visualizer.Items) { if (item is DisplayStringType) { DisplayStringType display = item as DisplayStringType; // e.g. <DisplayString>{{ size={_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst} }}</DisplayString> if (!EvalCondition(display.Condition, variable, visualizer.ScopedNames)) { continue; } return FormatValue(display.Value, variable, visualizer.ScopedNames); } } } } } catch (Exception e) { // don't allow natvis to mess up debugging // eat any exceptions and return the variable's value Logger.WriteLine("natvis FormatDisplayString: " + e.Message); } finally { _depth--; } return variable.Value; }
internal AD7Expression(IVariableInformation var) { _var = var; }
public AD7Property(AD7Engine engine, IVariableInformation vi) { _engine = engine; _variableInformation = vi; }
public VisualizerWrapper(string name, AD7Engine engine, IVariableInformation underlyingVariable, Natvis.VisualizerInfo viz, bool isVisualizerView) : base(name, engine, underlyingVariable) { Visualizer = viz; _isVisualizerView = isVisualizerView; }
public AD7Property(IVariableInformation vi) { _variableInformation = vi; }
private string ReplaceNamesInExpression(string expression, IVariableInformation variable, IDictionary<string, string> scopedNames) { return ProcessNamesInString(expression, new Substitute[] { (m)=> { // finds children of this structure and sub's in the fullname of the child IVariableInformation var = variable == null ? null : variable.FindChildByName(m.Value); if (var != null) // found a child { return "(" + var.FullName() + ")"; } return null; }, (m)=> { // replaces the '$Tx' with actual template parameter string res; if (scopedNames != null && scopedNames.TryGetValue(m.Value, out res)) { return res; } return null; }}); }
private Traverse GetTraverse(string direction, IVariableInformation node) { Traverse go; var val = node.FindChildByName(direction); if (val == null) { return null; } if (val.TypeName == node.TypeName) { go = (v) => v.FindChildByName(direction); } else { go = (v) => { ulong addr = MICore.Debugger.ParseAddr(v.Value); if (addr != 0) { var next = v.FindChildByName(direction); next = new VariableInformation("(" + v.TypeName + ")" + next.Value, next, _process.Engine, ""); next.SyncEval(); return next; } return null; }; } return go; }
private bool EvalCondition(string condition, IVariableInformation variable, IDictionary<string, string> scopedNames) { bool res = true; if (!String.IsNullOrWhiteSpace(condition)) { string exprValue = GetExpressionValue(condition, variable, scopedNames); res = !String.IsNullOrEmpty(exprValue) && (exprValue == "true"); } return res; }
private IVariableInformation GetVisualizationWrapper(IVariableInformation variable) { VisualizerInfo visualizer = FindType(variable); if (visualizer == null || variable is VisualizerWrapper) // don't stack wrappers { return null; } ExpandType1 expandType = (ExpandType1)Array.Find(visualizer.Visualizer.Items, (o) => { return o is ExpandType1; }); if (expandType == null) { return null; } // return expansion with [Visualizer View] child as first element return new VisualizerWrapper(ResourceStrings.VisualizedView, _process.Engine, variable, visualizer, isVisualizerView: true); }
public SimpleWrapper(string name, AD7Engine engine, IVariableInformation underlyingVariable) { Parent = underlyingVariable; Name = name; _engine = engine; }
private IVariableInformation[] ExpandVisualized(IVariableInformation variable) { VisualizerInfo visualizer = FindType(variable); if (visualizer == null) { return variable.Children; } List<IVariableInformation> children = new List<IVariableInformation>(); ExpandType1 expandType = (ExpandType1)Array.Find(visualizer.Visualizer.Items, (o) => { return o is ExpandType1; }); if (expandType == null) { return variable.Children; } foreach (var i in expandType.Items) { if (i is ItemType) { ItemType item = (ItemType)i; if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) { continue; } IVariableInformation expr = GetExpression(item.Value, variable, visualizer.ScopedNames, item.Name); children.Add(expr); } else if (i is ArrayItemsType) { ArrayItemsType item = (ArrayItemsType)i; if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) { continue; } uint size = 0; string val = GetExpressionValue(item.Size, variable, visualizer.ScopedNames); size = MICore.Debugger.ParseUint(val, throwOnError: true); size = size > MAX_EXPAND ? MAX_EXPAND : size; // limit expansion ValuePointerType[] vptrs = item.ValuePointer; foreach (var vp in vptrs) { if (EvalCondition(vp.Condition, variable, visualizer.ScopedNames)) { IVariableInformation ptrExpr = GetExpression('*' + vp.Value, variable, visualizer.ScopedNames); string typename = ptrExpr.TypeName; if (String.IsNullOrWhiteSpace(typename)) { continue; } StringBuilder arrayBuilder = new StringBuilder(); arrayBuilder.Append('('); arrayBuilder.Append(typename); arrayBuilder.Append('['); arrayBuilder.Append(size); arrayBuilder.Append("])*("); arrayBuilder.Append(vp.Value); arrayBuilder.Append(')'); string arrayStr = arrayBuilder.ToString(); IVariableInformation arrayExpr = GetExpression(arrayStr, variable, visualizer.ScopedNames); arrayExpr.EnsureChildren(); if (arrayExpr.CountChildren != 0) { children.AddRange(arrayExpr.Children); } break; } } } else if (i is TreeItemsType) { TreeItemsType item = (TreeItemsType)i; if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) { continue; } if (String.IsNullOrWhiteSpace(item.Size) || String.IsNullOrWhiteSpace(item.HeadPointer) || String.IsNullOrWhiteSpace(item.LeftPointer) || String.IsNullOrWhiteSpace(item.RightPointer)) { continue; } if (item.ValueNode == null || String.IsNullOrWhiteSpace(item.ValueNode.Value)) { continue; } string val = GetExpressionValue(item.Size, variable, visualizer.ScopedNames); uint size = MICore.Debugger.ParseUint(val, throwOnError: true); size = size > MAX_EXPAND ? MAX_EXPAND : size; // limit expansion IVariableInformation headVal = GetExpression(item.HeadPointer, variable, visualizer.ScopedNames); ulong head = MICore.Debugger.ParseAddr(headVal.Value); var content = new List<IVariableInformation>(); if (head != 0 && size != 0) { headVal.EnsureChildren(); Traverse goLeft = GetTraverse(item.LeftPointer, headVal); Traverse goRight = GetTraverse(item.RightPointer, headVal); Traverse getValue = null; if (item.ValueNode.Value == "this") // TODO: handle condition { getValue = (v) => v; } else if (headVal.FindChildByName(item.ValueNode.Value) != null) { getValue = (v) => v.FindChildByName(item.ValueNode.Value); } if (goLeft == null || goRight == null || getValue == null) { continue; } TraverseTree(headVal, goLeft, goRight, getValue, children, size); } } else if (i is LinkedListItemsType) { // example: // <LinkedListItems> // <Size>m_nElements</Size> -- optional, will go until NextPoint is 0 or == HeadPointer // <HeadPointer>m_pHead</HeadPointer> // <NextPointer>m_pNext</NextPointer> // <ValueNode>m_element</ValueNode> // </LinkedListItems> LinkedListItemsType item = (LinkedListItemsType)i; if (String.IsNullOrWhiteSpace(item.Condition)) { if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) continue; } if (String.IsNullOrWhiteSpace(item.HeadPointer) || String.IsNullOrWhiteSpace(item.NextPointer)) { continue; } if (String.IsNullOrWhiteSpace(item.ValueNode)) { continue; } uint size = MAX_EXPAND; if (!String.IsNullOrWhiteSpace(item.Size)) { string val = GetExpressionValue(item.Size, variable, visualizer.ScopedNames); size = MICore.Debugger.ParseUint(val); size = size > MAX_EXPAND ? MAX_EXPAND : size; // limit expansion } IVariableInformation headVal = GetExpression(item.HeadPointer, variable, visualizer.ScopedNames); ulong head = MICore.Debugger.ParseAddr(headVal.Value); var content = new List<IVariableInformation>(); if (head != 0 && size != 0) { headVal.EnsureChildren(); Traverse goNext = GetTraverse(item.NextPointer, headVal); Traverse getValue = null; if (item.ValueNode == "this") { getValue = (v) => v; } else if (headVal.FindChildByName(item.ValueNode) != null) { getValue = (v) => v.FindChildByName(item.ValueNode); } else { var value = GetExpression(item.ValueNode, headVal, visualizer.ScopedNames); if (value != null && !value.Error) { getValue = (v) => GetExpression(item.ValueNode, v, visualizer.ScopedNames); } } if (goNext == null || getValue == null) { continue; } TraverseList(headVal, goNext, getValue, children, size, item.NoValueHeadPointer); } } else if (i is IndexListItemsType) { // example: // <IndexListItems> // <Size>_M_vector._M_index</Size> // <ValueNode>*(_M_vector._M_array[$i])</ValueNode> // </IndexListItems> IndexListItemsType item = (IndexListItemsType)i; if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) { continue; } var sizes = item.Size; uint size = 0; if (sizes == null) { continue; } foreach (var s in sizes) { if (string.IsNullOrWhiteSpace(s.Value)) continue; if (EvalCondition(s.Condition, variable, visualizer.ScopedNames)) { string val = GetExpressionValue(s.Value, variable, visualizer.ScopedNames); size = MICore.Debugger.ParseUint(val); size = size > MAX_EXPAND ? MAX_EXPAND : size; // limit expansion break; } } var values = item.ValueNode; if (values == null) { continue; } foreach (var v in values) { if (string.IsNullOrWhiteSpace(v.Value)) continue; if (EvalCondition(v.Condition, variable, visualizer.ScopedNames)) { string processedExpr = ReplaceNamesInExpression(v.Value, variable, visualizer.ScopedNames); Dictionary<string, string> indexDic = new Dictionary<string, string>(); for (uint index = 0; index < size; ++index) { indexDic["$i"] = index.ToString(CultureInfo.InvariantCulture); string finalExpr = ReplaceNamesInExpression(processedExpr, null, indexDic); IVariableInformation expressionVariable = new VariableInformation(finalExpr, variable, _process.Engine, "[" + indexDic["$i"] + "]"); expressionVariable.SyncEval(); children.Add(expressionVariable); } break; } } } else if (i is ExpandedItemType) { ExpandedItemType item = (ExpandedItemType)i; // example: // <Type Name="std::auto_ptr<*>"> // <DisplayString>auto_ptr {*_Myptr}</DisplayString> // <Expand> // <ExpandedItem>_Myptr</ExpandedItem> // </Expand> // </Type> if (item.Condition != null) { if (!EvalCondition(item.Condition, variable, visualizer.ScopedNames)) { continue; } } if (String.IsNullOrWhiteSpace(item.Value)) { continue; } var expand = GetExpression(item.Value, variable, visualizer.ScopedNames); var eChildren = Expand(expand); if (eChildren != null) { children.AddRange(eChildren); } } } if (!(variable is VisualizerWrapper)) // don't stack wrappers { // add the [Raw View] field IVariableInformation rawView = new VisualizerWrapper(ResourceStrings.RawView, _process.Engine, variable, visualizer, isVisualizerView: false); children.Add(rawView); } return children.ToArray(); }
internal AD7Expression(AD7Engine engine, IVariableInformation var) { _engine = engine; _var = var; }
private IVariableInformation FindBaseClass(IVariableInformation variable) { variable.EnsureChildren(); if (variable.Children != null) { return Array.Find(variable.Children, (c) => c.VariableNodeType == VariableInformation.NodeType.BaseClass); } return null; }
private VisualizerInfo FindType(IVariableInformation variable) { if (variable is VisualizerWrapper) { return ((VisualizerWrapper)variable).Visualizer; } if (_vizCache.ContainsKey(variable.TypeName)) { return _vizCache[variable.TypeName]; } TypeName parsedName = TypeName.Parse(variable.TypeName); IVariableInformation var = variable; while (parsedName != null) { var visualizer = Scan(parsedName, variable); if (visualizer == null && (parsedName.BaseName.EndsWith("*", StringComparison.Ordinal) || parsedName.BaseName.EndsWith("&", StringComparison.Ordinal))) { parsedName.BaseName = parsedName.BaseName.Substring(0, parsedName.BaseName.Length - 1); visualizer = Scan(parsedName, variable); } if (visualizer != null) { return visualizer; } var = FindBaseClass(var); // TODO: handle more than one base class? if (var == null) { break; } parsedName = TypeName.Parse(var.TypeName); } return null; }
internal IVariableInformation[] Expand(IVariableInformation variable) { try { variable.EnsureChildren(); if (variable.IsVisualized || ((ShowDisplayStrings == DisplayStringsState.On) && !(variable is VisualizerWrapper))) // visualize right away if DisplayStringsState.On, but only if not dummy var ([Raw View]) { return ExpandVisualized(variable); } IVariableInformation visView = GetVisualizationWrapper(variable); if (visView == null) { return variable.Children; } List<IVariableInformation> children = new List<IVariableInformation>(); children.Add(visView); children.AddRange(variable.Children); return children.ToArray(); } catch (Exception e) { Logger.WriteLine("natvis Expand: " + e.Message); // TODO: add telemetry return variable.Children; } }
internal IVariableInformation[] Expand(IVariableInformation variable) { try { variable.EnsureChildren(); if (variable.IsVisualized) { return ExpandVisualized(variable); } IVariableInformation visView = GetVisualizationWrapper(variable); if (visView == null) { return variable.Children; } List<IVariableInformation> children = new List<IVariableInformation>(); children.Add(visView); Array.ForEach(variable.Children, (c) => children.Add(c)); return children.ToArray(); } catch (Exception e) { Logger.WriteLine("natvis Expand: " + e.Message); // TODO: add telemetry return variable.Children; } }