| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| library fuchsia.hardware.cpu.insntrace; |
| |
| using zx; |
| |
| const uint16 API_VERSION = 0; |
| |
| /// The maximum number of traces that can be collected at once. |
| /// A "trace" is the instruction stream for one entity, cpu or thread. |
| const uint16 MAX_NUM_TRACES = 64; |
| |
| /// The maximum number of supported address ranges. |
| const uint16 MAX_NUM_ADDR_RANGES = 2; |
| |
| /// Tracing modes |
| enum Mode : uint8 { |
| // Trace each cpu, regardless of what's running on it. |
| CPU = 0; |
| // Trace specific threads. |
| THREAD = 1; |
| }; |
| |
| /// The allocation configuration of a trace. |
| struct Allocation { |
| Mode mode; |
| |
| // The number of traces to create. |
| // In CPU mode this must be zx_system_get_num_cpus(). |
| // In THREAD mode this is the maximum number of threads for which traces |
| // will be collected. Buffer space is allocated on demand, but the |
| // underlying data structure has a maximum. This value can be at most |
| // MAX_NUM_TRACES. |
| uint16 num_traces; |
| }; |
| |
| /// An address range, as [start,end]. |
| struct AddressRange { |
| uint64 start; |
| uint64 end; |
| }; |
| |
| /// A buffer's configuration. |
| struct BufferConfig { |
| /// A "buffer" is made up of `num_chunks` chunks with each chunk having |
| /// size `1<<chunk_order` pages. |
| uint32 num_chunks; |
| |
| /// log2 of the number of pages |
| uint32 chunk_order; |
| |
| /// If true then use circular buffering. |
| bool is_circular; |
| |
| /// The value of the control register. |
| uint64 ctl; |
| |
| /// If non-zero then the address space of the instruction must match in |
| /// order for the instruction to be traced. On x86 architectures the |
| /// address space is specified by CR3. |
| uint64 address_space_match; |
| |
| /// If non-zero, tracing is restricted to these address ranges. |
| /// TODO(dje): There's only two, and vectors don't currently work here, |
| /// so spell these out individually |
| AddressRange address_range_0; |
| AddressRange address_range_1; |
| }; |
| |
| /// A buffer's runtime state. |
| struct BufferState { |
| /// This is the offset in the buffer where tracing stopped (treating all |
| /// buffers as one large one). If using a circular buffer then all of the |
| /// buffer may contain data, there's no current way to know if tracing |
| /// wrapped without scanning records. |
| uint64 capture_end; |
| }; |
| |
| alias BufferDescriptor = uint32; |
| |
| protocol Controller { |
| /// Initialize the trace. |
| /// This does not include allocating space for the trace buffers, that is |
| /// done later by `AllocateBuffer()`. |
| Initialize(Allocation allocation) -> () error zx.status; |
| |
| /// Free all trace buffers and any other resources allocated for the trace. |
| /// This is also done when the connection is closed (as well as stopping |
| /// the trace). |
| /// May be called multiple times. |
| /// This can only fail when tracing in THREAD mode where tracing is |
| /// terminated differently, in which case the error is `ZX_ERR_BAD_STATE`. |
| // TODO(fxbug.dev/30840): Support terminating the trace in THREAD mode. |
| Terminate() -> () error zx.status; |
| |
| /// Return the trace allocation configuration. |
| GetAllocation() -> (Allocation? allocation); |
| |
| /// Allocate a trace buffer. |
| /// When tracing cpus, buffers are auto-assigned to cpus: the resulting |
| /// trace buffer descriptor is the number of the cpu using the buffer. |
| AllocateBuffer(BufferConfig config) -> (BufferDescriptor descriptor) error zx.status; |
| |
| /// Assign a buffer to a thread. |
| AssignThreadBuffer(BufferDescriptor descriptor, zx.handle:THREAD thread) -> () error zx.status; |
| |
| /// Release a previously assigned buffer from a thread. |
| ReleaseThreadBuffer(BufferDescriptor descriptor, zx.handle:THREAD thread) -> () error zx.status; |
| |
| /// Fetch a buffer's configuration. |
| GetBufferConfig(BufferDescriptor descriptor) -> (BufferConfig? config); |
| |
| /// Fetch runtime information about a buffer. |
| GetBufferState(BufferDescriptor descriptor) -> (BufferState? state); |
| |
| /// Fetch the handle of a chunk of a trace buffer. |
| GetChunkHandle(BufferDescriptor descriptor, uint32 chunk_num) -> (zx.handle:VMO? buffer); |
| |
| /// Free a previously allocated trace buffer. |
| FreeBuffer(BufferDescriptor descriptor) -> (); |
| |
| /// Start tracing. |
| /// Must be called after `Initialize()` + `AllocateBuffer()`, |
| /// with tracing off. |
| Start() -> (); |
| |
| /// Stop tracing. |
| /// May be called any time after `Allocate()` has been called and before |
| /// `Free()`. If called at other times the call is ignored. |
| /// May be called multiple times. |
| // TODO(fxbug.dev/30840): Support terminating the trace in THREAD mode. |
| Stop() -> (); |
| }; |