1 use crate::emu::Emu; 2 use gdbstub::target; 3 use gdbstub::target::ext::tracepoints::ExperimentExplanation; 4 use gdbstub::target::ext::tracepoints::ExperimentStatus; 5 use gdbstub::target::ext::tracepoints::FrameDescription; 6 use gdbstub::target::ext::tracepoints::FrameRequest; 7 use gdbstub::target::ext::tracepoints::NewTracepoint; 8 use gdbstub::target::ext::tracepoints::SourceTracepoint; 9 use gdbstub::target::ext::tracepoints::TraceBufferConfig; 10 use gdbstub::target::ext::tracepoints::Tracepoint; 11 use gdbstub::target::ext::tracepoints::TracepointAction; 12 use gdbstub::target::ext::tracepoints::TracepointEnumerateState; 13 use gdbstub::target::ext::tracepoints::TracepointEnumerateStep; 14 use gdbstub::target::ext::tracepoints::TracepointStatus; 15 use gdbstub::target::TargetError; 16 use gdbstub::target::TargetResult; 17 18 impl Emu { step_to_next_tracepoint(&self, tp: Tracepoint) -> TracepointEnumerateStep<u32>19 fn step_to_next_tracepoint(&self, tp: Tracepoint) -> TracepointEnumerateStep<u32> { 20 let next_tp = self.tracepoints.range(tp..).nth(1); 21 if let Some((tp, (new_tp, _, _))) = next_tp { 22 TracepointEnumerateStep::Next { 23 tp: *tp, 24 addr: new_tp.addr, 25 } 26 } else { 27 // No more tracepoints 28 TracepointEnumerateStep::Done 29 } 30 } 31 } 32 33 impl target::ext::tracepoints::Tracepoints for Emu { tracepoints_init(&mut self) -> TargetResult<(), Self>34 fn tracepoints_init(&mut self) -> TargetResult<(), Self> { 35 self.tracepoints.clear(); 36 self.traceframes.clear(); 37 Ok(()) 38 } 39 tracepoint_create_begin(&mut self, tp: NewTracepoint<u32>) -> TargetResult<(), Self>40 fn tracepoint_create_begin(&mut self, tp: NewTracepoint<u32>) -> TargetResult<(), Self> { 41 self.tracepoints.insert(tp.number, (tp, vec![], vec![])); 42 Ok(()) 43 } 44 tracepoint_create_continue( &mut self, tp: Tracepoint, action: &TracepointAction<'_, u32>, ) -> TargetResult<(), Self>45 fn tracepoint_create_continue( 46 &mut self, 47 tp: Tracepoint, 48 action: &TracepointAction<'_, u32>, 49 ) -> TargetResult<(), Self> { 50 if let &TracepointAction::Registers { mask: _ } = &action { 51 // we only handle register collection actions for the simple 52 // case 53 } else { 54 return Err(TargetError::NonFatal); 55 } 56 self.tracepoints 57 .get_mut(&tp) 58 .map(move |(_ctp, _source, actions)| actions.push(action.get_owned())) 59 .ok_or(TargetError::Fatal("extend on non-existing tracepoint")) 60 } 61 tracepoint_create_complete(&mut self, _tp: Tracepoint) -> TargetResult<(), Self>62 fn tracepoint_create_complete(&mut self, _tp: Tracepoint) -> TargetResult<(), Self> { 63 /* nothing to do */ 64 Ok(()) 65 } 66 tracepoint_status( &self, tp: Tracepoint, _addr: u32, ) -> TargetResult<TracepointStatus, Self>67 fn tracepoint_status( 68 &self, 69 tp: Tracepoint, 70 _addr: u32, 71 ) -> TargetResult<TracepointStatus, Self> { 72 // We don't collect "real" trace buffer frames, so just report hit count 73 // and say the number of bytes is always 0. 74 // Because we don't implement "while-stepping" actions, we don't need to 75 // also check that `addr` matches. 76 Ok(TracepointStatus { 77 hit_count: self 78 .traceframes 79 .iter() 80 .filter(|frame| frame.number.0 == tp.0) 81 .count() as u64, 82 bytes_used: 0, 83 }) 84 } 85 tracepoint_enumerate_state(&mut self) -> &mut TracepointEnumerateState<u32>86 fn tracepoint_enumerate_state(&mut self) -> &mut TracepointEnumerateState<u32> { 87 &mut self.tracepoint_enumerate_state 88 } 89 tracepoint_enumerate_start( &mut self, tp: Option<Tracepoint>, f: &mut dyn FnMut(&NewTracepoint<u32>), ) -> TargetResult<TracepointEnumerateStep<u32>, Self>90 fn tracepoint_enumerate_start( 91 &mut self, 92 tp: Option<Tracepoint>, 93 f: &mut dyn FnMut(&NewTracepoint<u32>), 94 ) -> TargetResult<TracepointEnumerateStep<u32>, Self> { 95 let tp = match tp { 96 Some(tp) => tp, 97 None => { 98 // We have no tracepoints to report 99 if self.tracepoints.is_empty() { 100 return Ok(TracepointEnumerateStep::Done); 101 } else { 102 // Start enumerating at the first one 103 *self.tracepoints.keys().next().unwrap() 104 } 105 } 106 }; 107 108 // Report our tracepoint 109 (f)(&self.tracepoints[&tp].0); 110 111 let ret = if !self.tracepoints[&tp].1.is_empty() { 112 TracepointEnumerateStep::Source 113 } else if !self.tracepoints[&tp].2.is_empty() { 114 TracepointEnumerateStep::Action 115 } else { 116 TracepointEnumerateStep::Done 117 }; 118 119 Ok(ret) 120 } 121 tracepoint_enumerate_action( &mut self, tp: Tracepoint, step: u64, f: &mut dyn FnMut(&TracepointAction<'_, u32>), ) -> TargetResult<TracepointEnumerateStep<u32>, Self>122 fn tracepoint_enumerate_action( 123 &mut self, 124 tp: Tracepoint, 125 step: u64, 126 f: &mut dyn FnMut(&TracepointAction<'_, u32>), 127 ) -> TargetResult<TracepointEnumerateStep<u32>, Self> { 128 // Report our next action 129 (f)(&self.tracepoints[&tp].2[step as usize]); 130 131 let ret = if self.tracepoints[&tp].2.get((step as usize) + 1).is_some() { 132 // Continue stepping 133 TracepointEnumerateStep::Action 134 } else if !self.tracepoints[&tp].1.is_empty() { 135 // We're done with this tracepoint, report source 136 TracepointEnumerateStep::Source 137 } else { 138 // No sources, move to the next tracepoint 139 self.step_to_next_tracepoint(tp) 140 }; 141 142 Ok(ret) 143 } 144 145 #[inline(always)] support_tracepoint_source( &mut self, ) -> Option<target::ext::tracepoints::TracepointSourceOps<'_, Self>>146 fn support_tracepoint_source( 147 &mut self, 148 ) -> Option<target::ext::tracepoints::TracepointSourceOps<'_, Self>> { 149 Some(self) 150 } 151 trace_buffer_configure(&mut self, _config: TraceBufferConfig) -> TargetResult<(), Self>152 fn trace_buffer_configure(&mut self, _config: TraceBufferConfig) -> TargetResult<(), Self> { 153 // we don't collect a "real" trace buffer, so just ignore configuration 154 // attempts. 155 Ok(()) 156 } 157 trace_buffer_request( &mut self, _offset: u64, _len: usize, _f: &mut dyn FnMut(&mut [u8]), ) -> TargetResult<(), Self>158 fn trace_buffer_request( 159 &mut self, 160 _offset: u64, 161 _len: usize, 162 _f: &mut dyn FnMut(&mut [u8]), 163 ) -> TargetResult<(), Self> { 164 // We don't have a "real" trace buffer, so just don't report any data 165 Ok(()) 166 } 167 trace_experiment_status( &self, report: &mut dyn FnMut(ExperimentStatus<'_>), ) -> TargetResult<(), Self>168 fn trace_experiment_status( 169 &self, 170 report: &mut dyn FnMut(ExperimentStatus<'_>), 171 ) -> TargetResult<(), Self> { 172 // For a bare-bones example, we don't provide in-depth status explanations. 173 (report)(if self.tracing { 174 ExperimentStatus::Running 175 } else { 176 ExperimentStatus::NotRunning 177 }); 178 Ok(()) 179 } 180 trace_experiment_info( &self, report: &mut dyn FnMut(ExperimentExplanation<'_>), ) -> TargetResult<(), Self>181 fn trace_experiment_info( 182 &self, 183 report: &mut dyn FnMut(ExperimentExplanation<'_>), 184 ) -> TargetResult<(), Self> { 185 (report)(ExperimentExplanation::Frames(self.traceframes.len())); 186 187 Ok(()) 188 } 189 select_frame( &mut self, frame: FrameRequest<u32>, report: &mut dyn FnMut(FrameDescription), ) -> TargetResult<(), Self>190 fn select_frame( 191 &mut self, 192 frame: FrameRequest<u32>, 193 report: &mut dyn FnMut(FrameDescription), 194 ) -> TargetResult<(), Self> { 195 // For a bare-bones example, we only support `tfind <number>` and `tfind 196 // tracepoint <tpnum>` style frame selection and not the more 197 // complicated ones. 198 let found = match frame { 199 FrameRequest::Select(n) => self.traceframes.get(n as usize).map(|frame| (n, frame)), 200 FrameRequest::Hit(tp) => { 201 let start = self 202 .selected_frame 203 .map(|selected| selected + 1) 204 .unwrap_or(0); 205 self.traceframes.get(start..).and_then(|frames| { 206 frames 207 .iter() 208 .enumerate() 209 .filter(|(_n, frame)| frame.number == tp) 210 .map(|(n, frame)| ((start + n) as u64, frame)) 211 .next() 212 }) 213 } 214 _ => return Err(TargetError::NonFatal), 215 }; 216 if let Some((n, frame)) = found { 217 (report)(FrameDescription::FrameNumber(n)); 218 (report)(FrameDescription::Hit(frame.number)); 219 self.selected_frame = Some(n as usize); 220 } else { 221 self.selected_frame = None; 222 } 223 Ok(()) 224 } 225 trace_experiment_start(&mut self) -> TargetResult<(), Self>226 fn trace_experiment_start(&mut self) -> TargetResult<(), Self> { 227 self.tracing = true; 228 Ok(()) 229 } 230 trace_experiment_stop(&mut self) -> TargetResult<(), Self>231 fn trace_experiment_stop(&mut self) -> TargetResult<(), Self> { 232 self.tracing = false; 233 Ok(()) 234 } 235 } 236 237 impl target::ext::tracepoints::TracepointSource for Emu { tracepoint_enumerate_source( &mut self, tp: Tracepoint, step: u64, f: &mut dyn FnMut(&SourceTracepoint<'_, u32>), ) -> TargetResult<TracepointEnumerateStep<u32>, Self>238 fn tracepoint_enumerate_source( 239 &mut self, 240 tp: Tracepoint, 241 step: u64, 242 f: &mut dyn FnMut(&SourceTracepoint<'_, u32>), 243 ) -> TargetResult<TracepointEnumerateStep<u32>, Self> { 244 // Report our next source item 245 (f)(&self.tracepoints[&tp].1[step as usize]); 246 247 let ret = if self.tracepoints[&tp].1.get((step as usize) + 1).is_some() { 248 // Continue stepping 249 TracepointEnumerateStep::Source 250 } else { 251 // Move to next tracepoint 252 self.step_to_next_tracepoint(tp) 253 }; 254 255 Ok(ret) 256 } 257 tracepoint_attach_source( &mut self, src: SourceTracepoint<'_, u32>, ) -> TargetResult<(), Self>258 fn tracepoint_attach_source( 259 &mut self, 260 src: SourceTracepoint<'_, u32>, 261 ) -> TargetResult<(), Self> { 262 self.tracepoints 263 .get_mut(&src.number) 264 .unwrap() 265 .1 266 .push(src.get_owned()); 267 Ok(()) 268 } 269 } 270