1use {
2 crate::{
3 debugger::Debugger,
4 error::DebuggerResult,
5 input::ParsedInput,
6 parser::{LineMap, rodata_from_section},
7 },
8 sbpf_assembler::{Assembler, AssemblerOption, DebugMode, SbpfArch},
9 sbpf_disassembler::program::Program,
10 sbpf_runtime::{Runtime, config::RuntimeConfig},
11 sbpf_vm::memory::Memory,
12 std::path::{Path, PathBuf},
13};
14
15pub struct DebuggerSession {
16 pub debugger: Debugger,
17 pub line_map: Option<LineMap>,
18 pub elf_bytes: Vec<u8>,
19 pub elf_path: PathBuf,
20}
21
22pub fn load_session_from_asm(
23 asm_path: &str,
24 parsed: ParsedInput,
25 config: RuntimeConfig,
26) -> DebuggerResult<DebuggerSession> {
27 let asm_path = Path::new(asm_path);
28 if !asm_path.exists() {
29 return Err(crate::error::DebuggerError::InvalidInput(format!(
30 "Assembly file not found: {}",
31 asm_path.display()
32 )));
33 }
34
35 let source_code = std::fs::read_to_string(asm_path)?;
36 let filename = asm_path
37 .file_name()
38 .and_then(|n| n.to_str())
39 .unwrap_or("unknown.s")
40 .to_string();
41 let directory = asm_path
42 .parent()
43 .and_then(|p| p.canonicalize().ok())
44 .map(|p| p.to_string_lossy().to_string())
45 .unwrap_or_else(|| ".".to_string());
46
47 let options = AssemblerOption {
48 arch: SbpfArch::V0,
49 debug_mode: Some(DebugMode {
50 filename,
51 directory,
52 }),
53 };
54 let assembler = Assembler::new(options);
55 let bytecode = assembler
56 .assemble(&source_code)
57 .map_err(|errors| crate::error::DebuggerError::Assembler(format!("{:?}", errors)))?;
58
59 load_session_from_bytes(bytecode, parsed, config, None)
60}
61
62pub fn load_session_from_elf(
63 elf_path: &str,
64 parsed: ParsedInput,
65 config: RuntimeConfig,
66) -> DebuggerResult<DebuggerSession> {
67 let elf_bytes = std::fs::read(elf_path)?;
68 load_session_from_bytes(elf_bytes, parsed, config, Some(elf_path.into()))
69}
70
71fn load_session_from_bytes(
72 elf_bytes: Vec<u8>,
73 parsed: ParsedInput,
74 config: RuntimeConfig,
75 elf_path: Option<PathBuf>,
76) -> DebuggerResult<DebuggerSession> {
77 let mut runtime = Runtime::new(parsed.instruction.program_id, elf_bytes.clone(), config)?;
78 for (program_id, elf) in &parsed.programs {
79 runtime.add_program(program_id, elf.clone());
80 }
81 runtime.prepare(&parsed.instruction, &parsed.accounts)?;
82
83 let mut debugger = Debugger::new(runtime);
84 if let Ok(line_map) = LineMap::from_elf_data(&elf_bytes) {
85 debugger.set_dwarf_line_map(line_map);
86 }
87
88 if let Ok(program) = Program::from_bytes(&elf_bytes)
89 && let Ok((_, Some(ref section), _)) = program.to_ixs()
90 {
91 let mut rodata_symbols = rodata_from_section(section);
92 if let Some(ref line_map) = debugger.dwarf_line_map {
94 let text_offset = line_map.get_text_offset();
95 for sym in &mut rodata_symbols {
96 let rodata_offset = sym.address - Memory::RODATA_START;
97 let addr = rodata_offset + text_offset;
98 if let Some(name) = line_map.get_label_for_address(addr) {
99 sym.name = name.to_string();
100 }
101 }
102 }
103 if !rodata_symbols.is_empty() {
104 debugger.set_rodata(rodata_symbols);
105 }
106 }
107
108 Ok(DebuggerSession {
109 line_map: debugger.dwarf_line_map.clone(),
110 debugger,
111 elf_bytes,
112 elf_path: elf_path.unwrap_or_else(|| PathBuf::from("<memory>")),
113 })
114}