embedded_debugger_mcp/rtt/
elf_parser.rs1use crate::error::{DebugError, Result};
5use std::path::Path;
6use tracing::{debug, info, warn};
7
8const RTT_SYMBOL_NAME: &str = "_SEGGER_RTT";
10
11pub fn get_rtt_symbol_from_elf(elf_path: &Path) -> Result<u64> {
14 debug!("Parsing ELF file for RTT symbol: {}", elf_path.display());
15
16 let elf_data = std::fs::read(elf_path).map_err(|e| {
18 DebugError::RttError(format!("Failed to read ELF file {}: {}", elf_path.display(), e))
19 })?;
20
21 let elf = goblin::elf::Elf::parse(&elf_data).map_err(|e| {
23 DebugError::RttError(format!("Failed to parse ELF file {}: {}", elf_path.display(), e))
24 })?;
25
26 info!("ELF file parsed successfully, searching for {} symbol", RTT_SYMBOL_NAME);
27 debug!("ELF info - entry: 0x{:08X}, symbols: {}", elf.entry, elf.syms.len());
28
29 for sym in elf.syms.iter() {
31 if let Some(name) = elf.strtab.get_at(sym.st_name) {
32 debug!("Found symbol: {} at 0x{:08X}", name, sym.st_value);
33
34 if name == RTT_SYMBOL_NAME {
35 let rtt_address = sym.st_value;
36 info!("✅ Found {} symbol at address 0x{:08X}", RTT_SYMBOL_NAME, rtt_address);
37
38 if is_valid_rtt_address(rtt_address) {
40 return Ok(rtt_address);
41 } else {
42 warn!("RTT symbol address 0x{:08X} appears invalid (not in typical RAM range)", rtt_address);
43 return Err(DebugError::RttError(format!(
44 "RTT symbol found at invalid address 0x{:08X} (expected in RAM range 0x20000000-0x2FFFFFFF)",
45 rtt_address
46 )));
47 }
48 }
49 }
50 }
51
52 debug!("RTT symbol search completed, {} not found in {} symbols", RTT_SYMBOL_NAME, elf.syms.len());
54 Err(DebugError::RttError(format!(
55 "{} symbol not found in ELF file {}. Firmware may not have RTT enabled or symbols may be stripped.",
56 RTT_SYMBOL_NAME,
57 elf_path.display()
58 )))
59}
60
61fn is_valid_rtt_address(address: u64) -> bool {
64 const RAM_START: u64 = 0x20000000;
68 const RAM_END: u64 = 0x2FFFFFFF;
69
70 address >= RAM_START && address <= RAM_END
71}
72
73pub fn get_elf_debug_info(elf_path: &Path) -> Result<ElfDebugInfo> {
75 let elf_data = std::fs::read(elf_path).map_err(|e| {
76 DebugError::RttError(format!("Failed to read ELF file: {}", e))
77 })?;
78
79 let elf = goblin::elf::Elf::parse(&elf_data).map_err(|e| {
80 DebugError::RttError(format!("Failed to parse ELF file: {}", e))
81 })?;
82
83 let mut debug_symbols = Vec::new();
84 for sym in elf.syms.iter() {
85 if let Some(name) = elf.strtab.get_at(sym.st_name) {
86 if name.contains("RTT") || name.contains("rtt") {
87 debug_symbols.push(SymbolInfo {
88 name: name.to_string(),
89 address: sym.st_value,
90 size: sym.st_size,
91 });
92 }
93 }
94 }
95
96 Ok(ElfDebugInfo {
97 entry_point: elf.entry,
98 symbol_count: elf.syms.len(),
99 has_debug_info: !elf.section_headers.is_empty(),
100 rtt_related_symbols: debug_symbols,
101 })
102}
103
104#[derive(Debug)]
105pub struct ElfDebugInfo {
106 pub entry_point: u64,
107 pub symbol_count: usize,
108 pub has_debug_info: bool,
109 pub rtt_related_symbols: Vec<SymbolInfo>,
110}
111
112#[derive(Debug)]
113pub struct SymbolInfo {
114 pub name: String,
115 pub address: u64,
116 pub size: u64,
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_valid_rtt_address() {
125 assert!(is_valid_rtt_address(0x20000000)); assert!(is_valid_rtt_address(0x20008000)); assert!(is_valid_rtt_address(0x2000A000)); assert!(!is_valid_rtt_address(0x08000000)); assert!(!is_valid_rtt_address(0x00000000)); assert!(!is_valid_rtt_address(0x40000000)); }
135}