| // 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 API_VERSION uint16 = 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 MAX_NUM_TRACES uint16 = 64; |
| |
| /// The maximum number of supported address ranges. |
| const MAX_NUM_ADDR_RANGES uint16 = 2; |
| |
| /// Tracing modes |
| type Mode = strict enum : uint8 { |
| // Trace each cpu, regardless of what's running on it. |
| CPU = 0; |
| // Trace specific threads. |
| THREAD = 1; |
| }; |
| |
| /// The allocation configuration of a trace. |
| type Allocation = struct { |
| 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. |
| num_traces uint16; |
| }; |
| |
| /// An address range, as [start,end]. |
| type AddressRange = struct { |
| start uint64; |
| end uint64; |
| }; |
| |
| /// A buffer's configuration. |
| type BufferConfig = struct { |
| /// A "buffer" is made up of `num_chunks` chunks with each chunk having |
| /// size `1<<chunk_order` pages. |
| num_chunks uint32; |
| |
| /// log2 of the number of pages |
| chunk_order uint32; |
| |
| /// If true then use circular buffering. |
| is_circular bool; |
| |
| /// The value of the control register. |
| ctl uint64; |
| |
| /// 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. |
| address_space_match uint64; |
| |
| /// 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 |
| address_range_0 AddressRange; |
| address_range_1 AddressRange; |
| }; |
| |
| /// A buffer's runtime state. |
| type BufferState = struct { |
| /// 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. |
| capture_end uint64; |
| }; |
| |
| 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(struct { |
| allocation Allocation; |
| }) -> (struct {}) 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() -> (struct {}) error zx.status; |
| |
| /// Return the trace allocation configuration. |
| GetAllocation() -> (struct { |
| allocation box<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(struct { |
| config BufferConfig; |
| }) -> (struct { |
| descriptor BufferDescriptor; |
| }) error zx.status; |
| |
| /// Assign a buffer to a thread. |
| AssignThreadBuffer(resource struct { |
| descriptor BufferDescriptor; |
| thread zx.handle:THREAD; |
| }) -> (struct {}) error zx.status; |
| |
| /// Release a previously assigned buffer from a thread. |
| ReleaseThreadBuffer(resource struct { |
| descriptor BufferDescriptor; |
| thread zx.handle:THREAD; |
| }) -> (struct {}) error zx.status; |
| |
| /// Fetch a buffer's configuration. |
| GetBufferConfig(struct { |
| descriptor BufferDescriptor; |
| }) -> (struct { |
| config box<BufferConfig>; |
| }); |
| |
| /// Fetch runtime information about a buffer. |
| GetBufferState(struct { |
| descriptor BufferDescriptor; |
| }) -> (struct { |
| state box<BufferState>; |
| }); |
| |
| /// Fetch the handle of a chunk of a trace buffer. |
| GetChunkHandle(struct { |
| descriptor BufferDescriptor; |
| chunk_num uint32; |
| }) -> (resource struct { |
| buffer zx.handle:<VMO, optional>; |
| }); |
| |
| /// Free a previously allocated trace buffer. |
| FreeBuffer(struct { |
| descriptor BufferDescriptor; |
| }) -> (); |
| |
| /// 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() -> (); |
| }; |