From d7cf79a0925363c08a82ddbac7a2e9590887817c Mon Sep 17 00:00:00 2001 From: David Venhoff Date: Fri, 12 Sep 2025 11:54:10 +0200 Subject: [PATCH] Add anyhow for better errors --- Cargo.lock | 70 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- src/benchmark_nyx_no_pt.rs | 3 +- src/benchmark_nyx_pt.rs | 3 +- src/main.rs | 9 +++-- src/nyx.rs | 38 ++++++++++++--------- 6 files changed, 99 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 334f1c9..4232fc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -61,12 +76,36 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +dependencies = [ + "backtrace", +] + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "base-x" version = "0.2.11" @@ -421,6 +460,12 @@ dependencies = [ "wasi 0.14.5+wasi-0.2.4", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.3" @@ -573,6 +618,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "nix" version = "0.26.4" @@ -618,6 +672,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -692,6 +755,7 @@ dependencies = [ name = "qemu-nyx-runner" version = "0.1.0" dependencies = [ + "anyhow", "clap", "csv", "libnyx", @@ -809,6 +873,12 @@ dependencies = [ "serde", ] +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "rustc-hash" version = "2.1.1" diff --git a/Cargo.toml b/Cargo.toml index f33f712..5f93a78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ libnyx = { git = "https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork" } pt-dump-decoder = { path = "pt-dump-decoder" } csv = "1.3.1" clap.workspace = true +anyhow = { version = "1.0.99", features = ["backtrace"] } [workspace.dependencies] -clap = { version = "4.5.47", features = ["derive"] } \ No newline at end of file +clap = { version = "4.5.47", features = ["derive"] } diff --git a/src/benchmark_nyx_no_pt.rs b/src/benchmark_nyx_no_pt.rs index cdc43b9..5d8e403 100644 --- a/src/benchmark_nyx_no_pt.rs +++ b/src/benchmark_nyx_no_pt.rs @@ -1,13 +1,12 @@ use crate::benchmark::Benchmark; use crate::nyx::{NyxRunner, TraceMode}; -use std::error::Error; use std::path::Path; use std::time::Duration; pub struct BenchmarkNyxNoPt(NyxRunner); impl BenchmarkNyxNoPt { - pub fn new(client_path: &Path) -> Result> { + pub fn new(client_path: &Path) -> anyhow::Result { Ok(BenchmarkNyxNoPt(NyxRunner::setup( client_path, TraceMode::Disabled, diff --git a/src/benchmark_nyx_pt.rs b/src/benchmark_nyx_pt.rs index 8e789aa..edbbf3c 100644 --- a/src/benchmark_nyx_pt.rs +++ b/src/benchmark_nyx_pt.rs @@ -2,14 +2,13 @@ use crate::benchmark::{Benchmark, ToCsv}; use crate::nyx::{NyxRunner, TraceMode}; use csv::Writer; use pt_dump_decoder::{AnalyzeData, analyze_dump}; -use std::error::Error; use std::io::Write; use std::path::Path; pub struct BenchmarkNyx(NyxRunner); impl BenchmarkNyx { - pub fn new(client_bin: &Path) -> Result> { + pub fn new(client_bin: &Path) -> anyhow::Result { Ok(BenchmarkNyx(NyxRunner::setup( client_bin, TraceMode::Enabled, diff --git a/src/main.rs b/src/main.rs index 8eb8434..a6154e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,6 @@ use crate::benchmark_baseline::Baseline; use crate::benchmark_nyx_no_pt::BenchmarkNyxNoPt; use crate::benchmark_nyx_pt::BenchmarkNyx; use clap::Parser; -use std::error::Error; use std::fmt::Debug; use std::fs; use std::path::{Path, PathBuf}; @@ -30,7 +29,7 @@ struct Args { debug: bool, } -fn main() -> Result<(), Box> { +fn main() -> anyhow::Result<()> { let args = Args::parse(); if args.debug { @@ -56,7 +55,7 @@ fn benchmark( binary_name: &str, output_dir: &Path, mut benchmark: B, -) -> Result<(), Box> { +) -> anyhow::Result<()> { warmup(&mut benchmark); let results = benchmark_loop(&mut benchmark); write_results::(binary_name, output_dir, &results)?; @@ -89,10 +88,10 @@ fn write_results( binary_name: &str, output_dir: &Path, results: &[B::BenchmarkResult], -) -> Result<(), Box> { +) -> anyhow::Result<()> { fs::create_dir_all(output_dir)?; let filename = format!("benchmark_{binary_name}_{}", B::TITLE); - let file = std::fs::File::create(output_dir.join(filename))?; + let file = fs::File::create(output_dir.join(filename))?; let mut writer = csv::WriterBuilder::new().from_writer(file); writer.write_record(B::BenchmarkResult::HEADERS)?; for result in results { diff --git a/src/nyx.rs b/src/nyx.rs index b98e8b2..620a558 100644 --- a/src/nyx.rs +++ b/src/nyx.rs @@ -1,8 +1,8 @@ //! This module contains functionality to download and setup nyx, //! so that it can be used to execute a binary. +use anyhow::{Context, anyhow, bail}; use libnyx::{NyxConfig, NyxProcess, NyxProcessRole, NyxReturnValue}; -use std::error::Error; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Duration; @@ -19,7 +19,7 @@ pub enum TraceMode { pub struct NyxRunner(NyxProcess); impl NyxRunner { - pub fn setup(client_bin: &Path, trace_mode: TraceMode) -> Result> { + pub fn setup(client_bin: &Path, trace_mode: TraceMode) -> anyhow::Result { if let Err(e) = fs::remove_dir_all(WORKDIR_PATH) && !matches!(e.kind(), io::ErrorKind::NotFound) { @@ -28,7 +28,9 @@ impl NyxRunner { let sharedir = setup_nyx(&PathBuf::from("nyx_data"), client_bin)?; let sharedir = sharedir.to_str().expect("Expected unicode path"); - let mut nyx_config = NyxConfig::load(sharedir)?; + let mut nyx_config = NyxConfig::load(sharedir) + .map_err(|err| anyhow!(err)) + .with_context(|| "Creating nyx config")?; nyx_config.set_workdir_path(WORKDIR_PATH.to_string()); nyx_config.set_input_buffer_size(0x2000); nyx_config.set_nyx_debug_log_path("qemu_nyx.log".to_string()); @@ -37,7 +39,9 @@ impl NyxRunner { nyx_config.set_process_role(NyxProcessRole::StandAlone); nyx_config.print(); - let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0)?; + let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0) + .map_err(|err| anyhow!(err)) + .with_context(|| "Creating Nyx Process")?; nyx_runner.option_set_trace_mode(true); nyx_runner.option_set_reload_mode(false); @@ -79,30 +83,31 @@ impl Drop for NyxRunner { /// [client] Is the path to the client binary. /// /// Returns the path to the working directory -pub fn setup_nyx(out_dir: &Path, client: &Path) -> Result { - fn inner(out_dir: &Path, client: &Path) -> Result { +pub fn setup_nyx(out_dir: &Path, client: &Path) -> anyhow::Result { + fn inner(out_dir: &Path, client: &Path) -> anyhow::Result { if !out_dir.exists() { fs::create_dir(out_dir)?; } println!("Installing nyx..."); - setup_nyx_tools(out_dir)?; + setup_nyx_tools(out_dir).with_context(|| "Setting up nyx tools")?; - create_nyx_workdir(out_dir, client) + create_nyx_workdir(out_dir, client).with_context(|| "Creating the nyx working directory") } // Clean up the out directory if something went wrong match inner(out_dir, client) { Ok(path) => Ok(path), Err(err) => { - fs::remove_dir_all(out_dir)?; + fs::remove_dir_all(out_dir) + .with_context(|| format!("Error while handling error: {err}"))?; Err(err) } } } #[track_caller] -fn shell(cwd: impl AsRef, command_string: &str) -> Result<(), io::Error> { +fn shell(cwd: impl AsRef, command_string: &str) -> anyhow::Result<()> { println!("Running ({}) {command_string}", cwd.as_ref().display()); let cwd = cwd.as_ref(); @@ -118,9 +123,7 @@ fn shell(cwd: impl AsRef, command_string: &str) -> Result<(), io::Error> { let mut process = command.spawn()?; let exit_status = process.wait()?; if !exit_status.success() { - return Err(io::Error::other(format!( - "Command ({command_string}) failed with {exit_status}" - ))); + bail!("Command ({command_string}) failed with {exit_status}"); } Ok(()) @@ -128,7 +131,7 @@ fn shell(cwd: impl AsRef, command_string: &str) -> Result<(), io::Error> { /// Downloads and compiles qemu-nyx and packer and compiles them for the current architecture /// This means that cross-compilation is not supported -fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> { +fn setup_nyx_tools(out_dir: &Path) -> anyhow::Result<()> { let packer_path = out_dir.join("packer"); let qemu_path = out_dir.join("QEMU-Nyx"); if !packer_path.exists() { @@ -142,7 +145,7 @@ fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> { )?; // Compile with maximum optimizations - let qemu_compile_mode = "lto"; + let qemu_compile_mode = "debug_static"; shell( qemu_path, &format!("bash compile_qemu_nyx.sh {qemu_compile_mode}"), @@ -152,8 +155,9 @@ fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> { Ok(()) } -fn create_nyx_workdir(out_dir: &Path, client_bin: &Path) -> Result { - let client_bin = fs::canonicalize(client_bin)?; +fn create_nyx_workdir(out_dir: &Path, client_bin: &Path) -> anyhow::Result { + let client_bin = + fs::canonicalize(client_bin).with_context(|| format!("canonicalizing {client_bin:?}"))?; let client_bin = client_bin.to_str().expect("Expected unicode path"); // Create the directory and move required binaries to it shell(