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