From 8e874e6a8896d976dd5cd87079770df1b2011786 Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Fri, 17 May 2024 15:28:29 +0000 Subject: [PATCH] Let OSDK print source lines of the panic stack trace --- osdk/Cargo.lock | 15 +++++++++++++-- osdk/Cargo.toml | 2 ++ osdk/src/bundle/mod.rs | 12 ++++++++++++ osdk/src/util.rs | 43 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/osdk/Cargo.lock b/osdk/Cargo.lock index b362d3ea8..f9801004a 100644 --- a/osdk/Cargo.lock +++ b/osdk/Cargo.lock @@ -132,6 +132,8 @@ dependencies = [ "linux-bzimage-builder", "log", "quote", + "regex", + "rev_buf_reader", "serde", "serde_json", "sha2", @@ -388,9 +390,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -415,6 +417,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rev_buf_reader" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c0f2e47e00e29920959826e2e1784728a3780d1a784247be5257258cc75f910" +dependencies = [ + "memchr", +] + [[package]] name = "ryu" version = "1.0.17" diff --git a/osdk/Cargo.toml b/osdk/Cargo.toml index 5e8889b6d..9e6598bed 100644 --- a/osdk/Cargo.toml +++ b/osdk/Cargo.toml @@ -29,6 +29,8 @@ indexmap = "2.2.1" lazy_static = "1.4.0" log = "0.4.20" quote = "1.0.35" +regex = "1.10.4" +rev_buf_reader = "0.3.0" serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" sha2 = "0.10.8" diff --git a/osdk/src/bundle/mod.rs b/osdk/src/bundle/mod.rs index 2513aa8a5..db8a89007 100644 --- a/osdk/src/bundle/mod.rs +++ b/osdk/src/bundle/mod.rs @@ -247,6 +247,18 @@ impl Bundle { info!("Running QEMU: {:#?}", qemu_cmd); let exit_status = qemu_cmd.status().unwrap(); + + // Find the QEMU output in "qemu.log", read it and check if it failed with a panic. + // Setting a QEMU log is required for source line stack trace because piping the output + // is less desirable when running QEMU with serial redirected to standard I/O. + let qemu_log_path = config.work_dir.join("qemu.log"); + if let Ok(file) = std::fs::File::open(qemu_log_path) { + if let Some(aster_bin) = &self.manifest.aster_bin { + crate::util::trace_panic_from_log(file, self.path.join(aster_bin.path())); + } + } + + // FIXME: When panicking it sometimes returns success, why? if !exit_status.success() { // FIXME: Exit code manipulation is not needed when using non-x86 QEMU let qemu_exit_code = exit_status.code().unwrap(); diff --git a/osdk/src/util.rs b/osdk/src/util.rs index 9def7cb6b..a05aea9eb 100644 --- a/osdk/src/util.rs +++ b/osdk/src/util.rs @@ -2,7 +2,8 @@ use std::{ ffi::OsStr, - fs, + fs::{self, File}, + io::{BufRead, BufReader, Write}, path::{Path, PathBuf}, process::Command, }; @@ -212,3 +213,43 @@ pub fn parse_package_id_string(package_id: &str) -> CrateInfo { } } } + +/// Print source line stack trace if a panic is detected from QEMU log. +/// +/// The source line is produced with the `addr2line` command using the PC values in the panic +/// stack trace. +pub fn trace_panic_from_log(qemu_log: File, bin_path: PathBuf) { + // We read last 500 lines since more than 100 layers of stack trace is unlikely. + let reader = rev_buf_reader::RevBufReader::new(qemu_log); + let lines: Vec = reader.lines().take(500).map(|l| l.unwrap()).collect(); + let mut trace_exists = false; + let mut stack_num = 0; + let pc_matcher = regex::Regex::new(r" - pc (0x[0-9a-fA-F]+)").unwrap(); + let exe = bin_path.to_string_lossy(); + let mut addr2line = Command::new("addr2line"); + addr2line.args(["-e", &exe]); + let mut addr2line_proc = addr2line + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .unwrap(); + for line in lines.into_iter().rev() { + if line.contains("printing stack trace:") { + println!("[OSDK] The kernel seems panicked. Parsing stack trace for source lines:"); + trace_exists = true; + } + if trace_exists { + if let Some(cap) = pc_matcher.captures(&line) { + let pc = cap.get(1).unwrap().as_str(); + let mut stdin = addr2line_proc.stdin.as_ref().unwrap(); + stdin.write_all(pc.as_bytes()).unwrap(); + stdin.write_all(b"\n").unwrap(); + let mut line = String::new(); + let mut stdout = BufReader::new(addr2line_proc.stdout.as_mut().unwrap()); + stdout.read_line(&mut line).unwrap(); + stack_num += 1; + println!("({: >3}) {}", stack_num, line.trim()); + } + } + } +}