blob: b300e4ba3033b1127487febbcfdf19e551e7c499 [file] [log] [blame] [view]
# Intel Processor Trace driver
See Chapter 36 of the Intel Architecture Software Developer's Manual.
## Trace modes
There are two modes of tracing:
- per cpu
- specified threads (not implemented yet)
Only one may be active at a time.
### Per CPU tracing
In this mode of operation each cpu is traced, regardless of what is
running on the cpu, except as can be controlled by PT configuration MSRs
(e.g., cr3 filtering, kernel/user, address filtering).
### Specified thread tracing
In this mode of operation individual threads are traced, even as they
migrate from CPU to CPU. This is achieved via the PT state save/restore
capabilities of the XSAVES and XRSTORS instructions.
Filtering control (e.g., cr3, user/kernel) is not available in this mode.
Address filtering is possible, but is still TODO.
## IOCTLs
Several ioctls are provided to control tracing.
### *ioctl_ipt_alloc_trace*
```
ssize_t ioctl_ipt_alloc_trace(int fd, const ioctl_ipt_trace_config_t* config);
```
Request the kernel allocate the needed internal data structures for
managing IPT.
Returns zero on success or a negative error code.
### *ioctl_ipt_free_trace*
```
ssize_t ioctl_ipt_free_trace(int fd);
```
Request the kernel free all internal data structures for managing IPT.
Returns zero on success or a negative error code.
### *ioctl_ipt_get_trace_config*
```
ssize_t ioctl_ipt_get_trace_config(int fd,
const uint32_t* descriptor,
ioctl_ipt_trace_config_t* out_config);
```
Return the trace configuration.
Returns *sizeof(\*out_config)* on success or a negative error code.
### *ioctl_ipt_alloc_buffer*
```
ssize_t ioctl_ipt_alloc_buffer(int fd,
const ioctl_ipt_buffer_config_t* config,
uint32_t* out_descriptor);
```
Allocate an IPT buffer defined by |config| and return its buffer descriptor
in *|\*out_descriptor|*.
The descriptor is just an integer to identify the buffer.
When tracing in cpu mode the descriptor is the number of the cpu
that the buffer will be assigned to.
Returns *sizeof(\*out_descriptor)* on success or a negative error code.
### *ioctl_ipt_get_buffer_config*
```
ssize_t ioctl_ipt_get_buffer_config(int fd,
const uint32_t* descriptor,
ioctl_ipt_buffer_config_t* out_config);
```
Return the trace configuration.
Returns *sizeof(\*out_config)* on success or a negative error code.
### *ioctl_ipt_get_buffer_info*
```
ssize_t ioctl_ipt_get_buffer_info(int fd,
const uint32_t* descriptor,
ioctl_ipt_buffer_info_t* out_info);
```
Return info of the resulting trace of the specified buffer.
Currently this is the place in the buffer where tracing stopped,
treating the set of buffers as one large virtual buffer.
If not using circular buffers then this is the amount of data captured.
If using circular buffers then this is where tracing stopped.
Returns *sizeof(\*out_data)* on success or a negative error code.
### *ioctl_ipt_get_chunk_handle*
```
ssize_t ioctl_ipt_get_chunk_handle(int fd,
const ioctl_ipt_chunk_handle_req_t* req,
zx_handle_t* out_handle);
```
Return the handle of the requested VMO with buffer data.
IPT buffers can be spread out over multiple VMOs as specified when the
buffer was configured. This call returns the handle of one of them.
Multiple calls are required to fetch the handle for each VMO.
Returns *sizeof(\*out_handle)* on success or a negative error code.
### *ioctl_ipt_free_buffer*
```
ssize_t ioctl_ipt_free_buffer(int fd,
const uint32_t* descriptor);
```
Free the specified buffer and all associated VMOs.
The caller still needs to free its own handles of the VMOs.
Returns zero on success or a negative error code.
### *ioctl_ipt_start*
```
ssize_t ioctl_ipt_start(int fd);
```
Begin tracing.
One buffer must have already been allocated for each cpu
with *ioctl_ipt_alloc_buffer*.
Returns zero on success or a negative error code.
### *ioctl_ipt_stop*
```
ssize_t ioctl_ipt_stop(int fd);
```
Stop tracing.
Internally, status of the tracing of each cpu is collected for later
retrieval with *ioctl_ipt_get_buffer_info()*.
Returns zero on success or a negative error code.
## Usage
Here's a sketch of typical usage when tracing in cpu mode.
1) *ioctl_ipt_alloc_trace()*
2) allocate buffers for each cpu
3) *ioctl_ipt_start()*
4) launch program one wishes to trace
5) *ioctl_ipt_stop()*
6) fetch buffer data for each cpu
7) fetch handles for each vmo in each buffer
8) *ioctl_ipt_free_trace()*
9) post-process
10) free buffers
## Notes
- We currently only support Table of Physical Addresses mode so that
we can also support stop-on-full behavior in addition to wrap-around.
- Each cpu has the same size trace buffer.
- While it's possible to allocate and configure buffers outside of the driver,
this is not done so that we have control over their contents. ToPA buffers
must have specific contents or Bad Things can happen.
## TODOs (beyond those in the source)
- support tracing individual threads using xsaves
- handle driver crashes
- need to turn off tracing
- need to keep buffer/table vmos alive until tracing is off