Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProcessInfo2 Diagnostics IPC Command #52258

Merged
17 commits merged into from
Jun 9, 2021
20 changes: 20 additions & 0 deletions src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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]))
Expand Down Expand Up @@ -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.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/eventpipe/ep-rt-mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ 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;

// Managed Entrypoint Assembly Path
josalem marked this conversation as resolved.
Show resolved Hide resolved
mono_lazy_init_t _ep_rt_mono_managed_entrypoint_assembly_path_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
ep_char16_t *_ep_rt_mono_managed_entrypoint_assembly_path = NULL;

// Sample profiler.
static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL;
static uint32_t _ep_rt_mono_max_sampled_thread_count = 32;
Expand Down
17 changes: 17 additions & 0 deletions src/mono/mono/eventpipe/ep-rt-mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

#undef EP_ARRAY_SIZE
#define EP_ARRAY_SIZE(expr) G_N_ELEMENTS(expr)
Expand Down Expand Up @@ -1820,6 +1823,20 @@ ep_rt_diagnostics_command_line_get (void)
return cmd_line;
}

static
josalem marked this conversation as resolved.
Show resolved Hide resolved
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
josalem marked this conversation as resolved.
Show resolved Hide resolved
const ep_char8_t *
ep_rt_runtime_version_get_utf8 (void)
{
return (const ep_char8_t *)EGLIB_TOSTRING (RuntimeProductVersion);
}

/*
* Thread.
*/
Expand Down
218 changes: 218 additions & 0 deletions src/native/eventpipe/ds-process-protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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)
josalem marked this conversation as resolved.
Show resolved Hide resolved
// 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) ?
josalem marked this conversation as resolved.
Show resolved Hide resolved
(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)
{
;
josalem marked this conversation as resolved.
Show resolved Hide resolved
}


/*
* DiagnosticsEnvironmentInfoPayload.
*/
Expand Down Expand Up @@ -386,6 +529,78 @@ process_protocol_helper_get_process_info (
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 (
josalem marked this conversation as resolved.
Show resolved Hide resolved
&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);
josalem marked this conversation as resolved.
Show resolved Hide resolved
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 ();
josalem marked this conversation as resolved.
Show resolved Hide resolved
}

static
bool
process_protocol_helper_get_process_env (
Expand Down Expand Up @@ -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);
Expand Down
51 changes: 50 additions & 1 deletion src/native/eventpipe/ds-process-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -125,4 +175,3 @@ ds_process_protocol_helper_handle_ipc_message (

#endif /* ENABLE_PERFTRACING */
#endif /* __DIAGNOSTICS_PROCESS_PROTOCOL_H__ */

Loading