embedded_debugger_mcp/rtt/
manager.rs1use crate::error::{DebugError, Result};
4use std::collections::HashMap;
5use std::sync::Arc;
6use std::path::Path;
7use tokio::sync::Mutex;
8use tracing::{debug, info, error, warn};
9use probe_rs::{Session, rtt::{Rtt, ScanRegion}, MemoryInterface};
10
11#[derive(Debug)]
13pub struct RttManager {
14 attached: bool,
16 rtt: Option<Rtt>,
18 session: Option<Arc<Mutex<Session>>>,
20 channels: HashMap<u32, ChannelInfo>,
22 up_channel_count: usize,
24 down_channel_count: usize,
26}
27
28#[derive(Debug, Clone)]
29pub struct ChannelInfo {
30 pub id: u32,
31 pub name: String,
32 pub direction: ChannelDirection,
33 pub mode: String,
34 pub buffer_size: usize,
35}
36
37#[derive(Debug, Clone)]
38pub enum ChannelDirection {
39 Up, Down, }
42
43impl Default for RttManager {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl RttManager {
50 pub fn new() -> Self {
52 Self {
53 attached: false,
54 rtt: None,
55 session: None,
56 channels: HashMap::new(),
57 up_channel_count: 0,
58 down_channel_count: 0,
59 }
60 }
61
62 pub async fn attach_with_elf(
65 &mut self,
66 session: Arc<Mutex<Session>>,
67 firmware_path: &Path,
68 ) -> Result<()> {
69 info!("Starting enhanced RTT attachment with ELF symbol detection first");
70 debug!("Firmware path: {}", firmware_path.display());
71
72 match crate::rtt::elf_parser::get_rtt_symbol_from_elf(firmware_path) {
74 Ok(symbol_addr) => {
75 info!("✅ Found _SEGGER_RTT symbol at 0x{:08X}, attempting direct connection", symbol_addr);
76
77 match self.try_rtt_at_address(session.clone(), symbol_addr).await {
79 Ok(_) => {
80 info!("🎯 RTT connected successfully using ELF symbol address!");
81 return Ok(());
82 }
83 Err(e) => {
84 warn!("RTT connection failed at symbol address 0x{:08X}: {}", symbol_addr, e);
85 info!("Falling back to memory scanning...");
86 }
87 }
88 }
89 Err(e) => {
90 info!("ELF symbol detection failed: {}", e);
91 info!("Proceeding with memory scanning fallback...");
92 }
93 }
94
95 info!("Using memory scanning fallback approach");
97 self.attach(session, None, None).await
98 }
99
100 async fn try_rtt_at_address(
102 &mut self,
103 session: Arc<Mutex<Session>>,
104 address: u64,
105 ) -> Result<()> {
106 debug!("Attempting RTT connection at specific address: 0x{:08X}", address);
107
108 self.session = Some(session.clone());
110
111 let mut session_guard = session.lock().await;
112 let mut core = session_guard.core(0).map_err(|e| {
113 error!("Failed to get core for RTT attachment: {}", e);
114 DebugError::RttError(format!("Failed to get core: {}", e))
115 })?;
116
117 let is_valid = self.validate_rtt_control_block_sync(&mut core, address)?;
119 if !is_valid {
120 return Err(DebugError::RttError(format!(
121 "Invalid RTT control block at address 0x{:08X} (magic identifier not found)",
122 address
123 )));
124 }
125 debug!("✅ RTT control block validated at 0x{:08X}", address);
126
127 debug!("Using ScanRegion::Exact for direct address connection...");
129
130 let scan_region = ScanRegion::Exact(address);
131 let rtt_result = Rtt::attach_region(&mut core, &scan_region);
132
133 match rtt_result {
134 Ok(rtt) => {
135 info!("Successfully attached RTT at ELF symbol address 0x{:08X}!", address);
136 self.complete_attachment_sync(rtt)
137 }
138 Err(e) => {
139 error!("RTT attachment failed at address 0x{:08X}: {}", address, e);
140 Err(DebugError::RttError(format!(
141 "RTT attachment failed at symbol address 0x{:08X}: {}",
142 address, e
143 )))
144 }
145 }
146 }
147
148 fn validate_rtt_control_block_sync(
150 &self,
151 core: &mut probe_rs::Core<'_>,
152 address: u64,
153 ) -> Result<bool> {
154 debug!("Validating RTT control block at address 0x{:08X}", address);
155
156 let mut id_buffer = [0u8; 16];
158 core.read(address, &mut id_buffer).map_err(|e| {
159 DebugError::RttError(format!("Failed to read RTT control block at 0x{:08X}: {}", address, e))
160 })?;
161
162 const RTT_ID: &[u8] = b"SEGGER RTT\0\0\0\0\0\0";
164 let is_valid = id_buffer == RTT_ID;
165
166 if is_valid {
167 debug!("✅ Valid RTT control block found at 0x{:08X}", address);
168 } else {
169 debug!("❌ Invalid RTT control block at 0x{:08X}, found: {:02X?}", address, &id_buffer[..10]);
170 }
171
172 Ok(is_valid)
173 }
174
175 pub async fn attach(
178 &mut self,
179 session: Arc<Mutex<Session>>,
180 control_block_address: Option<u64>,
181 memory_ranges: Option<Vec<(u64, u64)>>
182 ) -> Result<()> {
183 debug!("Attaching to RTT using probe-rs integration with enhanced detection");
184
185 self.session = Some(session.clone());
187
188 let mut session_guard = session.lock().await;
192 let mut core = session_guard.core(0).map_err(|e| {
193 error!("Failed to get core for RTT attachment: {}", e);
194 DebugError::RttError(format!("Failed to get core: {}", e))
195 })?;
196
197 let core_status = core.status().map_err(|e| {
199 error!("Failed to get core status: {}", e);
200 DebugError::RttError(format!("Failed to get core status: {}", e))
201 })?;
202 debug!("Core status before RTT attach: {:?}", core_status);
203
204 let scan_region = if let Some(cb_addr) = control_block_address {
206 info!("RTT scan: Using exact address: 0x{:08X}", cb_addr);
207 ScanRegion::Exact(cb_addr)
208 } else if let Some(ranges) = memory_ranges {
209 info!("RTT scan: Using custom memory ranges: {:?}", ranges);
210 let ranges = ranges.into_iter()
211 .map(|(start, end)| start..end)
212 .collect();
213 ScanRegion::Ranges(ranges)
214 } else {
215 info!("RTT scan: Using RAM scan (probe-rs default)");
216 ScanRegion::Ram
217 };
218
219 debug!("Attempting RTT attach with scan region: {:?}", scan_region);
221 let rtt_result = Rtt::attach_region(&mut core, &scan_region);
222
223 match rtt_result {
224 Ok(rtt) => {
225 info!("Successfully attached to RTT control block!");
226 self.complete_attachment_sync(rtt)
227 }
228 Err(e) => {
229 error!("RTT attachment failed: {}", e);
230
231 let detailed_error = format!(
233 "RTT attachment failed: {}\n\n\
234 Debug Information:\n\
235 - Core Status: {:?}\n\
236 - Scan Region: {:?}\n\
237 - Control Block Address: {:?}\n\n\
238 Common Solutions:\n\
239 - Make sure RTT is initialized on the target (defmt-rtt or rtt-target)\n\
240 - Ensure target is running (not halted) during RTT initialization\n\
241 - Check that firmware has sufficient time to initialize RTT\n\
242 - Verify memory regions contain RTT control block\n\
243 - For defmt: ensure defmt-rtt feature is enabled in firmware",
244 e,
245 core_status,
246 scan_region,
247 control_block_address
248 );
249
250 Err(DebugError::RttError(detailed_error))
251 }
252 }
253 }
254
255 fn complete_attachment_sync(&mut self, mut rtt: Rtt) -> Result<()> {
257 self.channels.clear();
259
260 let up_channels = rtt.up_channels();
262 self.up_channel_count = up_channels.len();
263 for i in 0..up_channels.len() {
264 if let Some(up_channel) = up_channels.get(i) {
265 let channel_info = ChannelInfo {
266 id: i as u32,
267 name: up_channel.name().unwrap_or(&format!("Up{}", i)).to_string(),
268 direction: ChannelDirection::Up,
269 mode: "RTT".to_string(), buffer_size: up_channel.buffer_size(),
271 };
272 self.channels.insert(i as u32, channel_info);
273 debug!("Discovered up channel {}: {} (size: {} bytes)",
274 i, up_channel.name().unwrap_or("unnamed"), up_channel.buffer_size());
275 }
276 }
277
278 let down_channels = rtt.down_channels();
280 self.down_channel_count = down_channels.len();
281 for i in 0..down_channels.len() {
282 if let Some(down_channel) = down_channels.get(i) {
283 let channel_info = ChannelInfo {
284 id: i as u32,
285 name: down_channel.name().unwrap_or(&format!("Down{}", i)).to_string(),
286 direction: ChannelDirection::Down,
287 mode: "RTT".to_string(), buffer_size: down_channel.buffer_size(),
289 };
290 self.channels.insert(1000 + i as u32, channel_info);
292 debug!("Discovered down channel {}: {} (size: {} bytes)",
293 i, down_channel.name().unwrap_or("unnamed"), down_channel.buffer_size());
294 }
295 }
296
297 self.rtt = Some(rtt);
299 self.attached = true;
300
301 info!("RTT attachment completed: {} up channels, {} down channels",
302 self.up_channel_count, self.down_channel_count);
303 Ok(())
304 }
305
306 pub async fn detach(&mut self) -> Result<()> {
308 debug!("Detaching from RTT");
309
310 self.attached = false;
311 self.rtt = None;
312 self.session = None;
313 self.channels.clear();
314 self.up_channel_count = 0;
315 self.down_channel_count = 0;
316
317 info!("RTT detached successfully");
318 Ok(())
319 }
320
321 pub async fn read_channel(&mut self, channel: u32) -> Result<Vec<u8>> {
323 if !self.attached {
324 return Err(DebugError::RttError("RTT not attached".to_string()));
325 }
326
327 let session = self.session.as_ref()
328 .ok_or_else(|| DebugError::RttError("No session available".to_string()))?;
329
330 let rtt = self.rtt.as_mut()
331 .ok_or_else(|| DebugError::RttError("No RTT instance available".to_string()))?;
332
333 let mut session_guard = session.lock().await;
335 let mut core = session_guard.core(0).map_err(|e| {
336 DebugError::RttError(format!("Failed to get core: {}", e))
337 })?;
338
339 let up_channels = rtt.up_channels();
341 let up_channel = up_channels.get_mut(channel as usize)
342 .ok_or_else(|| DebugError::RttError(format!("Up channel {} not found", channel)))?;
343
344 let mut buffer = vec![0u8; 1024]; match up_channel.read(&mut core, &mut buffer) {
347 Ok(bytes_read) => {
348 buffer.truncate(bytes_read);
349 if bytes_read > 0 {
350 debug!("Read {} bytes from RTT up channel {}", bytes_read, channel);
351 }
352 Ok(buffer)
353 }
354 Err(e) => {
355 error!("Failed to read from RTT up channel {}: {}", channel, e);
356 Err(DebugError::RttError(format!("RTT read failed: {}", e)))
357 }
358 }
359 }
360
361 pub async fn write_channel(&mut self, channel: u32, data: &[u8]) -> Result<usize> {
363 if !self.attached {
364 return Err(DebugError::RttError("RTT not attached".to_string()));
365 }
366
367 let session = self.session.as_ref()
368 .ok_or_else(|| DebugError::RttError("No session available".to_string()))?;
369
370 let rtt = self.rtt.as_mut()
371 .ok_or_else(|| DebugError::RttError("No RTT instance available".to_string()))?;
372
373 let mut session_guard = session.lock().await;
375 let mut core = session_guard.core(0).map_err(|e| {
376 DebugError::RttError(format!("Failed to get core: {}", e))
377 })?;
378
379 let down_channels = rtt.down_channels();
381 let down_channel = down_channels.get_mut(channel as usize)
382 .ok_or_else(|| DebugError::RttError(format!("Down channel {} not found", channel)))?;
383
384 match down_channel.write(&mut core, data) {
386 Ok(bytes_written) => {
387 debug!("Wrote {} bytes to RTT down channel {}", bytes_written, channel);
388 info!("RTT Write Channel {}: {:?}", channel, String::from_utf8_lossy(&data[..bytes_written]));
389 Ok(bytes_written)
390 }
391 Err(e) => {
392 error!("Failed to write to RTT down channel {}: {}", channel, e);
393 Err(DebugError::RttError(format!("RTT write failed: {}", e)))
394 }
395 }
396 }
397
398 pub fn get_channels(&self) -> Vec<&ChannelInfo> {
400 self.channels.values().collect()
401 }
402
403 pub fn is_attached(&self) -> bool {
405 self.attached
406 }
407
408 pub fn up_channel_count(&self) -> usize {
410 self.up_channel_count
411 }
412
413 pub fn down_channel_count(&self) -> usize {
415 self.down_channel_count
416 }
417}