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