Let OSDK print source lines of the panic stack trace

This commit is contained in:
Zhang Junyang
2024-05-17 15:28:29 +00:00
committed by Tate, Hongliang Tian
parent f420286920
commit 8e874e6a88
4 changed files with 69 additions and 3 deletions

15
osdk/Cargo.lock generated
View File

@ -132,6 +132,8 @@ dependencies = [
"linux-bzimage-builder", "linux-bzimage-builder",
"log", "log",
"quote", "quote",
"regex",
"rev_buf_reader",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
@ -388,9 +390,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.3" version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -415,6 +417,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 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]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.17" version = "1.0.17"

View File

@ -29,6 +29,8 @@ indexmap = "2.2.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.20" log = "0.4.20"
quote = "1.0.35" quote = "1.0.35"
regex = "1.10.4"
rev_buf_reader = "0.3.0"
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111" serde_json = "1.0.111"
sha2 = "0.10.8" sha2 = "0.10.8"

View File

@ -247,6 +247,18 @@ impl Bundle {
info!("Running QEMU: {:#?}", qemu_cmd); info!("Running QEMU: {:#?}", qemu_cmd);
let exit_status = qemu_cmd.status().unwrap(); 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() { if !exit_status.success() {
// FIXME: Exit code manipulation is not needed when using non-x86 QEMU // FIXME: Exit code manipulation is not needed when using non-x86 QEMU
let qemu_exit_code = exit_status.code().unwrap(); let qemu_exit_code = exit_status.code().unwrap();

View File

@ -2,7 +2,8 @@
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fs, fs::{self, File},
io::{BufRead, BufReader, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, 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<String> = 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());
}
}
}
}