1 use crate::emu::Emu;
2 use crate::emu::ExecMode;
3 use armv4t_emu::reg;
4 use armv4t_emu::Memory;
5 use core::convert::TryInto;
6 use gdbstub::common::Signal;
7 use gdbstub::target;
8 use gdbstub::target::ext::base::singlethread::SingleThreadBase;
9 use gdbstub::target::ext::base::singlethread::SingleThreadResume;
10 use gdbstub::target::Target;
11 use gdbstub::target::TargetError;
12 use gdbstub::target::TargetResult;
13 use gdbstub_arch::arm::reg::id::ArmCoreRegId;
14
15 // Additional GDB extensions
16
17 mod auxv;
18 mod breakpoints;
19 mod catch_syscalls;
20 mod exec_file;
21 mod extended_mode;
22 mod host_io;
23 mod libraries;
24 mod lldb_register_info_override;
25 mod memory_map;
26 mod monitor_cmd;
27 mod section_offsets;
28 mod target_description_xml_override;
29 pub(crate) mod tracepoints;
30
31 /// Turn a `ArmCoreRegId` into an internal register number of `armv4t_emu`.
cpu_reg_id(id: ArmCoreRegId) -> Option<u8>32 fn cpu_reg_id(id: ArmCoreRegId) -> Option<u8> {
33 match id {
34 ArmCoreRegId::Gpr(i) => Some(i),
35 ArmCoreRegId::Sp => Some(reg::SP),
36 ArmCoreRegId::Lr => Some(reg::LR),
37 ArmCoreRegId::Pc => Some(reg::PC),
38 ArmCoreRegId::Cpsr => Some(reg::CPSR),
39 _ => None,
40 }
41 }
42
43 /// Copy all bytes of `data` to `buf`.
44 /// Return the size of data copied.
copy_to_buf(data: &[u8], buf: &mut [u8]) -> usize45 pub fn copy_to_buf(data: &[u8], buf: &mut [u8]) -> usize {
46 let len = buf.len().min(data.len());
47 buf[..len].copy_from_slice(&data[..len]);
48 len
49 }
50
51 /// Copy a range of `data` (start at `offset` with a size of `length`) to `buf`.
52 /// Return the size of data copied. Returns 0 if `offset >= buf.len()`.
53 ///
54 /// Mainly used by qXfer:_object_:read commands.
copy_range_to_buf(data: &[u8], offset: u64, length: usize, buf: &mut [u8]) -> usize55 pub fn copy_range_to_buf(data: &[u8], offset: u64, length: usize, buf: &mut [u8]) -> usize {
56 let offset = offset as usize;
57 if offset > data.len() {
58 return 0;
59 }
60
61 let start = offset;
62 let end = (offset + length).min(data.len());
63 copy_to_buf(&data[start..end], buf)
64 }
65
66 impl Target for Emu {
67 // As an example, I've defined a custom architecture based off
68 // `gdbstub_arch::arm::Armv4t`. The implementation is in the `custom_arch`
69 // module at the bottom of this file.
70 //
71 // unless you're working with a particularly funky architecture that uses custom
72 // registers, you should probably stick to using the simple `target.xml`
73 // implementations from the `gdbstub_arch` repo (i.e: `target.xml` files that
74 // only specify the <architecture> and <feature>s of the arch, instead of
75 // listing out all the registers out manually).
76 type Arch = custom_arch::Armv4tCustom;
77 type Error = &'static str;
78
79 // --------------- IMPORTANT NOTE ---------------
80 // Always remember to annotate IDET enable methods with `inline(always)`!
81 // Without this annotation, LLVM might fail to dead-code-eliminate nested IDET
82 // implementations, resulting in unnecessary binary bloat.
83
84 #[inline(always)]
base_ops(&mut self) -> target::ext::base::BaseOps<'_, Self::Arch, Self::Error>85 fn base_ops(&mut self) -> target::ext::base::BaseOps<'_, Self::Arch, Self::Error> {
86 target::ext::base::BaseOps::SingleThread(self)
87 }
88
89 #[inline(always)]
support_breakpoints( &mut self, ) -> Option<target::ext::breakpoints::BreakpointsOps<'_, Self>>90 fn support_breakpoints(
91 &mut self,
92 ) -> Option<target::ext::breakpoints::BreakpointsOps<'_, Self>> {
93 Some(self)
94 }
95
96 #[inline(always)]
support_extended_mode( &mut self, ) -> Option<target::ext::extended_mode::ExtendedModeOps<'_, Self>>97 fn support_extended_mode(
98 &mut self,
99 ) -> Option<target::ext::extended_mode::ExtendedModeOps<'_, Self>> {
100 Some(self)
101 }
102
103 #[inline(always)]
support_monitor_cmd(&mut self) -> Option<target::ext::monitor_cmd::MonitorCmdOps<'_, Self>>104 fn support_monitor_cmd(&mut self) -> Option<target::ext::monitor_cmd::MonitorCmdOps<'_, Self>> {
105 Some(self)
106 }
107
108 #[inline(always)]
support_section_offsets( &mut self, ) -> Option<target::ext::section_offsets::SectionOffsetsOps<'_, Self>>109 fn support_section_offsets(
110 &mut self,
111 ) -> Option<target::ext::section_offsets::SectionOffsetsOps<'_, Self>> {
112 Some(self)
113 }
114
115 #[inline(always)]
support_target_description_xml_override( &mut self, ) -> Option< target::ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<'_, Self>, >116 fn support_target_description_xml_override(
117 &mut self,
118 ) -> Option<
119 target::ext::target_description_xml_override::TargetDescriptionXmlOverrideOps<'_, Self>,
120 > {
121 Some(self)
122 }
123
124 #[inline(always)]
support_lldb_register_info_override( &mut self, ) -> Option<target::ext::lldb_register_info_override::LldbRegisterInfoOverrideOps<'_, Self>>125 fn support_lldb_register_info_override(
126 &mut self,
127 ) -> Option<target::ext::lldb_register_info_override::LldbRegisterInfoOverrideOps<'_, Self>>
128 {
129 Some(self)
130 }
131
132 #[inline(always)]
support_memory_map(&mut self) -> Option<target::ext::memory_map::MemoryMapOps<'_, Self>>133 fn support_memory_map(&mut self) -> Option<target::ext::memory_map::MemoryMapOps<'_, Self>> {
134 Some(self)
135 }
136
137 #[inline(always)]
support_catch_syscalls( &mut self, ) -> Option<target::ext::catch_syscalls::CatchSyscallsOps<'_, Self>>138 fn support_catch_syscalls(
139 &mut self,
140 ) -> Option<target::ext::catch_syscalls::CatchSyscallsOps<'_, Self>> {
141 Some(self)
142 }
143
144 #[inline(always)]
support_host_io(&mut self) -> Option<target::ext::host_io::HostIoOps<'_, Self>>145 fn support_host_io(&mut self) -> Option<target::ext::host_io::HostIoOps<'_, Self>> {
146 Some(self)
147 }
148
149 #[inline(always)]
support_exec_file(&mut self) -> Option<target::ext::exec_file::ExecFileOps<'_, Self>>150 fn support_exec_file(&mut self) -> Option<target::ext::exec_file::ExecFileOps<'_, Self>> {
151 Some(self)
152 }
153
154 #[inline(always)]
support_auxv(&mut self) -> Option<target::ext::auxv::AuxvOps<'_, Self>>155 fn support_auxv(&mut self) -> Option<target::ext::auxv::AuxvOps<'_, Self>> {
156 Some(self)
157 }
158
159 #[inline(always)]
support_libraries_svr4( &mut self, ) -> Option<target::ext::libraries::LibrariesSvr4Ops<'_, Self>>160 fn support_libraries_svr4(
161 &mut self,
162 ) -> Option<target::ext::libraries::LibrariesSvr4Ops<'_, Self>> {
163 Some(self)
164 }
165
166 #[inline(always)]
support_tracepoints( &mut self, ) -> Option<target::ext::tracepoints::TracepointsOps<'_, Self>>167 fn support_tracepoints(
168 &mut self,
169 ) -> Option<target::ext::tracepoints::TracepointsOps<'_, Self>> {
170 Some(self)
171 }
172 }
173
174 impl SingleThreadBase for Emu {
read_registers( &mut self, regs: &mut custom_arch::ArmCoreRegsCustom, ) -> TargetResult<(), Self>175 fn read_registers(
176 &mut self,
177 regs: &mut custom_arch::ArmCoreRegsCustom,
178 ) -> TargetResult<(), Self> {
179 // if we selected a frame from a tracepoint, return registers from that snapshot
180 let cpu = self
181 .selected_frame
182 .and_then(|selected| self.traceframes.get(selected))
183 .map(|frame| frame.snapshot)
184 .unwrap_or_else(|| self.cpu);
185 let mode = cpu.mode();
186
187 for i in 0..13 {
188 regs.core.r[i] = cpu.reg_get(mode, i as u8);
189 }
190 regs.core.sp = cpu.reg_get(mode, reg::SP);
191 regs.core.lr = cpu.reg_get(mode, reg::LR);
192 regs.core.pc = cpu.reg_get(mode, reg::PC);
193 regs.core.cpsr = cpu.reg_get(mode, reg::CPSR);
194
195 regs.custom = self.custom_reg;
196
197 Ok(())
198 }
199
write_registers(&mut self, regs: &custom_arch::ArmCoreRegsCustom) -> TargetResult<(), Self>200 fn write_registers(&mut self, regs: &custom_arch::ArmCoreRegsCustom) -> TargetResult<(), Self> {
201 if self.selected_frame.is_some() {
202 // we can't modify registers in a tracepoint frame
203 return Err(TargetError::NonFatal);
204 }
205 let mode = self.cpu.mode();
206
207 for i in 0..13 {
208 self.cpu.reg_set(mode, i, regs.core.r[i as usize]);
209 }
210 self.cpu.reg_set(mode, reg::SP, regs.core.sp);
211 self.cpu.reg_set(mode, reg::LR, regs.core.lr);
212 self.cpu.reg_set(mode, reg::PC, regs.core.pc);
213 self.cpu.reg_set(mode, reg::CPSR, regs.core.cpsr);
214
215 self.custom_reg = regs.custom;
216
217 Ok(())
218 }
219
220 #[inline(always)]
support_single_register_access( &mut self, ) -> Option<target::ext::base::single_register_access::SingleRegisterAccessOps<'_, (), Self>>221 fn support_single_register_access(
222 &mut self,
223 ) -> Option<target::ext::base::single_register_access::SingleRegisterAccessOps<'_, (), Self>>
224 {
225 Some(self)
226 }
227
read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<usize, Self>228 fn read_addrs(&mut self, start_addr: u32, data: &mut [u8]) -> TargetResult<usize, Self> {
229 if self.selected_frame.is_some() {
230 // we only support register collection actions for our tracepoint frames.
231 // if we have a selected frame, then we don't have any memory we can
232 // return from the frame snapshot.
233 return Ok(0);
234 }
235 // this is a simple emulator, with RAM covering the entire 32 bit address space
236 for (addr, val) in (start_addr..).zip(data.iter_mut()) {
237 *val = self.mem.r8(addr)
238 }
239 Ok(data.len())
240 }
241
write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self>242 fn write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self> {
243 if self.selected_frame.is_some() {
244 // we can't modify memory in a tracepoint frame
245 return Err(TargetError::NonFatal);
246 }
247
248 // this is a simple emulator, with RAM covering the entire 32 bit address space
249 for (addr, val) in (start_addr..).zip(data.iter().copied()) {
250 self.mem.w8(addr, val)
251 }
252 Ok(())
253 }
254
255 #[inline(always)]
support_resume( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadResumeOps<'_, Self>>256 fn support_resume(
257 &mut self,
258 ) -> Option<target::ext::base::singlethread::SingleThreadResumeOps<'_, Self>> {
259 Some(self)
260 }
261 }
262
263 impl SingleThreadResume for Emu {
resume(&mut self, signal: Option<Signal>) -> Result<(), Self::Error>264 fn resume(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> {
265 // Upon returning from the `resume` method, the target being debugged should be
266 // configured to run according to whatever resume actions the GDB client has
267 // specified (as specified by `set_resume_action`, `resume_range_step`,
268 // `reverse_{step, continue}`, etc...)
269 //
270 // In this basic `armv4t` example, the `resume` method simply sets the exec mode
271 // of the emulator's interpreter loop and returns.
272 //
273 // In more complex implementations, it's likely that the target being debugged
274 // will be running in another thread / process, and will require some kind of
275 // external "orchestration" to set it's execution mode (e.g: modifying the
276 // target's process state via platform specific debugging syscalls).
277
278 if signal.is_some() {
279 return Err("no support for continuing with signal");
280 }
281
282 self.exec_mode = ExecMode::Continue;
283
284 Ok(())
285 }
286
287 #[inline(always)]
support_reverse_cont( &mut self, ) -> Option<target::ext::base::reverse_exec::ReverseContOps<'_, (), Self>>288 fn support_reverse_cont(
289 &mut self,
290 ) -> Option<target::ext::base::reverse_exec::ReverseContOps<'_, (), Self>> {
291 Some(self)
292 }
293
294 #[inline(always)]
support_reverse_step( &mut self, ) -> Option<target::ext::base::reverse_exec::ReverseStepOps<'_, (), Self>>295 fn support_reverse_step(
296 &mut self,
297 ) -> Option<target::ext::base::reverse_exec::ReverseStepOps<'_, (), Self>> {
298 Some(self)
299 }
300
301 #[inline(always)]
support_single_step( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadSingleStepOps<'_, Self>>302 fn support_single_step(
303 &mut self,
304 ) -> Option<target::ext::base::singlethread::SingleThreadSingleStepOps<'_, Self>> {
305 Some(self)
306 }
307
308 #[inline(always)]
support_range_step( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadRangeSteppingOps<'_, Self>>309 fn support_range_step(
310 &mut self,
311 ) -> Option<target::ext::base::singlethread::SingleThreadRangeSteppingOps<'_, Self>> {
312 Some(self)
313 }
314 }
315
316 impl target::ext::base::singlethread::SingleThreadSingleStep for Emu {
step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error>317 fn step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> {
318 if signal.is_some() {
319 return Err("no support for stepping with signal");
320 }
321
322 self.exec_mode = ExecMode::Step;
323
324 Ok(())
325 }
326 }
327
328 impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu {
read_register( &mut self, _tid: (), reg_id: custom_arch::ArmCoreRegIdCustom, buf: &mut [u8], ) -> TargetResult<usize, Self>329 fn read_register(
330 &mut self,
331 _tid: (),
332 reg_id: custom_arch::ArmCoreRegIdCustom,
333 buf: &mut [u8],
334 ) -> TargetResult<usize, Self> {
335 match reg_id {
336 custom_arch::ArmCoreRegIdCustom::Core(reg_id) => {
337 if let Some(i) = cpu_reg_id(reg_id) {
338 let w = self.cpu.reg_get(self.cpu.mode(), i);
339 buf.copy_from_slice(&w.to_le_bytes());
340 Ok(buf.len())
341 } else {
342 Err(().into())
343 }
344 }
345 custom_arch::ArmCoreRegIdCustom::Custom => {
346 buf.copy_from_slice(&self.custom_reg.to_le_bytes());
347 Ok(buf.len())
348 }
349 custom_arch::ArmCoreRegIdCustom::Time => {
350 buf.copy_from_slice(
351 &(std::time::SystemTime::now()
352 .duration_since(std::time::UNIX_EPOCH)
353 .unwrap()
354 .as_millis() as u32)
355 .to_le_bytes(),
356 );
357 Ok(buf.len())
358 }
359 custom_arch::ArmCoreRegIdCustom::Unavailable => Ok(0),
360 }
361 }
362
write_register( &mut self, _tid: (), reg_id: custom_arch::ArmCoreRegIdCustom, val: &[u8], ) -> TargetResult<(), Self>363 fn write_register(
364 &mut self,
365 _tid: (),
366 reg_id: custom_arch::ArmCoreRegIdCustom,
367 val: &[u8],
368 ) -> TargetResult<(), Self> {
369 let w = u32::from_le_bytes(
370 val.try_into()
371 .map_err(|_| TargetError::Fatal("invalid data"))?,
372 );
373 match reg_id {
374 custom_arch::ArmCoreRegIdCustom::Core(reg_id) => {
375 if let Some(i) = cpu_reg_id(reg_id) {
376 self.cpu.reg_set(self.cpu.mode(), i, w);
377 Ok(())
378 } else {
379 Err(().into())
380 }
381 }
382 custom_arch::ArmCoreRegIdCustom::Custom => {
383 self.custom_reg = w;
384 Ok(())
385 }
386 // ignore writes
387 custom_arch::ArmCoreRegIdCustom::Unavailable
388 | custom_arch::ArmCoreRegIdCustom::Time => Ok(()),
389 }
390 }
391 }
392
393 impl target::ext::base::reverse_exec::ReverseCont<()> for Emu {
reverse_cont(&mut self) -> Result<(), Self::Error>394 fn reverse_cont(&mut self) -> Result<(), Self::Error> {
395 // FIXME: actually implement reverse step
396 eprintln!(
397 "FIXME: Not actually reverse-continuing. Performing forwards continue instead..."
398 );
399 self.exec_mode = ExecMode::Continue;
400 Ok(())
401 }
402 }
403
404 impl target::ext::base::reverse_exec::ReverseStep<()> for Emu {
reverse_step(&mut self, _tid: ()) -> Result<(), Self::Error>405 fn reverse_step(&mut self, _tid: ()) -> Result<(), Self::Error> {
406 // FIXME: actually implement reverse step
407 eprintln!(
408 "FIXME: Not actually reverse-stepping. Performing single forwards step instead..."
409 );
410 self.exec_mode = ExecMode::Step;
411 Ok(())
412 }
413 }
414
415 impl target::ext::base::singlethread::SingleThreadRangeStepping for Emu {
resume_range_step(&mut self, start: u32, end: u32) -> Result<(), Self::Error>416 fn resume_range_step(&mut self, start: u32, end: u32) -> Result<(), Self::Error> {
417 self.exec_mode = ExecMode::RangeStep(start, end);
418 Ok(())
419 }
420 }
421
422 mod custom_arch {
423 use core::num::NonZeroUsize;
424 use gdbstub::arch::lldb::Encoding;
425 use gdbstub::arch::lldb::Format;
426 use gdbstub::arch::lldb::Generic;
427 use gdbstub::arch::lldb::Register;
428 use gdbstub::arch::lldb::RegisterInfo;
429 use gdbstub::arch::Arch;
430 use gdbstub::arch::RegId;
431 use gdbstub::arch::Registers;
432 use gdbstub_arch::arm::reg::id::ArmCoreRegId;
433 use gdbstub_arch::arm::reg::ArmCoreRegs;
434 use gdbstub_arch::arm::ArmBreakpointKind;
435
436 /// Implements `Arch` for ARMv4T
437 pub enum Armv4tCustom {}
438
439 #[derive(Debug, Default, Clone, Eq, PartialEq)]
440 pub struct ArmCoreRegsCustom {
441 pub core: ArmCoreRegs,
442 pub custom: u32,
443 }
444
445 impl Registers for ArmCoreRegsCustom {
446 type ProgramCounter = u32;
447
pc(&self) -> Self::ProgramCounter448 fn pc(&self) -> Self::ProgramCounter {
449 self.core.pc
450 }
451
gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))452 fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
453 self.core.gdb_serialize(&mut write_byte);
454
455 macro_rules! write_bytes {
456 ($bytes:expr) => {
457 for b in $bytes {
458 write_byte(Some(*b))
459 }
460 };
461 }
462
463 write_bytes!(&self.custom.to_le_bytes());
464 }
465
gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>466 fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
467 // ensure bytes.chunks_exact(4) won't panic
468 if bytes.len() % 4 != 0 {
469 return Err(());
470 }
471
472 use core::convert::TryInto;
473 let mut regs = bytes
474 .chunks_exact(4)
475 .map(|c| u32::from_le_bytes(c.try_into().unwrap()));
476
477 // copied from ArmCoreRegs
478 {
479 for reg in self.core.r.iter_mut() {
480 *reg = regs.next().ok_or(())?
481 }
482 self.core.sp = regs.next().ok_or(())?;
483 self.core.lr = regs.next().ok_or(())?;
484 self.core.pc = regs.next().ok_or(())?;
485
486 // Floating point registers (unused)
487 for _ in 0..25 {
488 regs.next().ok_or(())?;
489 }
490
491 self.core.cpsr = regs.next().ok_or(())?;
492 }
493
494 self.custom = regs.next().ok_or(())?;
495
496 if regs.next().is_some() {
497 return Err(());
498 }
499
500 Ok(())
501 }
502 }
503
504 #[derive(Debug)]
505 pub enum ArmCoreRegIdCustom {
506 Core(ArmCoreRegId),
507 Custom,
508 // not sent as part of `struct ArmCoreRegsCustom`, and only accessible via the single
509 // register read/write functions
510 Time,
511 /// This pseudo-register is valid but never available
512 Unavailable,
513 }
514
515 impl RegId for ArmCoreRegIdCustom {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>516 fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
517 let reg = match id {
518 26 => Self::Custom,
519 27 => Self::Time,
520 28 => Self::Unavailable,
521 _ => {
522 let (reg, size) = ArmCoreRegId::from_raw_id(id)?;
523 return Some((Self::Core(reg), size));
524 }
525 };
526 Some((reg, Some(NonZeroUsize::new(4)?)))
527 }
528 }
529
530 impl Arch for Armv4tCustom {
531 type Usize = u32;
532 type Registers = ArmCoreRegsCustom;
533 type RegId = ArmCoreRegIdCustom;
534 type BreakpointKind = ArmBreakpointKind;
535
536 // for _purely demonstrative purposes_, i'll return dummy data from this
537 // function, as it will be overwritten by TargetDescriptionXmlOverride.
538 //
539 // See `examples/armv4t/gdb/target_description_xml_override.rs`
540 //
541 // in an actual implementation, you'll want to return an actual string here!
target_description_xml() -> Option<&'static str>542 fn target_description_xml() -> Option<&'static str> {
543 Some("never gets returned")
544 }
545
546 // (LLDB extension)
547 //
548 // for _purely demonstrative purposes_, even though this provides a working
549 // example, it will get overwritten by RegisterInfoOverride.
550 //
551 // See `examples/armv4t/gdb/register_info_override.rs`
lldb_register_info(reg_id: usize) -> Option<RegisterInfo<'static>>552 fn lldb_register_info(reg_id: usize) -> Option<RegisterInfo<'static>> {
553 match ArmCoreRegIdCustom::from_raw_id(reg_id) {
554 Some((_, None)) | None => Some(RegisterInfo::Done),
555 Some((r, Some(size))) => {
556 let name = match r {
557 // For the purpose of demonstration, we end the qRegisterInfo packet
558 // exchange when reaching the Time register id, so that this register can
559 // only be explicitly queried via the single-register read packet.
560 ArmCoreRegIdCustom::Time => return Some(RegisterInfo::Done),
561 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(i)) => match i {
562 0 => "r0",
563 1 => "r1",
564 2 => "r2",
565 3 => "r3",
566 4 => "r4",
567 5 => "r5",
568 6 => "r6",
569 7 => "r7",
570 8 => "r8",
571 9 => "r9",
572 10 => "r10",
573 11 => "r11",
574 12 => "r12",
575 _ => "unknown",
576 },
577 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) => "sp",
578 ArmCoreRegIdCustom::Core(ArmCoreRegId::Lr) => "lr",
579 ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) => "pc",
580 ArmCoreRegIdCustom::Core(ArmCoreRegId::Fpr(_i)) => "padding",
581 ArmCoreRegIdCustom::Core(ArmCoreRegId::Fps) => "padding",
582 ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) => "cpsr",
583 ArmCoreRegIdCustom::Custom => "custom",
584 ArmCoreRegIdCustom::Unavailable => "Unavailable",
585 _ => "unknown",
586 };
587 let encoding = match r {
588 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => Encoding::Uint,
589 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
590 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
591 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
592 | ArmCoreRegIdCustom::Unavailable
593 | ArmCoreRegIdCustom::Custom => Encoding::Uint,
594 _ => Encoding::Vector,
595 };
596 let format = match r {
597 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => Format::Hex,
598 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
599 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
600 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
601 | ArmCoreRegIdCustom::Unavailable
602 | ArmCoreRegIdCustom::Custom => Format::Hex,
603 _ => Format::VectorUInt8,
604 };
605 let set = match r {
606 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => {
607 "General Purpose Registers"
608 }
609 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
610 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
611 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
612 | ArmCoreRegIdCustom::Unavailable
613 | ArmCoreRegIdCustom::Custom => "General Purpose Registers",
614 _ => "Floating Point Registers",
615 };
616 let generic = match r {
617 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) => Some(Generic::Sp),
618 ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) => Some(Generic::Pc),
619 _ => None,
620 };
621 let reg = Register {
622 name,
623 alt_name: None,
624 bitsize: (usize::from(size)) * 8,
625 offset: reg_id * (usize::from(size)),
626 encoding,
627 format,
628 set,
629 gcc: None,
630 dwarf: Some(reg_id),
631 generic,
632 container_regs: None,
633 invalidate_regs: None,
634 };
635 Some(RegisterInfo::Register(reg))
636 }
637 }
638 }
639 }
640 }
641