Skip to main content

riscv_etrace/
lib.rs

1// Copyright (C) 2024 - 2026 FZI Forschungszentrum Informatik
2// SPDX-License-Identifier: Apache-2.0
3//! # Decoder and tracer for RISC-V E-Traces
4//!
5//! This library provides a [packet] decoder and encoder a [tracer] as well as
6//! a payload [generator] for the instruction tracing defined in the [Efficient
7//! Trace for RISC-V][etrace] specification. Given trace packets previously
8//! retrieved from an encoder and the traced program, the [tracer] allows
9//! reconstructing the execution path. The [generator], on the other hand,
10//! serves as a software implementation for a trace encoder.
11//!
12//! This library also features a limited [instruction] database with decoding
13//! functionality. Currently, only decoding of RV32IC and RV64IC instructions
14//! are supported. However, tracing is not impacted by other instructions that
15//! do not influence the control flow ("control transfer instructions").
16//!
17//! # Tracing flow
18//!
19//! Raw trace data needs to be decoded via [`packet::decoder::Decoder`]s, which
20//! are constructed via a [`packet::Builder`]. A builder is usually configured
21//! for a trace [`Unit`][packet::unit::Unit] implementation with specific
22//! [`config::Parameters`].
23//!
24//! A decoded packet or [`Payload`][packet::payload::Payload] payload needs to
25//! be dispatched to the [`Tracer`][tracer::Tracer] for that RISC-V hart. It is
26//! the responsibility of the library user to do so.
27//!
28//! A [`Tracer`][tracer::Tracer] processes packets and generates a series of
29//! tracing [`Item`][tracer::item::Item]s. It is constructed via a
30//! [`tracer::Builder`], which is configured for the specific program
31//! being traced (in the form of a [`Binary`][binary::Binary]) and the same
32//! [`config::Parameters`] that the decoder was configured with.
33//!
34//! [`Binary`][binary::Binary] is a trait abstracting access to
35//! [`Instruction`][instruction::Instruction]s. This library provides a number
36//! of implementations and utilities for constructing one, including limited
37//! instruction decoding capabilities.
38//!
39//! # E-Trace options
40//!
41//! The following [E-Trace][etrace] options are supported:
42//! * delta/full address mode
43//! * sequentially inferred jumps
44//! * implicit return ([tracer] only, known to be broken by specification)
45//!
46//! # Crate features
47//!
48//! Some functionality if controlled via crate features:
49//! * `alloc`: enables some features that require allocation
50//! * `either`: enables impls of various traits for [`either::Either`]
51//! * `elf`: enables the [`binary::elf`] module providing a
52//!   [`Binary`][binary::Binary] for static ELF files using the [`elf`] crate
53//! * `riscv-isa`: enables support for decoding and tracing
54//!   [`riscv_isa::Instruction`]s instead of [`instruction::Kind`].
55//! * `serde`: enables (de)serialization of configuration via [`serde`]
56//!
57//! # no_std
58//!
59//! This crate does not dependent on `std` and is thus suitable for `no_std`
60//! environments.
61//!
62//! # Example
63//!
64//! The following example demonstrates basic instruction tracing, with default
65//! [`config::Parameters`], a simple [`Binary`][binary::Binary] and tracing
66//! packets conforming to the [Unformatted Trace & Diagnostic Data Packet
67//! Encapsulation for RISC-V][encap] specification placed in a single buffer.
68//!
69//! ```
70//! use riscv_etrace::binary::{self, Adaptable};
71//! use riscv_etrace::packet;
72//! use riscv_etrace::instruction::{base, Instruction};
73//! use riscv_etrace::tracer::{self, Tracer};
74//!
75//! # let binary_data = b"\x14\x41\x11\x05\x94\xc1\x91\x05\xe3\xec\xc5\xfe\x82\x80";
76//! # let binary_offset = 0x80000028;
77//! # let trace_data = b"\x45\x73\x0a\x00\x00\x20\x41\x01";
78//! # let hart_to_trace = 0;
79//! let binary = binary::from_segment(binary_data, base::Set::Rv32I)
80//!     .with_offset(binary_offset);
81//!
82//! let parameters = Default::default();
83//! let mut decoder = packet::builder()
84//!     .with_params(&parameters)
85//!     .decoder(trace_data);
86//! let mut tracer: Tracer<_> = tracer::builder()
87//!     .with_binary(binary)
88//!     .with_params(&parameters)
89//!     .build()
90//!     .unwrap();
91//!
92//! while decoder.bytes_left() > 0 {
93//!     let packet = decoder.decode_encap_packet().unwrap().into_normal();
94//!     if let Some(packet) = packet.filter(|p| p.src_id() == hart_to_trace) {
95//!         let payload = packet.decode_payload().unwrap();
96//!         eprintln!("{payload:?}");
97//!         tracer.process_payload(&payload).unwrap();
98//!         tracer.by_ref().for_each(|i| {
99//!             let item = i.unwrap();
100//!             if let Some(info) = item.trap() {
101//!                 println!("Trap! EPC={:0x}, interrupt={}", item.pc(), info.is_interrupt());
102//!             } else {
103//!                 println!("PC: {:0x}", item.pc());
104//!             }
105//!         });
106//!     }
107//! }
108//! ```
109//!
110//! [etrace]: <https://github.com/riscv-non-isa/riscv-trace-spec/>
111//! [encap]: <https://github.com/riscv-non-isa/e-trace-encap/>
112#![no_std]
113#![cfg_attr(docsrs, feature(doc_cfg))]
114
115#[cfg(feature = "alloc")]
116extern crate alloc;
117
118#[cfg(test)]
119mod tests;
120
121pub mod binary;
122pub mod config;
123pub mod generator;
124pub mod instruction;
125pub mod packet;
126pub mod tracer;
127pub mod types;