From 4db4706674df67b141ce3f73d57acffa456a2fca Mon Sep 17 00:00:00 2001 From: Andrey Fedotov Date: Thu, 8 Feb 2024 16:30:39 +0300 Subject: [PATCH] Add --strip-path option to strip paths for stacktrace and crash line (#199) --- casr/src/bin/casr-gdb.rs | 12 +++++ casr/src/bin/casr-java.rs | 16 ++++++- casr/src/bin/casr-js.rs | 16 ++++++- casr/src/bin/casr-python.rs | 16 ++++++- casr/src/bin/casr-san.rs | 12 +++++ casr/src/util.rs | 32 ++++++++++++- casr/tests/tests.rs | 3 +- docs/usage.md | 89 ++++++++++++++++++++----------------- 8 files changed, 148 insertions(+), 48 deletions(-) diff --git a/casr/src/bin/casr-gdb.rs b/casr/src/bin/casr-gdb.rs index 2b62eb41..013423b8 100644 --- a/casr/src/bin/casr-gdb.rs +++ b/casr/src/bin/casr-gdb.rs @@ -79,6 +79,14 @@ fn main() -> Result<()> { .value_parser(clap::value_parser!(PathBuf)) .help("File with regular expressions for functions and file paths that should be ignored"), ) + .arg( + Arg::new("strip-path") + .long("strip-path") + .env("CASR_STRIP_PATH") + .action(ArgAction::Set) + .value_name("PREFIX") + .help("Path prefix to strip from stacktrace and crash line"), + ) .arg( Arg::new("ARGS") .action(ArgAction::Set) @@ -257,6 +265,10 @@ fn main() -> Result<()> { } } + if let Some(path) = matches.get_one::("strip-path") { + util::strip_paths(&mut report, &parsed_stacktrace, path); + } + //Output report util::output_report(&report, &matches, &argv) } diff --git a/casr/src/bin/casr-java.rs b/casr/src/bin/casr-java.rs index 7fef0b84..2f544657 100644 --- a/casr/src/bin/casr-java.rs +++ b/casr/src/bin/casr-java.rs @@ -74,6 +74,14 @@ fn main() -> Result<()> { .value_name("FILE") .help("File with regular expressions for functions and file paths that should be ignored"), ) + .arg( + Arg::new("strip-path") + .long("strip-path") + .env("CASR_STRIP_PATH") + .action(ArgAction::Set) + .value_name("PREFIX") + .help("Path prefix to strip from stacktrace and crash line"), + ) .arg( Arg::new("ARGS") .action(ArgAction::Set) @@ -157,8 +165,8 @@ fn main() -> Result<()> { // Call casr-san return util::call_casr_san(&matches, &argv, "casr-java"); } - - if let Ok(crash_line) = JavaStacktrace::parse_stacktrace(&report.stacktrace)?.crash_line() { + let stacktrace = JavaStacktrace::parse_stacktrace(&report.stacktrace)?; + if let Ok(crash_line) = stacktrace.crash_line() { report.crashline = crash_line.to_string(); if let CrashLine::Source(mut debug) = crash_line { // Modify DebugInfo to find sources @@ -190,6 +198,10 @@ fn main() -> Result<()> { } } + if let Some(path) = matches.get_one::("strip-path") { + util::strip_paths(&mut report, &stacktrace, path); + } + //Output report util::output_report(&report, &matches, &argv) } diff --git a/casr/src/bin/casr-js.rs b/casr/src/bin/casr-js.rs index 875b4eb7..8ac68fad 100644 --- a/casr/src/bin/casr-js.rs +++ b/casr/src/bin/casr-js.rs @@ -62,6 +62,14 @@ fn main() -> Result<()> { .value_name("FILE") .help("File with regular expressions for functions and file paths that should be ignored"), ) + .arg( + Arg::new("strip-path") + .long("strip-path") + .env("CASR_STRIP_PATH") + .action(ArgAction::Set) + .value_name("PREFIX") + .help("Path prefix to strip from stacktrace and crash line"), + ) .arg( Arg::new("ARGS") .action(ArgAction::Set) @@ -155,8 +163,8 @@ fn main() -> Result<()> { modified_argv[0] = path_to_tool.to_str().unwrap_or(argv[0]); return util::call_casr_san(&matches, &modified_argv, "casr-js"); } - - if let Ok(crash_line) = JsStacktrace::parse_stacktrace(&report.stacktrace)?.crash_line() { + let stacktrace = JsStacktrace::parse_stacktrace(&report.stacktrace)?; + if let Ok(crash_line) = stacktrace.crash_line() { report.crashline = crash_line.to_string(); if let CrashLine::Source(debug) = crash_line { if let Some(sources) = CrashReport::sources(&debug) { @@ -165,6 +173,10 @@ fn main() -> Result<()> { } } + if let Some(path) = matches.get_one::("strip-path") { + util::strip_paths(&mut report, &stacktrace, path); + } + //Output report util::output_report(&report, &matches, &argv) } diff --git a/casr/src/bin/casr-python.rs b/casr/src/bin/casr-python.rs index 12a68975..b7ace1bf 100644 --- a/casr/src/bin/casr-python.rs +++ b/casr/src/bin/casr-python.rs @@ -66,6 +66,14 @@ fn main() -> Result<()> { .value_name("FILE") .help("File with regular expressions for functions and file paths that should be ignored"), ) + .arg( + Arg::new("strip-path") + .long("strip-path") + .env("CASR_STRIP_PATH") + .action(ArgAction::Set) + .value_name("PREFIX") + .help("Path prefix to strip from stacktrace"), + ) .arg( Arg::new("ARGS") .action(ArgAction::Set) @@ -175,8 +183,8 @@ fn main() -> Result<()> { // Call casr-san return util::call_casr_san(&matches, &argv, "casr-python"); } - - if let Ok(crash_line) = PythonStacktrace::parse_stacktrace(&report.stacktrace)?.crash_line() { + let stacktrace = PythonStacktrace::parse_stacktrace(&report.stacktrace)?; + if let Ok(crash_line) = stacktrace.crash_line() { report.crashline = crash_line.to_string(); if let CrashLine::Source(debug) = crash_line { if let Some(sources) = CrashReport::sources(&debug) { @@ -185,6 +193,10 @@ fn main() -> Result<()> { } } + if let Some(path) = matches.get_one::("strip-path") { + util::strip_paths(&mut report, &stacktrace, path); + } + //Output report util::output_report(&report, &matches, &argv) } diff --git a/casr/src/bin/casr-san.rs b/casr/src/bin/casr-san.rs index c2b338a5..7b25dd15 100644 --- a/casr/src/bin/casr-san.rs +++ b/casr/src/bin/casr-san.rs @@ -83,6 +83,14 @@ fn main() -> Result<()> { .value_parser(clap::value_parser!(PathBuf)) .help("File with regular expressions for functions and file paths that should be ignored"), ) + .arg( + Arg::new("strip-path") + .long("strip-path") + .env("CASR_STRIP_PATH") + .action(ArgAction::Set) + .value_name("PREFIX") + .help("Path prefix to strip from stacktrace and crash line"), + ) .arg( Arg::new("ARGS") .action(ArgAction::Set) @@ -286,5 +294,9 @@ fn main() -> Result<()> { } } + if let Some(path) = matches.get_one::("strip-path") { + util::strip_paths(&mut report, &stacktrace, path); + } + util::output_report(&report, &matches, &argv) } diff --git a/casr/src/util.rs b/casr/src/util.rs index 4ef59909..53cd8276 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -4,11 +4,12 @@ extern crate libcasr; use libcasr::cluster::{Cluster, ReportInfo}; use libcasr::report::CrashReport; use libcasr::stacktrace::{ - STACK_FRAME_FILEPATH_IGNORE_REGEXES, STACK_FRAME_FUNCTION_IGNORE_REGEXES, + Stacktrace, STACK_FRAME_FILEPATH_IGNORE_REGEXES, STACK_FRAME_FUNCTION_IGNORE_REGEXES, }; use anyhow::{bail, Context, Result}; use clap::ArgMatches; +use gdb_command::stacktrace::StacktraceExt; use is_executable::IsExecutable; use log::{info, warn}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; @@ -558,3 +559,32 @@ pub fn save_reports(reports: &Vec, dir: &str) -> Result<()> { } Ok(()) } + +/// Strip paths for stacktrace and crash line in CrashReport +/// +/// # Arguments +/// +/// * `report` - CASR crash report struct +/// +/// * 'stacktrace' - Stacktrace struct +/// +/// * `prefix` - path prefix +pub fn strip_paths(report: &mut CrashReport, stacktrace: &Stacktrace, prefix: &str) { + let mut stripped_stacktrace = stacktrace.clone(); + stripped_stacktrace.strip_prefix(prefix); + for (idx, (entry, stripped)) in stacktrace + .iter() + .zip(stripped_stacktrace.iter()) + .enumerate() + { + if !stripped.debug.file.is_empty() { + report.stacktrace[idx] = + report.stacktrace[idx].replace(&entry.debug.file, &stripped.debug.file); + } + } + if !report.crashline.is_empty() { + if let Ok(stripped) = Path::new(&report.crashline).strip_prefix(prefix) { + report.crashline = stripped.display().to_string(); + } + } +} diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index 6e0a9885..02ddde68 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -2852,6 +2852,7 @@ fn test_casr_san() { let output = Command::new(*EXE_CASR_SAN.read().unwrap()) .args(["--stdout", "--", &paths[1]]) + .env("CASR_STRIP_PATH", env::current_dir().unwrap()) .output() .expect("failed to start casr-san"); @@ -2884,7 +2885,7 @@ fn test_casr_san() { report["CrashLine"] .as_str() .unwrap() - .contains("test_asan_df.cpp:8:5") + .eq("tests/casr_tests/test_asan_df.cpp:8:5") // We build a test on ubuntu18 and run it on ubuntu20. // Debug information is broken. || report["CrashLine"] diff --git a/docs/usage.md b/docs/usage.md index be5058ae..67ad68fb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -28,16 +28,18 @@ Create CASR reports (.casrep) from gdb execution [ARGS]... Add "-- ./binary " to run executable Options: - -o, --output Path to save report. Path can be a directory, then report name - is generated - --stdout Print CASR report to stdout - --stdin Stdin file for program - -t, --timeout Timeout (in seconds) for target execution, 0 value means that - timeout is disabled [default: 0] - --ignore File with regular expressions for functions and file paths that - should be ignored - -h, --help Print help - -V, --version Print version + -o, --output Path to save report. Path can be a directory, then report + name is generated + --stdout Print CASR report to stdout + --stdin Stdin file for program + -t, --timeout Timeout (in seconds) for target execution, 0 value means that + timeout is disabled [default: 0] + --ignore File with regular expressions for functions and file paths + that should be ignored + --strip-path Path prefix to strip from stacktrace and crash line [env: + CASR_STRIP_PATH=] + -h, --help Print help + -V, --version Print version Example: @@ -53,16 +55,18 @@ Create CASR reports (.casrep) from AddressSanitizer reports [ARGS]... Add "-- ./binary " to run executable Options: - -o, --output Path to save report. Path can be a directory, then report name - is generated - --stdout Print CASR report to stdout - --stdin Stdin file for program - -t, --timeout Timeout (in seconds) for target execution, 0 value means that - timeout is disabled [default: 0] - --ignore File with regular expressions for functions and file paths that - should be ignored - -h, --help Print help - -V, --version Print version + -o, --output Path to save report. Path can be a directory, then report + name is generated + --stdout Print CASR report to stdout + --stdin Stdin file for program + -t, --timeout Timeout (in seconds) for target execution, 0 value means that + timeout is disabled [default: 0] + --ignore File with regular expressions for functions and file paths + that should be ignored + --strip-path Path prefix to strip from stacktrace and crash line [env: + CASR_STRIP_PATH=] + -h, --help Print help + -V, --version Print version Compile binary with ASAN: @@ -126,16 +130,17 @@ Create CASR reports (.casrep) from python reports [ARGS]... Add "-- " to run Options: - -o, --output Path to save report. Path can be a directory, then report name - is generated - --stdout Print CASR report to stdout - --stdin Stdin file for program - -t, --timeout Timeout (in seconds) for target execution, 0 value means that - timeout is disabled [default: 0] - --ignore File with regular expressions for functions and file paths that - should be ignored - -h, --help Print help - -V, --version Print version + -o, --output Path to save report. Path can be a directory, then report + name is generated + --stdout Print CASR report to stdout + --stdin Stdin file for program + -t, --timeout Timeout (in seconds) for target execution, 0 value means that + timeout is disabled [default: 0] + --ignore File with regular expressions for functions and file paths + that should be ignored + --strip-path Path prefix to strip from stacktrace [env: CASR_STRIP_PATH=] + -h, --help Print help + -V, --version Print version Example: @@ -161,6 +166,8 @@ Create CASR reports (.casrep) from java reports that timeout is disabled [default: 0] --ignore File with regular expressions for functions and file paths that should be ignored + --strip-path Path prefix to strip from stacktrace and crash line [env: + CASR_STRIP_PATH=] -h, --help Print help -V, --version Print version @@ -178,16 +185,18 @@ Create CASR reports (.casrep) from JavaScript crash reports [ARGS]... Add "-- " to run Options: - -o, --output Path to save report. Path can be a directory, then report name - is generated - --stdout Print CASR report to stdout - --stdin Stdin file for program - -t, --timeout Timeout (in seconds) for target execution, 0 value means that - timeout is disabled [default: 0] - --ignore File with regular expressions for functions and file paths that - should be ignored - -h, --help Print help - -V, --version Print version + -o, --output Path to save report. Path can be a directory, then report + name is generated + --stdout Print CASR report to stdout + --stdin Stdin file for program + -t, --timeout Timeout (in seconds) for target execution, 0 value means that + timeout is disabled [default: 0] + --ignore File with regular expressions for functions and file paths + that should be ignored + --strip-path Path prefix to strip from stacktrace and crash line [env: + CASR_STRIP_PATH=] + -h, --help Print help + -V, --version Print version Run casr-js: