未验证 提交 197cfb60 编写于 作者: J John Salem 提交者: GitHub

ProcessInfo2 Diagnostics IPC Command (#52258)

* Stash the entrypoint assembly path

* Add ep funcs for accessing entrypoint and version
 * TODO: get Mono's entrypoint asm

* Add ProcessInfo2 command
 * command includes everything the first one did + product ver
   and entrypoint asm path
* Add a test too

* Mono build fixes

* fix Mono build

* PR feedback
* fetch mono info from main assembly
* remove ref naming
* remove lazy method

* handle bundled host
* need to test still

* Use assembly name
* simplify access patterns
* change API to utf8
* updated test

* update comment

* PR feedback

* save before I commit this time...

* fix merge conflict

* Update ds-process-protocol.c

add missing break statement from merge conflict fix

* Update src/native/eventpipe/ds-process-protocol.h

* Update ds-process-protocol.c

add missing frees

* PR feedback
上级 879879e6
......@@ -12,6 +12,7 @@
#include "fstream.h"
#include "typestring.h"
#include "win32threadpool.h"
#include "clrversion.h"
#undef EP_ARRAY_SIZE
#define EP_ARRAY_SIZE(expr) (sizeof(expr) / sizeof ((expr) [0]))
......@@ -1161,6 +1162,25 @@ ep_rt_coreclr_config_lock_get (void)
return &_ep_rt_coreclr_config_lock_handle;
}
static
inline
const ep_char8_t *
ep_rt_entrypoint_assembly_name_get_utf8 (void)
{
STATIC_CONTRACT_NOTHROW;
return reinterpret_cast<const ep_char8_t*>(GetAppDomain ()->GetRootAssembly ()->GetSimpleName ());
}
static
const ep_char8_t *
ep_rt_runtime_version_get_utf8 (void)
{
STATIC_CONTRACT_NOTHROW;
return reinterpret_cast<const ep_char8_t*>(CLR_PRODUCT_VERSION);
}
/*
* Atomics.
*/
......
......@@ -44,6 +44,7 @@ char *_ep_rt_mono_os_cmd_line = NULL;
mono_lazy_init_t _ep_rt_mono_managed_cmd_line_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
char *_ep_rt_mono_managed_cmd_line = NULL;
// Sample profiler.
static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL;
static uint32_t _ep_rt_mono_max_sampled_thread_count = 32;
......
......@@ -20,9 +20,12 @@
#include <mono/utils/mono-rand.h>
#include <mono/utils/mono-lazy-init.h>
#include <mono/utils/w32api.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/w32file.h>
#include <mono/metadata/w32event.h>
#include <mono/metadata/environment-internals.h>
#include <mono/metadata/metadata-internals.h>
#include <runtime_version.h>
#include <mono/metadata/profiler.h>
#undef EP_ARRAY_SIZE
......@@ -1824,6 +1827,22 @@ ep_rt_diagnostics_command_line_get (void)
return cmd_line;
}
static
inline
const ep_char8_t *
ep_rt_entrypoint_assembly_name_get_utf8 (void)
{
return (const ep_char8_t *)m_image_get_assembly_name (mono_assembly_get_main ()->image);
}
static
inline
const ep_char8_t *
ep_rt_runtime_version_get_utf8 (void)
{
return (const ep_char8_t *)EGLIB_TOSTRING (RuntimeProductVersion);
}
/*
* Thread.
*/
......
......@@ -53,6 +53,12 @@ process_protocol_helper_get_process_info (
DiagnosticsIpcMessage *message,
DiagnosticsIpcStream *stream);
static
bool
process_protocol_helper_get_process_info_2 (
DiagnosticsIpcMessage *message,
DiagnosticsIpcStream *stream);
static
bool
process_protocol_helper_get_process_env (
......@@ -191,6 +197,143 @@ ds_process_info_payload_fini (DiagnosticsProcessInfoPayload *payload)
;
}
/*
* DiagnosticsProcessInfo2Payload.
*/
static
uint16_t
process_info_2_payload_get_size (DiagnosticsProcessInfo2Payload *payload)
{
// see IPC spec @ https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/ipc-protocol.md
// for definition of serialization format
// uint64_t ProcessId; -> 8 bytes
// GUID RuntimeCookie; -> 16 bytes
// LPCWSTR CommandLine; -> 4 bytes + strlen * sizeof(WCHAR)
// LPCWSTR OS; -> 4 bytes + strlen * sizeof(WCHAR)
// LPCWSTR Arch; -> 4 bytes + strlen * sizeof(WCHAR)
// LPCWSTR managed_entrypoint_assembly_name; -> 4 bytes + strlen * sizeof(WCHAR)
// LPCWSTR clr_product_version; -> 4 bytes + strlen * sizeof(WCHAR)
EP_ASSERT (payload != NULL);
size_t size = 0;
size += sizeof(payload->process_id);
size += sizeof(payload->runtime_cookie);
size += sizeof(uint32_t);
size += (payload->command_line != NULL) ?
(ep_rt_utf16_string_len (payload->command_line) + 1) * sizeof(ep_char16_t) : 0;
size += sizeof(uint32_t);
size += (payload->os != NULL) ?
(ep_rt_utf16_string_len (payload->os) + 1) * sizeof(ep_char16_t) : 0;
size += sizeof(uint32_t);
size += (payload->arch != NULL) ?
(ep_rt_utf16_string_len (payload->arch) + 1) * sizeof(ep_char16_t) : 0;
size += sizeof(uint32_t);
size += (payload->managed_entrypoint_assembly_name != NULL) ?
(ep_rt_utf16_string_len (payload->managed_entrypoint_assembly_name) + 1) * sizeof(ep_char16_t) : 0;
size += sizeof(uint32_t);
size += (payload->clr_product_version != NULL) ?
(ep_rt_utf16_string_len (payload->clr_product_version) + 1) * sizeof(ep_char16_t) : 0;
EP_ASSERT (size <= UINT16_MAX);
return (uint16_t)size;
}
static
bool
process_info_2_payload_flatten (
void *payload,
uint8_t **buffer,
uint16_t *size)
{
DiagnosticsProcessInfo2Payload *process_info = (DiagnosticsProcessInfo2Payload*)payload;
EP_ASSERT (payload != NULL);
EP_ASSERT (buffer != NULL);
EP_ASSERT (*buffer != NULL);
EP_ASSERT (size != NULL);
EP_ASSERT (process_info_2_payload_get_size (process_info) == *size);
// see IPC spec @ https://github.com/dotnet/diagnostics/blob/master/documentation/design-docs/ipc-protocol.md
// for definition of serialization format
bool success = true;
// uint64_t ProcessId;
memcpy (*buffer, &process_info->process_id, sizeof (process_info->process_id));
*buffer += sizeof (process_info->process_id);
*size -= sizeof (process_info->process_id);
// GUID RuntimeCookie;
memcpy(*buffer, &process_info->runtime_cookie, sizeof (process_info->runtime_cookie));
*buffer += sizeof (process_info->runtime_cookie);
*size -= sizeof (process_info->runtime_cookie);
// LPCWSTR CommandLine;
success &= ds_ipc_message_try_write_string_utf16_t (buffer, size, process_info->command_line);
// LPCWSTR OS;
if (success)
success &= ds_ipc_message_try_write_string_utf16_t (buffer, size, process_info->os);
// LPCWSTR Arch;
if (success)
success &= ds_ipc_message_try_write_string_utf16_t (buffer, size, process_info->arch);
// LPCWSTR managed_entrypoint_assembly_name;
if (success)
success &= ds_ipc_message_try_write_string_utf16_t (buffer, size, process_info->managed_entrypoint_assembly_name);
// LPCWSTR clr_product_version;
if (success)
success &= ds_ipc_message_try_write_string_utf16_t (buffer, size, process_info->clr_product_version);
// Assert we've used the whole buffer we were given
EP_ASSERT(*size == 0);
return success;
}
DiagnosticsProcessInfo2Payload *
ds_process_info_2_payload_init (
DiagnosticsProcessInfo2Payload *payload,
const ep_char16_t *command_line,
const ep_char16_t *os,
const ep_char16_t *arch,
uint32_t process_id,
const uint8_t *runtime_cookie,
const ep_char16_t *managed_entrypoint_assembly_name,
const ep_char16_t *clr_product_version)
{
ep_return_null_if_nok (payload != NULL);
payload->command_line = command_line;
payload->os = os;
payload->arch = arch;
payload->process_id = process_id;
payload->managed_entrypoint_assembly_name = managed_entrypoint_assembly_name;
payload->clr_product_version = clr_product_version;
if (runtime_cookie)
memcpy (&payload->runtime_cookie, runtime_cookie, EP_GUID_SIZE);
return payload;
}
void
ds_process_info_2_payload_fini (DiagnosticsProcessInfo2Payload *payload)
{
;
}
/*
* DiagnosticsEnvironmentInfoPayload.
*/
......@@ -386,6 +529,78 @@ ep_on_error:
ep_exit_error_handler ();
}
static
bool
process_protocol_helper_get_process_info_2 (
DiagnosticsIpcMessage *message,
DiagnosticsIpcStream *stream)
{
EP_ASSERT (message != NULL);
EP_ASSERT (stream != NULL);
bool result = false;
ep_char16_t *command_line = NULL;
ep_char16_t *os_info = NULL;
ep_char16_t *arch_info = NULL;
ep_char16_t *managed_entrypoint_assembly_name = NULL;
ep_char16_t *clr_product_version = NULL;
DiagnosticsProcessInfo2Payload payload;
DiagnosticsProcessInfo2Payload *process_info_2_payload = NULL;
command_line = ep_rt_utf8_to_utf16_string (ep_rt_diagnostics_command_line_get (), -1);
ep_raise_error_if_nok (command_line != NULL);
os_info = ep_rt_utf8_to_utf16_string (ep_event_source_get_os_info (), -1);
ep_raise_error_if_nok (os_info != NULL);
arch_info = ep_rt_utf8_to_utf16_string (ep_event_source_get_arch_info (), -1);
ep_raise_error_if_nok (arch_info != NULL);
managed_entrypoint_assembly_name = ep_rt_utf8_to_utf16_string (ep_rt_entrypoint_assembly_name_get_utf8 (), -1);
ep_raise_error_if_nok (managed_entrypoint_assembly_name != NULL);
clr_product_version = ep_rt_utf8_to_utf16_string (ep_rt_runtime_version_get_utf8 (), -1);
ep_raise_error_if_nok (clr_product_version != NULL);
process_info_2_payload = ds_process_info_2_payload_init (
&payload,
command_line,
os_info,
arch_info,
ep_rt_current_process_get_id (),
ds_ipc_advertise_cookie_v1_get (),
managed_entrypoint_assembly_name,
clr_product_version);
ep_raise_error_if_nok (process_info_2_payload != NULL);
ep_raise_error_if_nok (ds_ipc_message_initialize_buffer (
message,
ds_ipc_header_get_generic_success (),
(void *)process_info_2_payload,
process_info_2_payload_get_size (process_info_2_payload),
process_info_2_payload_flatten));
ep_raise_error_if_nok (ds_ipc_message_send (message, stream));
result = true;
ep_on_exit:
ds_process_info_2_payload_fini (process_info_2_payload);
ep_rt_utf16_string_free (arch_info);
ep_rt_utf16_string_free (os_info);
ep_rt_utf16_string_free (command_line);
ep_rt_utf16_string_free (managed_entrypoint_assembly_name);
ep_rt_utf16_string_free (clr_product_version);
ds_ipc_stream_free (stream);
return result;
ep_on_error:
EP_ASSERT (!result);
ds_ipc_message_send_error (stream, DS_IPC_E_FAIL);
DS_LOG_WARNING_0 ("Failed to send DiagnosticsIPC response");
ep_exit_error_handler ();
}
static
bool
process_protocol_helper_get_process_env (
......@@ -566,6 +781,9 @@ ds_process_protocol_helper_handle_ipc_message (
break;
case DS_PROCESS_COMMANDID_SET_ENV_VAR:
result = process_protocol_helper_set_environment_variable (message, stream);
break;
case DS_PROCESS_COMMANDID_GET_PROCESS_INFO_2:
result = process_protocol_helper_get_process_info_2 (message, stream);
break;
default:
result = process_protocol_helper_unknown_command (message, stream);
......
......@@ -58,6 +58,56 @@ ds_process_info_payload_init (
void
ds_process_info_payload_fini (DiagnosticsProcessInfoPayload *payload);
/*
* DiagnosticsProcessInfo2Payload
*/
// command = 0x0400
#if defined(DS_INLINE_GETTER_SETTER) || defined(DS_IMPL_PROCESS_PROTOCOL_GETTER_SETTER)
struct _DiagnosticsProcessInfo2Payload {
#else
struct _DiagnosticsProcessInfo2Payload_Internal {
#endif
// The protocol buffer is defined as:
// X, Y, Z means encode bytes for X followed by bytes for Y followed by bytes for Z
// uint = 4 little endian bytes
// long = 8 little endian bytes
// GUID = 16 little endian bytes
// wchar = 2 little endian bytes, UTF16 encoding
// array<T> = uint length, length # of Ts
// string = (array<char> where the last char must = 0) or (length = 0)
// ProcessInfo = long pid, GUID runtimeCookie, string cmdline, string OS, string arch, string managed entrypoint assembly path, string clr product version
uint64_t process_id;
const ep_char16_t *command_line;
const ep_char16_t *os;
const ep_char16_t *arch;
uint8_t runtime_cookie [EP_GUID_SIZE];
const ep_char16_t *managed_entrypoint_assembly_name;
const ep_char16_t *clr_product_version;
};
#if !defined(DS_INLINE_GETTER_SETTER) && !defined(DS_IMPL_PROCESS_PROTOCOL_GETTER_SETTER)
struct _DiagnosticsProcessInfo2Payload {
uint8_t _internal [sizeof (struct _DiagnosticsProcessInfo2Payload_Internal)];
};
#endif
DiagnosticsProcessInfo2Payload *
ds_process_info_2_payload_init (
DiagnosticsProcessInfo2Payload *payload,
const ep_char16_t *command_line,
const ep_char16_t *os,
const ep_char16_t *arch,
uint32_t process_id,
const uint8_t *runtime_cookie,
const ep_char16_t *managed_entrypoint_assembly_name,
const ep_char16_t *clr_product_version);
void
ds_process_info_2_payload_fini (DiagnosticsProcessInfo2Payload *payload);
/*
* DiagnosticsEnvironmentInfoPayload
*/
......@@ -125,4 +175,3 @@ ds_process_protocol_helper_handle_ipc_message (
#endif /* ENABLE_PERFTRACING */
#endif /* __DIAGNOSTICS_PROCESS_PROTOCOL_H__ */
......@@ -29,6 +29,7 @@ typedef struct _DiagnosticsPort DiagnosticsPort;
typedef struct _DiagnosticsPortBuilder DiagnosticsPortBuilder;
typedef struct _DiagnosticsPortVtable DiagnosticsPortVtable;
typedef struct _DiagnosticsProcessInfoPayload DiagnosticsProcessInfoPayload;
typedef struct _DiagnosticsProcessInfo2Payload DiagnosticsProcessInfo2Payload;
typedef struct _EventPipeCollectTracingCommandPayload EventPipeCollectTracingCommandPayload;
typedef struct _EventPipeCollectTracing2CommandPayload EventPipeCollectTracing2CommandPayload;
typedef struct _EventPipeStopTracingCommandPayload EventPipeStopTracingCommandPayload;
......@@ -67,6 +68,7 @@ typedef enum {
DS_PROCESS_COMMANDID_RESUME_RUNTIME = 0x01,
DS_PROCESS_COMMANDID_GET_PROCESS_ENV = 0x02,
DS_PROCESS_COMMANDID_SET_ENV_VAR = 0x03,
DS_PROCESS_COMMANDID_GET_PROCESS_INFO_2 = 0x04
// future
} DiagnosticsProcessCommandId;
......
......@@ -600,6 +600,14 @@ static
void
ep_rt_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array);
static
const ep_char8_t *
ep_rt_entrypoint_assembly_name_get_utf8 (void);
static
const ep_char8_t *
ep_rt_runtime_version_get_utf8 (void);
/*
* Lock
*/
......
......@@ -339,6 +339,53 @@ string ParseString(ref int start, ref int end)
}
}
public class ProcessInfo2
{
// uint64_t ProcessId;
// GUID RuntimeCookie;
// LPCWSTR CommandLine;
// LPCWSTR OS;
// LPCWSTR Arch;
public UInt64 ProcessId;
public Guid RuntimeCookie;
public string Commandline;
public string OS;
public string Arch;
public string ManagedEntrypointAssemblyName;
public string ClrProductVersion;
public static ProcessInfo2 TryParse(byte[] buf)
{
var info = new ProcessInfo2();
int start = 0;
int end = 8; /* sizeof(uint64_t) */
info.ProcessId = BitConverter.ToUInt64(buf[start..end]);
start = end;
end = start + 16; /* sizeof(guid) */
info.RuntimeCookie = new Guid(buf[start..end]);
string ParseString(ref int start, ref int end)
{
start = end;
end = start + 4; /* sizeof(uint32_t) */
uint nChars = BitConverter.ToUInt32(buf[start..end]);
start = end;
end = start + ((int)nChars * sizeof(char));
return System.Text.Encoding.Unicode.GetString(buf[start..end]).TrimEnd('\0');
}
info.Commandline = ParseString(ref start, ref end);
info.OS = ParseString(ref start, ref end);
info.Arch = ParseString(ref start, ref end);
info.ManagedEntrypointAssemblyName = ParseString(ref start, ref end);
info.ClrProductVersion = ParseString(ref start, ref end);
return info;
}
}
public class IpcClient
{
public static IpcMessage SendMessage(Stream stream, IpcMessage message)
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tools.RuntimeClient;
using Microsoft.Diagnostics.Tracing;
using Tracing.Tests.Common;
namespace Tracing.Tests.ProcessInfoValidation
{
public class ProcessInfoValidation
{
public static string NormalizeCommandLine(string cmdline)
{
// ASSUMPTION: double quotes (") and single quotes (') are used for paths with spaces
// ASSUMPTION: This test will only have two parts to the commandline
// check for quotes in first part
var parts = new List<string>();
bool isQuoted = false;
int start = 0;
for (int i = 0; i < cmdline.Length; i++)
{
if (isQuoted)
{
if (cmdline[i] == '"' || cmdline[i] == '\'')
{
parts.Add(cmdline.Substring(start, i - start));
isQuoted = false;
start = i + 1;
}
}
else if (cmdline[i] == '"' || cmdline[i] == '\'')
{
isQuoted = true;
start = i + 1;
}
else if (cmdline[i] == ' ')
{
parts.Add(cmdline.Substring(start, i - start));
start = i + 1;
}
else if (i == cmdline.Length - 1)
{
parts.Add(cmdline.Substring(start));
}
}
string normalizedCommandLine = parts
.Where(part => !string.IsNullOrWhiteSpace(part))
.Select(part => (new FileInfo(part)).FullName)
.Aggregate((s1, s2) => string.Join(' ', s1, s2));
// Tests are run out of /tmp on Mac and linux, but on Mac /tmp is actually a symlink that points to /private/tmp.
// This isn't represented in the output from FileInfo.FullName unfortunately, so we'll fake that completion in that case.
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && normalizedCommandLine.StartsWith("/tmp/"))
normalizedCommandLine = "/private" + normalizedCommandLine;
return normalizedCommandLine;
}
public static int Main(string[] args)
{
Process currentProcess = Process.GetCurrentProcess();
int pid = currentProcess.Id;
Logger.logger.Log($"Test PID: {pid}");
Stream stream = ConnectionHelper.GetStandardTransport(pid);
// 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2
var processInfoMessage = new IpcMessage(0x04, 0x04);
Logger.logger.Log($"Wrote: {processInfoMessage}");
IpcMessage response = IpcClient.SendMessage(stream, processInfoMessage);
Logger.logger.Log($"Received: <omitted>");
Utils.Assert(response.Header.CommandSet == 0xFF, $"Response must have Server command set. Expected: 0xFF, Received: 0x{response.Header.CommandSet:X2}"); // server
Utils.Assert(response.Header.CommandId == 0x00, $"Response must have OK command id. Expected: 0x00, Received: 0x{response.Header.CommandId:X2}"); // OK
// Parse payload
// uint64_t ProcessId;
// GUID RuntimeCookie;
// LPCWSTR CommandLine;
// LPCWSTR OS;
// LPCWSTR Arch;
int totalSize = response.Payload.Length;
Logger.logger.Log($"Total size of Payload = {totalSize} bytes");
// VALIDATE PID
int start = 0;
int end = start + 8 /* sizeof(uint63_t) */;
UInt64 processId = BitConverter.ToUInt64(response.Payload[start..end]);
Utils.Assert((int)processId == pid, $"PID in process info must match. Expected: {pid}, Received: {processId}");
Logger.logger.Log($"pid: {processId}");
// VALIDATE RUNTIME COOKIE
start = end;
end = start + 16 /* sizeof(GUID) */;
Guid runtimeCookie = new Guid(response.Payload[start..end]);
Logger.logger.Log($"runtimeCookie: {runtimeCookie}");
// VALIDATE COMMAND LINE
start = end;
end = start + 4 /* sizeof(uint32_t) */;
UInt32 commandLineLength = BitConverter.ToUInt32(response.Payload[start..end]);
Logger.logger.Log($"commandLineLength: {commandLineLength}");
start = end;
end = start + ((int)commandLineLength * sizeof(char));
Utils.Assert(end <= totalSize, $"String end can't exceed payload size. Expected: <{totalSize}, Received: {end} (decoded length: {commandLineLength})");
Logger.logger.Log($"commandLine bytes: [ {response.Payload[start..end].Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
string commandLine = System.Text.Encoding.Unicode.GetString(response.Payload[start..end]).TrimEnd('\0');
Logger.logger.Log($"commandLine: \"{commandLine}\"");
// The following logic is tailored to this specific test where the cmdline _should_ look like the following:
// /path/to/corerun /path/to/processinfo.dll
// or
// "C:\path\to\CoreRun.exe" C:\path\to\processinfo.dll
string currentProcessCommandLine = $"{currentProcess.MainModule.FileName} {System.Reflection.Assembly.GetExecutingAssembly().Location}";
string receivedCommandLine = NormalizeCommandLine(commandLine);
Utils.Assert(currentProcessCommandLine.Equals(receivedCommandLine, StringComparison.OrdinalIgnoreCase), $"CommandLine must match current process. Expected: {currentProcessCommandLine}, Received: {receivedCommandLine} (original: {commandLine})");
// VALIDATE OS
start = end;
end = start + 4 /* sizeof(uint32_t) */;
UInt32 OSLength = BitConverter.ToUInt32(response.Payload[start..end]);
Logger.logger.Log($"OSLength: {OSLength}");
start = end;
end = start + ((int)OSLength * sizeof(char));
Utils.Assert(end <= totalSize, $"String end can't exceed payload size. Expected: <{totalSize}, Received: {end} (decoded length: {OSLength})");
Logger.logger.Log($"OS bytes: [ {response.Payload[start..end].Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
string OS = System.Text.Encoding.Unicode.GetString(response.Payload[start..end]).TrimEnd('\0');
Logger.logger.Log($"OS: \"{OS}\"");
// see eventpipeeventsource.cpp for these values
string expectedOSValue = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
expectedOSValue = "Windows";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
expectedOSValue = "macOS";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
expectedOSValue = "Linux";
}
else
{
expectedOSValue = "Unknown";
}
Utils.Assert(expectedOSValue.Equals(OS), $"OS must match current Operating System. Expected: \"{expectedOSValue}\", Received: \"{OS}\"");
// VALIDATE ARCH
start = end;
end = start + 4 /* sizeof(uint32_t) */;
UInt32 archLength = BitConverter.ToUInt32(response.Payload[start..end]);
Logger.logger.Log($"archLength: {archLength}");
start = end;
end = start + ((int)archLength * sizeof(char));
Utils.Assert(end <= totalSize, $"String end can't exceed payload size. Expected: <{totalSize}, Received: {end} (decoded length: {archLength})");
Logger.logger.Log($"arch bytes: [ {response.Payload[start..end].Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
string arch = System.Text.Encoding.Unicode.GetString(response.Payload[start..end]).TrimEnd('\0');
Logger.logger.Log($"arch: \"{arch}\"");
// see eventpipeeventsource.cpp for these values
string expectedArchValue = RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => "x86",
Architecture.X64 => "x64",
Architecture.Arm => "arm32",
Architecture.Arm64 => "arm64",
_ => "Unknown"
};
Utils.Assert(expectedArchValue.Equals(arch), $"OS must match current Operating System. Expected: \"{expectedArchValue}\", Received: \"{arch}\"");
// VALIDATE ManagedEntrypointAssemblyName
start = end;
end = start + 4 /* sizeof(uint32_t) */;
UInt32 managedEntrypointAssemblyNameLength = BitConverter.ToUInt32(response.Payload[start..end]);
Logger.logger.Log($"managedEntrypointAssemblyNameLength: {managedEntrypointAssemblyNameLength}");
start = end;
end = start + ((int)managedEntrypointAssemblyNameLength * sizeof(char));
Utils.Assert(end <= totalSize, $"String end can't exceed payload size. Expected: <{totalSize}, Received: {end} (decoded length: {managedEntrypointAssemblyNameLength})");
Logger.logger.Log($"ManagedEntrypointAssemblyName bytes: [ {response.Payload[start..end].Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
string managedEntrypointAssemblyName = System.Text.Encoding.Unicode.GetString(response.Payload[start..end]).TrimEnd('\0');
Logger.logger.Log($"ManagedEntrypointAssemblyName: \"{managedEntrypointAssemblyName}\"");
string expectedManagedEntrypointAssemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
Utils.Assert(expectedManagedEntrypointAssemblyName.Equals(managedEntrypointAssemblyName), $"ManagedEntrypointAssemblyName must match. Expected: \"{expectedManagedEntrypointAssemblyName}\", received: \"{managedEntrypointAssemblyName}\"");
// VALIDATE ClrProductVersion
start = end;
end = start + 4 /* sizeof(uint32_t) */;
UInt32 clrProductVersionSize = BitConverter.ToUInt32(response.Payload[start..end]);
Logger.logger.Log($"clrProductVersionSize: {clrProductVersionSize}");
start = end;
end = start + ((int)clrProductVersionSize * sizeof(char));
Utils.Assert(end <= totalSize, $"String end can't exceed payload size. Expected: <{totalSize}, Received: {end} (decoded length: {clrProductVersionSize})");
Logger.logger.Log($"ClrProductVersion bytes: [ {response.Payload[start..end].Select(b => b.ToString("X2") + " ").Aggregate(string.Concat)}]");
string clrProductVersion = System.Text.Encoding.Unicode.GetString(response.Payload[start..end]).TrimEnd('\0');
Logger.logger.Log($"ClrProductVersion: \"{clrProductVersion}\"");
string expectedClrProductVersion = typeof(object).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
Utils.Assert(expectedClrProductVersion.Equals(clrProductVersion), $"ClrProductVersion must match. Expected: \"{expectedClrProductVersion}\", received: \"{clrProductVersion}\"");
Utils.Assert(end == totalSize, $"Full payload should have been read. Expected: {totalSize}, Received: {end}");
Logger.logger.Log($"\n{{\n\tprocessId: {processId},\n\truntimeCookie: {runtimeCookie},\n\tcommandLine: {commandLine},\n\tOS: {OS},\n\tArch: {arch},\n\tManagedEntrypointAssemblyName: {managedEntrypointAssemblyName},\n\tClrProductVersion: {clrProductVersion}\n}}");
return 100;
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
<OutputType>exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CLRTestPriority>0</CLRTestPriority>
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
<JitOptimizationSensitive>true</JitOptimizationSensitive>
<!-- ilasm round-trip testing doesn't work, as test expects unchanged assembly name.
Issue: https://github.com/dotnet/runtime/issues/39935
-->
<IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
<ProjectReference Include="../common/common.csproj" />
</ItemGroup>
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册