Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
46 changes: 40 additions & 6 deletions documentation/design-docs/ipc-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,34 @@ The `metadata` either points at nothing if the event doesn’t have metadata, or

The runtime will keep track per-session whether it has sent a particular event before. The first time each event is sent during a session, metadata will be included. Should multiple threads race to write the same event to the same session, they may all emit metadata. Afterwards, all instances of that event will not emit metadata, and the responsibility is on the reader to cache and link events with their previously sent metadata. As a special case, runtime events currently implemented in native code will never send metadata.

#### Capability probing with CollectTracing5

Clients may use `CollectTracing5` as a capability probe to determine whether a runtime supports user_events-based EventPipe sessions.

A recommended probe is:

* Header: `{ Magic; 24; 0x0206; 0x0000 }`
* `Magic` = `"DOTNET_IPC_V1"`
* `size` = `sizeof(IpcHeader) + sizeof(uint)` = `20 + 4 = 24`
* `command_set` = `0x02` (EventPipe)
* `command_id` = `0x06` (CollectTracing5)
* `reserved` = `0x0000`
* Payload:
* `uint session_type = 0xFFFFFFFF;`

Expected behavior:

* If the runtime does not implement `CollectTracing5`, it responds with an error message using the generic `Server/Error` pattern and an error code of `DS_IPC_E_UNKNOWN_COMMAND` (`0x80131385`).
* If the runtime implements `CollectTracing5`, it:
* Parses the header and `session_type`.
* Treats `0xFFFFFFFF` as an invalid `session_type` value.
* Responds with an error Diagnostic IPC Message (see [Errors](#errors)) of Server/Error with a payload of `DS_IPC_E_BAD_ENCODING` (`0x80131384L`).

This allows clients to distinguish between:

* Runtimes that do not support `CollectTracing5` (return `UnknownCommand`), and
* Runtimes that understand `CollectTracing5` and its `session_type` semantics (return a non-`UnknownCommand` error for the probe message).

## Dump Commands

### `CreateCoreDump`
Expand Down Expand Up @@ -1573,15 +1601,21 @@ In the event an error occurs in the handling of an Ipc Message, the Diagnostic S

Errors are `HRESULTS` encoded as `int32_t` when sent back to the client. There are a few Diagnostics IPC specific `HRESULT`s:
```c
#define CORDIAGIPC_E_BAD_ENCODING = 0x80131384
#define CORDIAGIPC_E_UNKNOWN_COMMAND = 0x80131385
#define CORDIAGIPC_E_UNKNOWN_MAGIC = 0x80131386
#define CORDIAGIPC_E_UNKNOWN_ERROR = 0x80131387
#define DS_IPC_E_BAD_ENCODING ((ds_ipc_result_t)(0x80131384L))
#define DS_IPC_E_UNKNOWN_COMMAND ((ds_ipc_result_t)(0x80131385L))
#define DS_IPC_E_UNKNOWN_MAGIC ((ds_ipc_result_t)(0x80131386L))
#define DS_IPC_E_NOTSUPPORTED ((ds_ipc_result_t)(0x80131515L))
#define DS_IPC_E_FAIL ((ds_ipc_result_t)(0x80004005L))
#define DS_IPC_E_NOT_YET_AVAILABLE ((ds_ipc_result_t)(0x8013135bL))
#define DS_IPC_E_RUNTIME_UNINITIALIZED ((ds_ipc_result_t)(0x80131371L))
#define DS_IPC_E_INVALIDARG ((ds_ipc_result_t)(0x80070057L))
#define DS_IPC_E_INSUFFICIENT_BUFFER ((ds_ipc_result_t)(0x8007007A))
#define DS_IPC_E_ENVVAR_NOT_FOUND ((ds_ipc_result_t)(0x800000CB))
```

Diagnostic Server errors are sent as a Diagnostic IPC Message with:
* a `command_set` of `0xFF`
* a `command_id` of `0xFF`
* a `command_set` of `0xFF` (Server)
* a `command_id` of `0xFF` (Error)
* a Payload consisting of a `int32_t` representing the error encountered (described above)

All errors will result in the Server closing the connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace Microsoft.Diagnostics.NETCore.Client
public sealed class DiagnosticsClient
{
private const int DefaultCircularBufferMB = 256;
private const uint UserEventsProbePayload = uint.MaxValue;

private readonly IpcEndpoint _endpoint;

Expand Down Expand Up @@ -149,6 +150,20 @@ public Task<EventPipeSession> StartEventPipeSessionAsync(EventPipeSessionConfigu
return EventPipeSession.StartAsync(_endpoint, configuration, token);
}

/// <summary>
/// Check whether the target runtime understands the CollectTracing5 user_events IPC command.
/// </summary>
/// <returns>
/// A boolean indicating whether the runtime understands the CollectTracing5 user_events IPC command.
/// </returns>
internal bool SupportsEventPipeUserEventsCommand()
{
IpcMessage probe = CreateUserEventsCapabilityProbeMessage();
IpcMessage response = IpcClient.SendMessage(_endpoint, probe);

return IsCommandSupportedFromResponse(response);
}

/// <summary>
/// Trigger a core dump generation.
/// </summary>
Expand Down Expand Up @@ -623,6 +638,12 @@ private static void SerializePayloadArgument<T>(T obj, BinaryWriter writer)
}
}

private static IpcMessage CreateUserEventsCapabilityProbeMessage()
{
byte[] payload = SerializePayload(UserEventsProbePayload);
return new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.CollectTracing5, payload);
}

private static IpcMessage CreateAttachProfilerMessage(TimeSpan attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData)
{
if (profilerGuid == null || profilerGuid == Guid.Empty)
Expand Down Expand Up @@ -763,6 +784,27 @@ private static ProcessInfo TryGetProcessInfo3FromResponse(IpcResponse response,
return ProcessInfo.ParseV3(response.Message.Payload);
}

private static bool IsCommandSupportedFromResponse(IpcMessage responseMessage)
{
switch ((DiagnosticsServerResponseId)responseMessage.Header.CommandId)
{
case DiagnosticsServerResponseId.OK:
return true;

case DiagnosticsServerResponseId.Error:
if (responseMessage.Payload == null || responseMessage.Payload.Length < sizeof(uint))
{
return false;
}

uint hr = BinaryPrimitives.ReadUInt32LittleEndian(new ReadOnlySpan<byte>(responseMessage.Payload, 0, sizeof(uint)));
return hr != (uint)DiagnosticsIpcError.UnknownCommand;

default:
return false;
}
}

internal static bool ValidateResponseMessage(IpcMessage responseMessage, string operationName, ValidateResponseOptions options = ValidateResponseOptions.None)
{
switch ((DiagnosticsServerResponseId)responseMessage.Header.CommandId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal enum EventPipeCommandId : byte
CollectTracing2 = 0x03,
CollectTracing3 = 0x04,
CollectTracing4 = 0x05,
CollectTracing5 = 0x06,
}

internal enum DumpCommandId : byte
Expand Down
Loading