Skip to content
Merged
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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,9 @@ functionality without actually doing any changes to their code.
A default post-instruction callback is provided for storing the
register tracing data in files. It persists the register sets,
the SBPF instructions, and a SHA-256 hash identifying the executable that
was used to generate the tracing data. The motivation behind providing the
was used to generate the tracing data. If the `SBF_TRACE_DISASSEMBLE`
environment variable is set, a disassembled register trace will also be
produced for each collected register trace. The motivation behind providing the
SHA-256 identifier is that files may grow in number, and consumers need a
deterministic way to evaluate which shared object should be used when
analyzing the tracing data.
Expand Down Expand Up @@ -637,5 +639,6 @@ mollusk.invocation_inspect_callback = Box::new(EmptyInvocationInspectCallback {}
mollusk.invocation_inspect_callback =
Box::new(register_tracing::DefaultRegisterTracingCallback {
sbf_trace_dir: std::env::var("SBF_TRACE_DIR").unwrap(),
sbf_trace_disassemble: std::env::var("SBF_TRACE_DISASSEMBLE").is_ok(),
});
```
35 changes: 35 additions & 0 deletions harness/src/register_tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,41 @@ const DEFAULT_PATH: &str = "target/sbf/trace";

pub struct DefaultRegisterTracingCallback {
pub sbf_trace_dir: String,
pub sbf_trace_disassemble: bool,
}

impl Default for DefaultRegisterTracingCallback {
fn default() -> Self {
Self {
// User can override default path with `SBF_TRACE_DIR` environment variable.
sbf_trace_dir: std::env::var("SBF_TRACE_DIR").unwrap_or(DEFAULT_PATH.to_string()),
sbf_trace_disassemble: std::env::var("SBF_TRACE_DISASSEMBLE").is_ok(),
}
}
}

impl DefaultRegisterTracingCallback {
pub fn disassemble_register_trace<W: std::io::Write>(
&self,
writer: &mut W,
program_id: &Pubkey,
executable: &Executable,
register_trace: RegisterTrace,
) {
match solana_program_runtime::solana_sbpf::static_analysis::Analysis::from_executable(
executable,
) {
Ok(analysis) => {
if let Err(e) = analysis.disassemble_register_trace(writer, register_trace) {
eprintln!("Can't disassemble register trace for {program_id}: {e:#?}");
}
}
Err(e) => {
eprintln!("Can't create trace disassemble analysis for {program_id}: {e:#?}")
}
}
}

pub fn handler(
&self,
mollusk: &Mollusk,
Expand All @@ -47,6 +70,18 @@ impl DefaultRegisterTracingCallback {

// Get program_id.
let program_id = instruction_context.get_program_key()?;

// Persist a full trace disassembly if requested.
if self.sbf_trace_disassemble {
let mut trace_disassemble_file = File::create(base_fname.with_extension("trace"))?;
self.disassemble_register_trace(
&mut trace_disassemble_file,
program_id,
executable,
register_trace,
);
}

// Persist the program id.
let _ = program_id_file.write(program_id.to_string().as_bytes());

Expand Down