Use the System.CommandLine CommandProcessor for the new commands.
Add "sos", "exit", "help", native "modules" and "setthread" commands.
--- /dev/null
+// --------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// --------------------------------------------------------------------
+using Microsoft.Diagnostics.Runtime;
+using SOS;
+using System;
+using System.CommandLine;
+using System.Threading;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ /// <summary>
+ /// The the common context for analyze commands
+ /// </summary>
+ public class AnalyzeContext: ISOSHostContext
+ {
+ readonly IConsole _console;
+ ClrRuntime _runtime;
+
+ public AnalyzeContext(IConsole console, DataTarget target, Action exit)
+ {
+ _console = console;
+ Target = target;
+ Exit = exit;
+ }
+
+ /// <summary>
+ /// ClrMD data target
+ /// </summary>
+ public DataTarget Target { get; }
+
+ /// <summary>
+ /// ClrMD runtime info
+ /// </summary>
+ public ClrRuntime Runtime
+ {
+ get
+ {
+ if (_runtime == null)
+ {
+ if (Target.ClrVersions.Count != 1)
+ {
+ throw new InvalidOperationException("More or less than 1 CLR version is present");
+ }
+ _runtime = Target.ClrVersions[0].CreateRuntime();
+ }
+ return _runtime;
+ }
+ }
+
+ /// <summary>
+ /// Delegate to invoke to exit repl
+ /// </summary>
+ public Action Exit { get; }
+
+ /// <summary>
+ /// Current OS thread Id
+ /// </summary>
+ public int CurrentThreadId { get; set; }
+
+ /// <summary>
+ /// Cancellation token for current command
+ /// </summary>
+ public CancellationToken CancellationToken { get; set; }
+
+ /// <summary>
+ /// Console write function
+ /// </summary>
+ /// <param name="text"></param>
+ void ISOSHostContext.Write(string text)
+ {
+ _console.Out.Write(text);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Microsoft.Diagnostic.Repl;
+using Microsoft.Diagnostics.Runtime;
+using System.CommandLine;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ public class Analyzer
+ {
+ private readonly ConsoleProvider _consoleProvider;
+ private readonly CommandProcessor _commandProcessor;
+
+ public Analyzer()
+ {
+ _consoleProvider = new ConsoleProvider();
+ _commandProcessor = new CommandProcessor(new Assembly[] { typeof(Analyzer).Assembly });
+ }
+
+ public async Task<int> Analyze(FileInfo dump_path, string[] command)
+ {
+ _consoleProvider.Out.WriteLine($"Loading core dump: {dump_path} ...");
+
+ DataTarget target = null;
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
+ target = DataTarget.LoadCoreDump(dump_path.FullName);
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
+ target = DataTarget.LoadCrashDump(dump_path.FullName, CrashDumpReader.ClrMD);
+ }
+ else {
+ _consoleProvider.Error.WriteLine($"{RuntimeInformation.OSDescription} not supported");
+ return 1;
+ }
+
+ using (target)
+ {
+ // Create common analyze context for commands
+ var analyzeContext = new AnalyzeContext(_consoleProvider, target, _consoleProvider.Stop) {
+ CurrentThreadId = unchecked((int)target.DataReader.EnumerateAllThreads().FirstOrDefault())
+ };
+ _commandProcessor.CommandContext = analyzeContext;
+
+ // Automatically enable symbol server support on Linux and MacOS
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
+ await _commandProcessor.Parse("setsymbolserver -ms", _consoleProvider);
+ }
+
+ // Run the commands from the dotnet-dump command line
+ if (command != null)
+ {
+ foreach (string cmd in command)
+ {
+ await _commandProcessor.Parse(cmd, _consoleProvider);
+ }
+ }
+
+ // Start interactive command line processing
+ await _consoleProvider.Start(async (string commandLine, CancellationToken cancellation) => {
+ analyzeContext.CancellationToken = cancellation;
+ await _commandProcessor.Parse(commandLine, _consoleProvider);
+ });
+ }
+
+ return 0;
+ }
+ }
+}
--- /dev/null
+
+using Microsoft.Diagnostic.Repl;
+using System.CommandLine;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ [Command(Name = "exit", Help = "Exit interactive mode.")]
+ public class ExitCommand : CommandBase
+ {
+ public AnalyzeContext AnalyzeContext { get; set; }
+
+ public override Task InvokeAsync()
+ {
+ AnalyzeContext.Exit();
+ return Task.CompletedTask;
+ }
+ }
+}
--- /dev/null
+using Microsoft.Diagnostic.Repl;
+using System.CommandLine;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ [Command(Name = "help", Help = "Display help for a command.")]
+ public class HelpCommand : CommandBase
+ {
+ [Argument(Help = "Command to find help.")]
+ public string Command { get; set; }
+
+ public CommandProcessor CommandProcessor { get; set; }
+
+ public override Task InvokeAsync()
+ {
+ return Task.CompletedTask;
+ }
+
+ /// <summary>
+ /// Get help builder interface
+ /// </summary>
+ /// <param name="helpBuilder">help builder</param>
+ public Task InvokeAsync(IHelpBuilder helpBuilder)
+ {
+ Command command = CommandProcessor.GetCommand(Command);
+ if (command != null) {
+ helpBuilder.Write(command);
+ }
+ else {
+ Console.Error.WriteLine($"Help for {Command} not found.");
+ }
+ return Task.CompletedTask;
+ }
+ }
+}
--- /dev/null
+
+using Microsoft.Diagnostic.Repl;
+using Microsoft.Diagnostics.Runtime;
+using System.CommandLine;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ [Command(Name = "modules", Help = "Displays the native modules in the process.")]
+ [Command(Name = "lm")]
+ public class ModulesCommand : CommandBase
+ {
+ [Option(Name = "--verbose", Help = "Displays more details.")]
+ [OptionAlias(Name = "-v")]
+ public bool Verbose { get; set; }
+
+ public AnalyzeContext AnalyzeContext { get; set; }
+
+ public override Task InvokeAsync()
+ {
+ foreach (ModuleInfo module in AnalyzeContext.Target.DataReader.EnumerateModules())
+ {
+ if (Verbose)
+ {
+ WriteLine("{0}", module.FileName);
+ WriteLine(" Address: {0:X16}", module.ImageBase);
+ WriteLine(" FileSize: {0:X8}", module.FileSize);
+ WriteLine(" TimeStamp: {0:X8}", module.TimeStamp);
+ if (module.BuildId != null) {
+ WriteLine(" BuildId: {0}", string.Concat(module.BuildId.Select((b) => b.ToString("x2"))));
+ }
+ WriteLine(" IsRuntime: {0}", module.IsRuntime);
+ WriteLine(" IsManaged: {0}", module.IsManaged);
+ }
+ else
+ {
+ WriteLine("{0:X16} {1:X8} {2}", module.ImageBase, module.FileSize, module.FileName);
+ }
+ }
+ return Task.CompletedTask;
+ }
+ }
+}
--- /dev/null
+using Microsoft.Diagnostic.Repl;
+using SOS;
+using System;
+using System.CommandLine;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ [Command(Name = "clrstack", AliasExpansion = "ClrStack", Help = "Provides a stack trace of managed code only.")]
+ [Command(Name = "clrthreads", AliasExpansion = "Threads", Help = "List the managed threads running.")]
+ [Command(Name = "dumpasync", AliasExpansion = "DumpAsync", Help = "Displays info about async state machines on the garbage-collected heap.")]
+ [Command(Name = "dumpclass", AliasExpansion = "DumpClass", Help = "Displays information about a EE class structure at the specified address.")]
+ [Command(Name = "dumpdelegate", AliasExpansion = "DumpDelegate", Help = "Displays information about a delegate.")]
+ [Command(Name = "dumpdomain", AliasExpansion = "DumpDomain", Help = "Displays information all the AppDomains and all assemblies within the domains.")]
+ [Command(Name = "dumpheap", AliasExpansion = "DumpHeap", Help = "Displays info about the garbage-collected heap and collection statistics about objects.")]
+ [Command(Name = "dumpil", AliasExpansion = "DumpIL", Help = "Displays the Microsoft intermediate language (MSIL) that is associated with a managed method.")]
+ [Command(Name = "dumplog", AliasExpansion = "DumpLog", Help = "Writes the contents of an in-memory stress log to the specified file.")]
+ [Command(Name = "dumpmd", AliasExpansion = "DumpMD", Help = "Displays information about a MethodDesc structure at the specified address.")]
+ [Command(Name = "dumpmodule", AliasExpansion = "DumpModule", Help = "Displays information about a EE module structure at the specified address.")]
+ [Command(Name = "dumpmt", AliasExpansion = "DumpMT", Help = "Displays information about a method table at the specified address.")]
+ [Command(Name = "dumpobj", AliasExpansion = "DumpObj", Help = "Displays info about an object at the specified address.")]
+ [Command(Name = "dumpstack", AliasExpansion = "DumpStack", Help = "Displays a native and managed stack trace.")]
+ [Command(Name = "dso", AliasExpansion = "DumpStackObjects", Help = "Displays all managed objects found within the bounds of the current stack.")]
+ [Command(Name = "eeheap", AliasExpansion = "EEHeap", Help = "Displays info about process memory consumed by internal runtime data structures.")]
+ [Command(Name = "eestack", AliasExpansion = "EEStack", Help = "Runs dumpstack on all threads in the process.")]
+ [Command(Name = "finalizequeue", AliasExpansion = "FinalizeQueue", Help = "Displays all objects registered for finalization.")]
+ [Command(Name = "gcroot", AliasExpansion = "GCRoot", Help = "Displays info about references (or roots) to an object at the specified address.")]
+ [Command(Name = "ip2md", AliasExpansion = "IP2MD", Help = "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.")]
+ [Command(Name = "name2ee", AliasExpansion = "Name2EE", Help = "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.")]
+ [Command(Name = "pe", AliasExpansion = "PrintException", Help = "Displays and formats fields of any object derived from the Exception class at the specified address.")]
+ [Command(Name = "syncblk", AliasExpansion = "SyncBlk", Help = "Displays the SyncBlock holder info.")]
+ [Command(Name = "histclear", AliasExpansion = "HistClear", Help = "Releases any resources used by the family of Hist commands.")]
+ [Command(Name = "histinit", AliasExpansion = "HistInit", Help = "Initializes the SOS structures from the stress log saved in the debuggee.")]
+ [Command(Name = "histobj", AliasExpansion = "HistObj", Help = "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument.")]
+ [Command(Name = "histobjfind", AliasExpansion = "HistObjFind", Help = "Displays all the log entries that reference an object at the specified address.")]
+ [Command(Name = "histroot", AliasExpansion = "HistRoot", Help = "Displays information related to both promotions and relocations of the specified root.")]
+ [Command(Name = "setsymbolserver", AliasExpansion = "SetSymbolServer", Help = "Enables the symbol server support ")]
+ [Command(Name = "soshelp", AliasExpansion = "Help", Help = "Displays all available commands when no parameter is specified, or displays detailed help information about the specified command. soshelp <command>")]
+ public class SOSCommand : CommandBase
+ {
+ [Argument(Name = "arguments", Help = "Arguments to SOS command.")]
+ public string[] Arguments { get; set; }
+
+ public AnalyzeContext AnalyzeContext { get; set; }
+
+ private SOSHost _sosHost;
+
+ public override Task InvokeAsync()
+ {
+ try {
+ if (_sosHost == null) {
+ _sosHost = new SOSHost(AnalyzeContext.Target.DataReader, AnalyzeContext);
+ }
+ string arguments = null;
+ if (Arguments.Length > 0) {
+ arguments = string.Concat(Arguments.Select((arg) => arg + " "));
+ }
+ _sosHost.ExecuteCommand(AliasExpansion, arguments);
+ }
+ catch (Exception ex) when (ex is FileNotFoundException || ex is EntryPointNotFoundException || ex is InvalidOperationException) {
+ Console.Error.WriteLine(ex.Message);
+ }
+ return Task.CompletedTask;
+ }
+ }
+}
--- /dev/null
+
+using Microsoft.Diagnostic.Repl;
+using System.CommandLine;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+ [Command(Name = "setthread", Help = "Sets or displays the current thread id for the SOS commands.")]
+ [Command(Name = "threads")]
+ public class SetThreadCommand : CommandBase
+ {
+ [Argument(Help = "The thread id to set, otherwise displays the current id.")]
+ public int? ThreadId { get; set; } = null;
+
+ public AnalyzeContext AnalyzeContext { get; set; }
+
+ public override Task InvokeAsync()
+ {
+ if (ThreadId.HasValue)
+ {
+ AnalyzeContext.CurrentThreadId = ThreadId.Value;
+ }
+ else
+ {
+ int index = 0;
+ foreach (uint threadId in AnalyzeContext.Target.DataReader.EnumerateAllThreads())
+ {
+ WriteLine("{0}{1} 0x{2:X4} ({2})", threadId == AnalyzeContext.CurrentThreadId ? "*" : " ", index, threadId);
+ index++;
+ }
+ }
+ return Task.CompletedTask;
+ }
+ }
+}
using System.Threading.Tasks;
using System.IO;
-namespace Microsoft.Diagnostics.Tools.Dump
+namespace Microsoft.Diagnostic.Tools.Dump
{
- public static partial class Dumper
+ public partial class Dumper
{
private static class Linux
{
internal static async Task CollectDumpAsync(Process process, string fileName)
{
// We don't work on WSL :(
- var ostype = await File.ReadAllTextAsync("/proc/sys/kernel/osrelease");
- if(ostype.Contains("Microsoft"))
+ string ostype = await File.ReadAllTextAsync("/proc/sys/kernel/osrelease");
+ if (ostype.Contains("Microsoft"))
{
throw new PlatformNotSupportedException("Cannot collect memory dumps from Windows Subsystem for Linux.");
}
// First step is to find the .NET runtime. To do this we look for coreclr.so
- var coreclr = process.Modules.Cast<ProcessModule>().FirstOrDefault(m => string.Equals(m.ModuleName, "libcoreclr.so"));
- if(coreclr == null)
+ ProcessModule coreclr = process.Modules.Cast<ProcessModule>().FirstOrDefault(m => string.Equals(m.ModuleName, "libcoreclr.so"));
+ if (coreclr == null)
{
throw new NotSupportedException("Unable to locate .NET runtime associated with this process!");
}
// Find createdump next to that file
- var runtimeDirectory = Path.GetDirectoryName(coreclr.FileName);
- var createDumpPath = Path.Combine(runtimeDirectory, "createdump");
- if(!File.Exists(createDumpPath))
+ string runtimeDirectory = Path.GetDirectoryName(coreclr.FileName);
+ string createDumpPath = Path.Combine(runtimeDirectory, "createdump");
+ if (!File.Exists(createDumpPath))
{
throw new NotSupportedException($"Unable to locate 'createdump' tool in '{runtimeDirectory}'");
}
// Create the dump
- var exitCode = await CreateDumpAsync(createDumpPath, fileName, process.Id);
- if(exitCode != 0)
+ int exitCode = await CreateDumpAsync(createDumpPath, fileName, process.Id);
+ if (exitCode != 0)
{
throw new Exception($"createdump exited with non-zero exit code: {exitCode}");
}
StartInfo = new ProcessStartInfo()
{
FileName = exePath,
- Arguments = $"-f {fileName} {processId}",
- RedirectStandardError = true,
- RedirectStandardOutput = true,
- RedirectStandardInput = true,
+ Arguments = $"--diag -f {fileName} {processId}",
+ //RedirectStandardError = true,
+ //RedirectStandardOutput = true,
+ //RedirectStandardInput = true,
},
EnableRaisingEvents = true,
};
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
-namespace Microsoft.Diagnostics.Tools.Dump
+namespace Microsoft.Diagnostic.Tools.Dump
{
- public static partial class Dumper
+ public partial class Dumper
{
private static class Windows
{
using System;
+using System.CommandLine;
using System.Diagnostics;
+using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
-namespace Microsoft.Diagnostics.Tools.Dump
+namespace Microsoft.Diagnostic.Tools.Dump
{
- public static partial class Dumper
+ public partial class Dumper
{
- public static Task CollectDumpAsync(Process process, string fileName)
+ public Dumper()
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- return Windows.CollectDumpAsync(process, fileName);
+ }
+
+ public async Task<int> Collect(IConsole console, int processId, string outputDirectory)
+ {
+ if (processId == 0) {
+ console.Error.WriteLine("ProcessId is required.");
+ return 1;
}
- else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+
+ // System.CommandLine has a bug in the default value handling
+ if (outputDirectory == null) {
+ outputDirectory = Directory.GetCurrentDirectory();
+ }
+
+ // Get the process
+ Process process = null;
+ try
{
- return Linux.CollectDumpAsync(process, fileName);
+ process = Process.GetProcessById(processId);
}
- else
+ catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException)
{
- throw new PlatformNotSupportedException("Can't collect a memory dump on this platform.");
+ console.Error.WriteLine($"Invalid process id: {processId}");
+ return 1;
}
+
+ // Generate the file name
+ string fileName = Path.Combine(outputDirectory, $"{process.ProcessName}-{process.Id}-{DateTime.Now:yyyyMMdd-HHmmss-fff}.dmp");
+
+ console.Out.WriteLine($"Collecting memory dump for {process.ProcessName} (ID: {process.Id}) ...");
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
+ await Windows.CollectDumpAsync(process, fileName);
+ }
+ else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
+ await Linux.CollectDumpAsync(process, fileName);
+ }
+ else {
+ console.Error.WriteLine($"Unsupported operating system {RuntimeInformation.OSDescription}");
+ return 1;
+ }
+
+ console.Out.WriteLine($"Dump saved to {fileName}");
+ return 0;
}
}
}
-using System;
-using System.ComponentModel.DataAnnotations;
-using System.Diagnostics;
+using System.CommandLine;
+using System.CommandLine.Builder;
+using System.CommandLine.Invocation;
using System.IO;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
-using McMaster.Extensions.CommandLineUtils;
-using Microsoft.Internal.Utilities;
-namespace Microsoft.Diagnostics.Tools.Dump
+namespace Microsoft.Diagnostic.Tools.Dump
{
- [Command(Name = "dotnet-dump", Description = "Captures memory dumps of .NET processes")]
- internal class Program
+ class Program
{
- [Required(ErrorMessage = "You must provide a process ID to be dumped.")]
- [Option("-p|--process-id <PROCESS_ID>", Description = "The ID of the process to collect a memory dump for")]
- public int ProcessId { get; set; }
-
- [Option("-o|--output <OUTPUT_DIRECTORY>", Description = "The directory to write the dump to. Defaults to the current working directory.")]
- public string OutputDir { get; set; }
-
- public async Task<int> OnExecute(IConsole console, CommandLineApplication app)
+ public static Task<int> Main(string[] args)
{
- if (string.IsNullOrEmpty(OutputDir))
- {
- OutputDir = Directory.GetCurrentDirectory();
- }
-
- // Get the process
- var process = Process.GetProcessById(ProcessId);
-
- // Generate the file name
- var fileName = Path.Combine(OutputDir, $"{process.ProcessName}-{process.Id}-{DateTime.Now:yyyyMMdd-HHmmss-fff}.dmp");
+ var parser = new CommandLineBuilder()
+ .AddCommand(CollectCommand())
+ .AddCommand(AnalyzeCommand())
+ .UseDefaults()
+ .Build();
- console.WriteLine($"Collecting memory dump for {process.ProcessName} (ID: {process.Id}) ...");
- await Dumper.CollectDumpAsync(process, fileName);
- console.WriteLine($"Dump saved to {fileName}");
-
- return 0;
+ return parser.InvokeAsync(args);
}
- private static int Main(string[] args)
- {
- DebugUtil.WaitForDebuggerIfRequested(ref args);
-
- try
- {
- return CommandLineApplication.Execute<Program>(args);
- }
- catch(PlatformNotSupportedException ex)
- {
- Console.Error.WriteLine(ex.Message);
- return 1;
- }
- catch (OperationCanceledException)
- {
- return 0;
- }
- }
+ private static Command CollectCommand() =>
+ new Command(
+ "collect",
+ "Captures memory dumps of .NET processes.",
+ new Option[] { ProcessIdOption(), OutputOption() },
+ handler: CommandHandler.Create<IConsole, int, string>(new Dumper().Collect));
+
+ private static Option ProcessIdOption() =>
+ new Option(
+ new[] { "-p", "--process-id" },
+ "The ID of the process to collect a memory dump.",
+ new Argument<int> { Name = "processId" });
+
+ private static Option OutputOption() =>
+ new Option(
+ new[] { "-o", "--output" },
+ "The directory to write the dump. Defaults to the current working directory.",
+ new Argument<string>(Directory.GetCurrentDirectory()) { Name = "directory" });
+
+ private static Command AnalyzeCommand() =>
+ new Command(
+ "analyze",
+ "Start interactive dump analyze.",
+ new Option[] { RunCommand() }, argument: DumpPath(),
+ handler: CommandHandler.Create<FileInfo, string[]>(new Analyzer().Analyze));
+
+ private static Argument DumpPath() =>
+ new Argument<FileInfo> {
+ Name = "dump_path",
+ Description = "Name of the dump file to analyze." }.ExistingOnly();
+
+ private static Option RunCommand() =>
+ new Option(
+ new[] { "-c", "--command" },
+ "Run the command on start.",
+ new Argument<string[]>() { Name = "command" });
}
}
<PropertyGroup>
<OutputType>Exe</OutputType>
- <!-- Target .NET Core 2.1 so it will run on LTS -->
<TargetFramework>netcoreapp2.1</TargetFramework>
- <RootNamespace>Microsoft.Diagnostics.Tools.Dump</RootNamespace>
-
+ <RuntimeFrameworkVersion>2.1.0</RuntimeFrameworkVersion>
<!-- Don't pack until ship engineering is done. Currently causing the official job to fail.
<IsPackable>true</IsPackable>
<PackAsTool>true</PackAsTool>
-->
+ <PackAsToolShimRuntimeIdentifiers>win-x64;win-x86;osx-x64</PackAsToolShimRuntimeIdentifiers>
+ <!-- The package version needs to be hard coded as a stable version so "dotnet tool install -g dotnet-dump" works -->
+ <Version>$(VersionPrefix)</Version>
+ <PackageVersion>$(VersionPrefix)</PackageVersion>
+ <ToolCommandName>dotnet-dump</ToolCommandName>
+ <RootNamespace>Microsoft.Diagnostic.Tools.Dump</RootNamespace>
+ <Description>Diagnostic dump collect and analyze tool</Description>
+ <PackageTags>Diagnostic</PackageTags>
+ <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
+ <!-- Need to put the shims here to sign -->
+ <PackagedShimOutputRootDirectory>$(OutputPath)</PackagedShimOutputRootDirectory>
+ <SOSNETCoreBinaries>$(ArtifactsBinDir)\SOS.NETCore\$(Configuration)\netstandard2.0\publish\*.dll</SOSNETCoreBinaries>
</PropertyGroup>
<ItemGroup>
- <Compile Include="..\Common\ConsoleCancellation.cs" Link="ConsoleCancellation.cs" />
- <Compile Include="..\Common\DebugUtil.cs" Link="DebugUtil.cs" />
+ <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="$(MicrosoftDiagnosticsRuntimeVersion)" />
</ItemGroup>
-
+
<ItemGroup>
- <PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.2.5" />
+ <ProjectReference Include="..\..\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
+ <ProjectReference Include="..\..\SOS\SOS.Hosting\SOS.Hosting.csproj" />
</ItemGroup>
+ <ItemGroup>
+ <_PackageFiles Include="$(SOSNETCoreBinaries)">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/win-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\Windows_NT.x64.$(Configuration)\sos.dll">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/win-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(SOSNETCoreBinaries)">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/win-x86</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\Windows_NT.x86.$(Configuration)\sos.dll">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/win-x86</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(SOSNETCoreBinaries)">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/linux-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\Linux.x64.$(Configuration)\libsosplugin.so">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/linux-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\Linux.x64.$(Configuration)\libsos.so">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/linux-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\Linux.x64.$(Configuration)\sosdocsunix.txt">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/linux-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(SOSNETCoreBinaries)">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/osx-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\OSX.x64.$(Configuration)\libsosplugin.dylib">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/osx-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\OSX.x64.$(Configuration)\libsos.dylib">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/osx-x64</PackagePath>
+ </_PackageFiles>
+ <_PackageFiles Include="$(ArtifactsBinDir)\OSX.x64.$(Configuration)\sosdocsunix.txt">
+ <BuildAction>None</BuildAction>
+ <PackagePath>tools/netcoreapp2.1/any/osx-x64</PackagePath>
+ </_PackageFiles>
+ </ItemGroup>
</Project>