From: Justin Anderson Date: Fri, 30 Jun 2023 07:48:14 +0000 (-0700) Subject: ProcessInfo3 diagnostic command (#3985) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055542~38^2^2~126 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9385de7980ceb1c981a28c6896592f64e293c0aa;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git ProcessInfo3 diagnostic command (#3985) Implement the ProcessInfo3 command as described in #3476 Corresponding runtime change: https://github.com/dotnet/runtime/pull/87707 --- diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs index 898d6f72a..8084d0af8 100644 --- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs +++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsClient/DiagnosticsClient.cs @@ -404,8 +404,15 @@ namespace Microsoft.Diagnostics.NETCore.Client internal ProcessInfo GetProcessInfo() { + // Attempt to get ProcessInfo v3 + ProcessInfo processInfo = TryGetProcessInfo3(); + if (null != processInfo) + { + return processInfo; + } + // Attempt to get ProcessInfo v2 - ProcessInfo processInfo = TryGetProcessInfo2(); + processInfo = TryGetProcessInfo2(); if (null != processInfo) { return processInfo; @@ -418,8 +425,15 @@ namespace Microsoft.Diagnostics.NETCore.Client internal async Task GetProcessInfoAsync(CancellationToken token) { + // Attempt to get ProcessInfo v3 + ProcessInfo processInfo = await TryGetProcessInfo3Async(token).ConfigureAwait(false); + if (null != processInfo) + { + return processInfo; + } + // Attempt to get ProcessInfo v2 - ProcessInfo processInfo = await TryGetProcessInfo2Async(token).ConfigureAwait(false); + processInfo = await TryGetProcessInfo2Async(token).ConfigureAwait(false); if (null != processInfo) { return processInfo; @@ -444,6 +458,20 @@ namespace Microsoft.Diagnostics.NETCore.Client return TryGetProcessInfo2FromResponse(response2, nameof(GetProcessInfoAsync)); } + private ProcessInfo TryGetProcessInfo3() + { + IpcMessage request = CreateProcessInfo3Message(); + using IpcResponse response2 = IpcClient.SendMessageGetContinuation(_endpoint, request); + return TryGetProcessInfo3FromResponse(response2, nameof(GetProcessInfo)); + } + + private async Task TryGetProcessInfo3Async(CancellationToken token) + { + IpcMessage request = CreateProcessInfo3Message(); + using IpcResponse response2 = await IpcClient.SendMessageGetContinuationAsync(_endpoint, request, token).ConfigureAwait(false); + return TryGetProcessInfo3FromResponse(response2, nameof(GetProcessInfoAsync)); + } + private static byte[] SerializePayload(T arg) { using (MemoryStream stream = new()) @@ -571,6 +599,11 @@ namespace Microsoft.Diagnostics.NETCore.Client return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo2); } + private static IpcMessage CreateProcessInfo3Message() + { + return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.GetProcessInfo3); + } + private static IpcMessage CreateResumeRuntimeMessage() { return new IpcMessage(DiagnosticsServerCommandSet.Process, (byte)ProcessCommandId.ResumeRuntime); @@ -665,6 +698,16 @@ namespace Microsoft.Diagnostics.NETCore.Client return ProcessInfo.ParseV2(response.Message.Payload); } + private static ProcessInfo TryGetProcessInfo3FromResponse(IpcResponse response, string operationName) + { + if (!ValidateResponseMessage(response.Message, operationName, ValidateResponseOptions.UnknownCommandReturnsFalse)) + { + return null; + } + + return ProcessInfo.ParseV3(response.Message.Payload); + } + internal static bool ValidateResponseMessage(IpcMessage responseMessage, string operationName, ValidateResponseOptions options = ValidateResponseOptions.None) { switch ((DiagnosticsServerResponseId)responseMessage.Header.CommandId) diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs index 6f86eb59a..f9eb3019e 100644 --- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs +++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcCommands.cs @@ -49,6 +49,7 @@ namespace Microsoft.Diagnostics.NETCore.Client GetProcessInfo2 = 0x04, EnablePerfMap = 0x05, DisablePerfMap = 0x06, - ApplyStartupHook = 0x07 + ApplyStartupHook = 0x07, + GetProcessInfo3 = 0x08 } } diff --git a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs index 044065b14..2d84a4b25 100644 --- a/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs +++ b/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/ProcessInfo.cs @@ -53,10 +53,28 @@ namespace Microsoft.Diagnostics.NETCore.Client internal static ProcessInfo ParseV2(byte[] payload) { int index = 0; - ProcessInfo processInfo = ParseCommon(payload, ref index); + return ParseCommon2(payload, ref index); + } - processInfo.ManagedEntrypointAssemblyName = IpcHelpers.ReadString(payload, ref index); - processInfo.ClrProductVersionString = IpcHelpers.ReadString(payload, ref index); + /// + /// Parses a ProcessInfo3 payload. + /// + internal static ProcessInfo ParseV3(byte[] payload) + { + int index = 0; + + // The ProcessInfo3 command is intended to allow the addition of new fields in future versions so + // long as the version field is incremented; prior fields shall not be changed or removed. + // Read the version field, parse the common payload, and dynamically parse the remainder depending on the version. + uint version = BinaryPrimitives.ReadUInt32LittleEndian(new ReadOnlySpan(payload, index, 4)); + index += sizeof(uint); + + ProcessInfo processInfo = ParseCommon2(payload, ref index); + + if (version >= 1) + { + processInfo.PortableRuntimeIdentifier = IpcHelpers.ReadString(payload, ref index); + } return processInfo; } @@ -80,6 +98,16 @@ namespace Microsoft.Diagnostics.NETCore.Client return processInfo; } + private static ProcessInfo ParseCommon2(byte[] payload, ref int index) + { + ProcessInfo processInfo = ParseCommon(payload, ref index); + + processInfo.ManagedEntrypointAssemblyName = IpcHelpers.ReadString(payload, ref index); + processInfo.ClrProductVersionString = IpcHelpers.ReadString(payload, ref index); + + return processInfo; + } + public ulong ProcessId { get; private set; } public Guid RuntimeInstanceCookie { get; private set; } public string CommandLine { get; private set; } @@ -87,5 +115,6 @@ namespace Microsoft.Diagnostics.NETCore.Client public string ProcessArchitecture { get; private set; } public string ManagedEntrypointAssemblyName { get; private set; } public string ClrProductVersionString { get; private set; } + public string PortableRuntimeIdentifier { get; private set; } } }