• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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