Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/AndroidDebugLauncher/Launcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@ private LaunchOptions SetupForDebuggingWorker(CancellationToken token)

launchOptions.DebuggerMIMode = MIMode.Gdb;

launchOptions.VisualizerFile = "Microsoft.Android.natvis";
launchOptions.VisualizerFiles = new List<string>();
launchOptions.VisualizerFiles.Add("Microsoft.Android.natvis");
launchOptions.WaitDynamicLibLoad = _launchOptions.WaitDynamicLibLoad;

return launchOptions;
Expand Down
36 changes: 32 additions & 4 deletions src/MICore/JsonLaunchOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ public abstract partial class BaseOptions
public string TargetArchitecture { get; set; }

/// <summary>
/// .natvis file to be used when debugging this process. This option is not compatible with GDB pretty printing. Please also see "showDisplayString" if using this setting.
/// .natvis files to be used when debugging this process. This option is not compatible with GDB pretty printing. Please also see "showDisplayString" if using this setting.
/// </summary>
[JsonProperty("visualizerFile", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string VisualizerFile { get; set; }
[JsonConverter(typeof(VisualizerFileConverter))]
public List<string> VisualizerFile { get; set; }

/// <summary>
/// When a visualizerFile is specified, showDisplayString will enable the display string. Turning this option on can cause slower performance during debugging.
Expand Down Expand Up @@ -123,6 +124,33 @@ public abstract partial class BaseOptions
public UnknownBreakpointHandling? UnknownBreakpointHandling { get; set; }
}

internal class VisualizerFileConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
List<string> visualizerFile = new List<string>();
if (reader.TokenType == JsonToken.StartArray)
{
visualizerFile = serializer.Deserialize<List<string>>(reader);
}
else if (reader.TokenType == JsonToken.String)
{
visualizerFile.Add(reader.Value.ToString());
}
return visualizerFile;
}

public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

