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},
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::default().with_debug_mode(DebugMode {
48 filename,
49 directory,
50 });
51 let assembler = Assembler::new(options);
52 let bytecode = assembler
53 .assemble(&source_code)
54 .map_err(|errors| crate::error::DebuggerError::Assembler(format!("{:?}", errors)))?;
55
56 load_session_from_bytes(bytecode, parsed, config, None)
57}
58
59pub fn load_session_from_elf(
60 elf_path: &str,
61 parsed: ParsedInput,
62 config: RuntimeConfig,
63) -> DebuggerResult<DebuggerSession> {
64 let elf_bytes = std::fs::read(elf_path)?;
65 load_session_from_bytes(elf_bytes, parsed, config, Some(elf_path.into()))
66}
67
68fn load_session_from_bytes(
69 elf_bytes: Vec<u8>,
70 parsed: ParsedInput,
71 config: RuntimeConfig,
72 elf_path: Option<PathBuf>,
73) -> DebuggerResult<DebuggerSession> {
74 let mut runtime = Runtime::new(parsed.instruction.program_id, elf_bytes.clone(), config)?;
75 for (program_id, elf) in &parsed.programs {
76 runtime.add_program(program_id, elf.clone());
77 }
78 runtime.prepare(&parsed.instruction, &parsed.accounts)?;
79
80 let mut debugger = Debugger::new(runtime);
81 if let Ok(line_map) = LineMap::from_elf_data(&elf_bytes) {
82 debugger.set_dwarf_line_map(line_map);
83 }
84
85 if let Ok(program) = Program::from_bytes(&elf_bytes)
88 && let Ok(disassembled) = program.to_ixs()
89 && let Some(ref section) = disassembled.value.rodata
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}