use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use crate::toolchain::{cargo_home, get_toolchain_sysroot, map_dwarf_path};
use crate::util::read_nth_line;
use crate::{Dwarf, Outcome};
use anyhow::Result;
pub fn trace_disassemble(
src_paths: &HashSet<PathBuf>,
regs_path: &Path,
vaddrs: &[u64],
dwarf: &Dwarf,
colorize: bool,
) -> Result<Outcome> {
let mut file_cache = HashMap::new();
let toolchain_path = get_toolchain_sysroot(&dwarf.debug_path);
let disassemble_content =
std::fs::read_to_string(regs_path.with_extension("trace").display().to_string())
.unwrap_or("".into());
for (idx, pc) in vaddrs.iter().enumerate() {
let disassemble = read_nth_line(&disassemble_content, idx);
let pc_in_disassemble = pc_in_disassemble(*pc, dwarf)?;
match dwarf.vaddr_entry_map.iter().find(|(vaddr, _)| *vaddr == pc) {
None => {
eprintln!("[{pc_in_disassemble}] (0x{pc:x}) {disassemble}");
}
Some((_, entry)) => {
let (content, file_path, mapped_file_path) =
file_cache.entry(entry.file).or_insert_with(|| {
if let Ok(content) = std::fs::read_to_string(entry.file) {
(content, entry.file.to_string(), "".into())
} else {
let mapped_file_path = map_dwarf_path(
entry.file,
toolchain_path.as_deref(),
&cargo_home(),
);
if mapped_file_path != entry.file
&& let Ok(content) = std::fs::read_to_string(&mapped_file_path)
{
return (content, entry.file.to_string(), mapped_file_path);
}
("".into(), entry.file.to_string(), "".into())
}
});
let code = read_nth_line(content, entry.line.saturating_sub(1) as usize);
let src_location = if !mapped_file_path.is_empty() {
format!(
"{}:{} -> {}:{}",
file_path, entry.line, mapped_file_path, entry.line
)
} else {
format!("{}:{}", file_path, entry.line)
};
let is_user_src = src_paths
.iter()
.any(|path| file_path.contains(&path.to_string_lossy().to_string()));
let marker = if is_user_src { ">>> " } else { " " };
if colorize {
let file_color = if is_user_src { "\x1b[35m" } else { "\x1b[34m" };
eprintln!(
"[{pc_in_disassemble}] (0x{pc:x}) {disassemble}\n{marker}\x1b[33msrc:\x1b[0m {file_color}{src_location}\x1b[0m\n{marker}\x1b[36mcode:\x1b[0m \x1b[32m{}\x1b[0m",
code.trim(),
);
} else {
eprintln!(
"[{pc_in_disassemble}] (0x{pc:x}) {disassemble}\n{marker}src: {src_location}\n{marker}code: {}",
code.trim(),
);
}
}
};
}
Ok(Outcome::TraceDisassemble)
}
pub fn pc_in_disassemble(pc_in_trace: u64, dwarf: &Dwarf) -> Result<u64> {
let pc_in_disassembly = (pc_in_trace - dwarf.text_section_offset) / 8;
Ok(pc_in_disassembly)
}