public partial class AttachOptions : BaseOptions
{
#region Public Properties for Serialization
Expand All @@ -144,7 +172,7 @@ public AttachOptions(
int processId,
string type = null,
string targetArchitecture = null,
string visualizerFile = null,
List<string> visualizerFile = null,
bool? showDisplayString = null,
string additionalSOLibSearchPath = null,
string MIMode = null,
Expand Down Expand Up @@ -408,7 +436,7 @@ public LaunchOptions(
List<SetupCommand> postRemoteConnectCommands = null,
List<SetupCommand> customLaunchSetupCommands = null,
LaunchCompleteCommand? launchCompleteCommand = null,
string visualizerFile = null,
List<string> visualizerFile = null,
bool? showDisplayString = null,
List<Environment> environment = null,
string additionalSOLibSearchPath = null,
Expand Down
18 changes: 9 additions & 9 deletions src/MICore/LaunchOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -960,16 +960,16 @@ public string AdditionalSOLibSearchPath
}
}

private string _visualizerFile;
private List<string> _visualizerFile;
/// <summary>
/// [Optional] Natvis file name - from install location
/// </summary>
public string VisualizerFile
public List<string> VisualizerFiles
{
get { return _visualizerFile; }
get { return _visualizerFile; }
set
{
VerifyCanModifyProperty(nameof(VisualizerFile));
VerifyCanModifyProperty(nameof(VisualizerFiles));
_visualizerFile = value;
}
}
Expand Down Expand Up @@ -1579,9 +1579,9 @@ private void Merge(AttachOptionsForConnection suppOptions)
{
DebugChildProcesses = suppOptions.DebugChildProcesses;
}
if (string.IsNullOrWhiteSpace(VisualizerFile))
if (VisualizerFiles == null || VisualizerFiles.Count == 0)
{
VisualizerFile = suppOptions.VisualizerFile;
VisualizerFiles = suppOptions.VisualizerFile;
}
if (suppOptions.ShowDisplayStringSpecified)
{
Expand Down Expand Up @@ -1771,7 +1771,7 @@ protected void InitializeCommonOptions(Json.LaunchOptions.BaseOptions options)
this.TargetArchitecture = ConvertTargetArchitectureAttribute(options.TargetArchitecture);
}

this.VisualizerFile = options.VisualizerFile;
this.VisualizerFiles = options.VisualizerFile;
this.ShowDisplayString = options.ShowDisplayString.GetValueOrDefault(false);

this.AdditionalSOLibSearchPath = String.IsNullOrEmpty(this.AdditionalSOLibSearchPath) ?
Expand Down Expand Up @@ -1841,8 +1841,8 @@ protected void InitializeCommonOptions(Xml.LaunchOptions.BaseLaunchOptions sourc
if (string.IsNullOrEmpty(this.WorkingDirectory))
this.WorkingDirectory = source.WorkingDirectory;

if (string.IsNullOrEmpty(this.VisualizerFile))
this.VisualizerFile = source.VisualizerFile;
if (this.VisualizerFiles == null || this.VisualizerFiles.Count == 0)
this.VisualizerFiles = source.VisualizerFile;

this.ShowDisplayString = source.ShowDisplayString;
this.WaitDynamicLibLoad = source.WaitDynamicLibLoad;
Expand Down
9 changes: 5 additions & 4 deletions src/MICore/LaunchOptions.xsd.types.designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/MICoreUnitTests/BasicLaunchOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ internal void VerifyCoreApisPresent()
launchOptions.WorkingDirectory = "/home/user";
launchOptions.DebuggerMIMode = MIMode.Gdb;
launchOptions.WaitDynamicLibLoad = false;
launchOptions.VisualizerFile = @"c:\myproject\file.natvis";
launchOptions.VisualizerFiles = new List<string>();
launchOptions.VisualizerFiles.Add(@"c:\myproject\file.natvis");
launchOptions.SourceMap = new ReadOnlyCollection<SourceMapEntry>(new List<SourceMapEntry>());
launchOptions.Environment = new ReadOnlyCollection<EnvironmentEntry>(new List<EnvironmentEntry>());
Microsoft.DebugEngineHost.HostConfigurationStore configStore = null;
Expand Down
2 changes: 1 addition & 1 deletion src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ private async Task EnsureModulesLoaded()
public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token)
{
bool success = false;
Natvis.Initialize(_launchOptions.VisualizerFile);
Natvis.Initialize(_launchOptions.VisualizerFiles);
int total = 1;

await this.WaitForConsoleDebuggerInitialize(token);
Expand Down
20 changes: 19 additions & 1 deletion src/MIDebugEngine/Natvis.Impl/Natvis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ internal Natvis(DebuggedProcess process, bool showDisplayString, HostConfigurati
_configStore = configStore;
}

public void Initialize(string fileName)
public void InitializeNatvisServices()
{
try
{
Expand All @@ -271,7 +271,10 @@ public void Initialize(string fileName)
{
// failed to find the VS Service
}
}

public void Initialize(string fileName)
{
if (!string.IsNullOrEmpty(fileName))
{
if (!Path.IsPathRooted(fileName))
Expand Down Expand Up @@ -321,6 +324,21 @@ public void Initialize(string fileName)
}
}

/*
* Handle multiple Natvis files
*/
public void Initialize(List <string> fileNames)
{
if (fileNames != null && fileNames.Count > 0)
{
InitializeNatvisServices();
foreach (var file in fileNames)
{
Initialize(file);
}
}
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security.Xml", "CA3053: UseSecureXmlResolver.",
Justification = "Usage is secure -- XmlResolver property is set to 'null' in desktop CLR, and is always null in CoreCLR. But CodeAnalysis cannot understand the invocation since it happens through reflection.")]
private bool LoadFile(string path)
Expand Down
5 changes: 1 addition & 4 deletions test/CppTests/CppTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@
</ItemGroup>

<Target Name="Copy Config and Debuggees" BeforeTargets="DropFiles">
<Copy
SourceFiles="@(ContentFiles)"
DestinationFolder="$(DropDir)\contentFiles\%(RecursiveDir)"
/>
<Copy SourceFiles="@(ContentFiles)" DestinationFolder="$(DropDir)\contentFiles\%(RecursiveDir)" />
</Target>

<ItemGroup>
Expand Down
16 changes: 12 additions & 4 deletions test/CppTests/OpenDebug/CrossPlatCpp/LaunchCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
using System.Collections.Generic;
using System.IO;
using DebuggerTesting.OpenDebug.Commands;
using DebuggerTesting.OpenDebug.CrossPlatCpp;
using DebuggerTesting.Utilities;
using Newtonsoft.Json;

namespace DebuggerTesting.OpenDebug.CrossPlatCpp
{
#region LaunchCommandArgs

public sealed class CppLaunchCommandArgs : LaunchCommandArgs
public class CppLaunchCommandArgs : LaunchCommandArgs
{
public string launchOptionType;
public string miDebuggerPath;
Expand All @@ -34,7 +35,8 @@ public sealed class CppLaunchCommandArgs : LaunchCommandArgs
public string MIMode;

[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string VisualizerFile;
public object VisualizerFile;


[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool ShowDisplayString;
Expand All @@ -50,10 +52,16 @@ public class LaunchCommand : LaunchCommand<CppLaunchCommandArgs>
/// <param name="program">The full path to the program to launch</param>
/// <param name="architecture">The architecture of the program</param>
/// <param name="args">[OPTIONAL] Args to pass to the program</param>
public LaunchCommand(IDebuggerSettings settings, string program, string visualizerFile = null, bool isAttach = false, params string[] args)
public LaunchCommand(IDebuggerSettings settings, string program, object visualizerFile = null, bool isAttach = false, params string[] args)
{
if (!(visualizerFile == null || visualizerFile is string || visualizerFile is List<string>))
{
throw new ArgumentOutOfRangeException(nameof(visualizerFile));
}

this.Timeout = TimeSpan.FromSeconds(15);

this.Args = new CppLaunchCommandArgs();
this.Args.name = CreateName(settings);
this.Args.program = program;
this.Args.args = args ?? new string[] { };
Expand All @@ -75,7 +83,7 @@ public LaunchCommand(IDebuggerSettings settings, string program, string visualiz
this.Args.targetArchitecture = settings.DebuggeeArchitecture.ToArchitectureString();
this.Args.MIMode = settings.MIMode;
this.Args.VisualizerFile = visualizerFile;
this.Args.ShowDisplayString = !string.IsNullOrEmpty(visualizerFile);
this.Args.ShowDisplayString = visualizerFile != null;
}
}

Expand Down
68 changes: 68 additions & 0 deletions test/CppTests/Tests/NatvisTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,74 @@ public void TestCommaFormatWithSquareBrackets(ITestSettings settings)
}
}

[Theory]
[DependsOnTest(nameof(CompileNatvisDebuggee))]
[RequiresTestSettings]
// Disable on macOS
// Error:
// C-style cast from 'int' to 'int [10]' is not allowed
// (int[10])*(((vec)._start))
[UnsupportedDebugger(SupportedDebugger.Lldb, SupportedArchitecture.x64 | SupportedArchitecture.x86)]
public void TestMultipleNatvisFiles(ITestSettings settings)
{
this.TestPurpose("This test checks if multiple Natvis files can be used.");
this.WriteSettings(settings);

IDebuggee debuggee = Debuggee.Open(this, settings.CompilerSettings, NatvisName, DebuggeeMonikers.Natvis.Default);

using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
{
this.Comment("Configure launch");
List<string> visFile = new List<string>();
visFile.Add(Path.Join(debuggee.SourceRoot, "visualizer_files", "Simple1.natvis"));
visFile.Add(Path.Join(debuggee.SourceRoot, "visualizer_files", "Simple2.natvis"));

LaunchCommand launch = new LaunchCommand(settings.DebuggerSettings, debuggee.OutputPath, visFile, false);
runner.RunCommand(launch);

this.Comment("Set Breakpoint");
SourceBreakpoints writerBreakpoints = debuggee.Breakpoints(NatvisSourceName, ReturnSourceLine);
runner.SetBreakpoints(writerBreakpoints);

runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

using (IThreadInspector threadInspector = runner.GetThreadInspector())
{
IFrameInspector currentFrame = threadInspector.Stack.First();

// Simple1.natvis
this.Comment("Verifying ArrayItems natvis");
var ll = currentFrame.GetVariable("vec");
Assert.Equal("{ size=2000 }", ll.Value);

// Custom Item in natvis
Assert.Equal("2000", ll.GetVariable("Size").Value);

// Index element for ArrayItems
Assert.Equal("20", ll.GetVariable("[5]").Value);
Assert.Equal("51", ll.GetVariable("[More...]").GetVariable("[51]").Value);

// Simple2.natvis
this.Comment("Verifying TreeItems natvis");
var map = currentFrame.GetVariable("map");

// Custom Item in natvis
Assert.Equal("6", map.GetVariable("Count").Value);

// Index element for TreeItems
// Visualized map will show the BST in a flat ordered list.
// Values are inserted as [0, -100, 15, -35, 4, -72]
// Expected visualize list to be [-100, -72, -35, 0, 4, 15]
Assert.Equal("-100", map.GetVariable("[0]").Value);
Assert.Equal("0", map.GetVariable("[3]").Value);
Assert.Equal("15", map.GetVariable("[5]").Value);
}

runner.Expects.ExitedEvent(exitCode: 0).TerminatedEvent().AfterContinue();
runner.DisconnectAndVerify();
}
}

#endregion
}
}
33 changes: 33 additions & 0 deletions test/CppTests/debuggees/natvis/src/visualizer_files/Simple1.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>

<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="SimpleDisplayObject">
<DisplayString>Hello DisplayString</DisplayString>
</Type>

<Type Name="SimpleClass">
<DisplayString Condition="this == 0">Null Class</DisplayString>
<DisplayString Condition="this != 0">Non-null Class</DisplayString>
</Type>

<Type Name="SimpleVector">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<Item Name="Size">_size</Item>
<ArrayItems>
<Size>_size</Size>
<ValuePointer>_start</ValuePointer>
</ArrayItems>
</Expand>
</Type>

<Type Name="SimpleArray">
<DisplayString>{{ size={_size} }}</DisplayString>
<Expand>
<IndexListItems>
<Size>_size</Size>
<ValueNode>_array[_size - 1 - $i]</ValueNode>
</IndexListItems>
</Expand>
</Type>
</AutoVisualizer>
Loading