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 // These values are taken from the link script.
212 const MEMORY_ORIGIN: u32 = 0x5555_0000;
213 const MEMORY_LENGTH: u32 = 0x1000_0000;
214 const MEMORY_END: u32 = MEMORY_ORIGIN + MEMORY_LENGTH;
215
216 if !(MEMORY_ORIGIN..MEMORY_END).contains(&start_addr) {
217 return Err(TargetError::NonFatal);
218 }
219
220 let end_addr = std::cmp::min(start_addr + data.len() as u32, MEMORY_END);
221
222 for (addr, val) in (start_addr..end_addr).zip(data.iter_mut()) {
223 *val = self.mem.r8(addr)
224 }
225 Ok((end_addr - start_addr) as usize)
226 }
227
write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self>228 fn write_addrs(&mut self, start_addr: u32, data: &[u8]) -> TargetResult<(), Self> {
229 for (addr, val) in (start_addr..).zip(data.iter().copied()) {
230 self.mem.w8(addr, val)
231 }
232 Ok(())
233 }
234
235 #[inline(always)]
support_resume( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadResumeOps<'_, Self>>236 fn support_resume(
237 &mut self,
238 ) -> Option<target::ext::base::singlethread::SingleThreadResumeOps<'_, Self>> {
239 Some(self)
240 }
241 }
242
243 impl SingleThreadResume for Emu {
resume(&mut self, signal: Option<Signal>) -> Result<(), Self::Error>244 fn resume(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> {
245 // Upon returning from the `resume` method, the target being debugged should be
246 // configured to run according to whatever resume actions the GDB client has
247 // specified (as specified by `set_resume_action`, `resume_range_step`,
248 // `reverse_{step, continue}`, etc...)
249 //
250 // In this basic `armv4t` example, the `resume` method simply sets the exec mode
251 // of the emulator's interpreter loop and returns.
252 //
253 // In more complex implementations, it's likely that the target being debugged
254 // will be running in another thread / process, and will require some kind of
255 // external "orchestration" to set it's execution mode (e.g: modifying the
256 // target's process state via platform specific debugging syscalls).
257
258 if signal.is_some() {
259 return Err("no support for continuing with signal");
260 }
261
262 self.exec_mode = ExecMode::Continue;
263
264 Ok(())
265 }
266
267 #[inline(always)]
support_reverse_cont( &mut self, ) -> Option<target::ext::base::reverse_exec::ReverseContOps<'_, (), Self>>268 fn support_reverse_cont(
269 &mut self,
270 ) -> Option<target::ext::base::reverse_exec::ReverseContOps<'_, (), Self>> {
271 Some(self)
272 }
273
274 #[inline(always)]
support_reverse_step( &mut self, ) -> Option<target::ext::base::reverse_exec::ReverseStepOps<'_, (), Self>>275 fn support_reverse_step(
276 &mut self,
277 ) -> Option<target::ext::base::reverse_exec::ReverseStepOps<'_, (), Self>> {
278 Some(self)
279 }
280
281 #[inline(always)]
support_single_step( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadSingleStepOps<'_, Self>>282 fn support_single_step(
283 &mut self,
284 ) -> Option<target::ext::base::singlethread::SingleThreadSingleStepOps<'_, Self>> {
285 Some(self)
286 }
287
288 #[inline(always)]
support_range_step( &mut self, ) -> Option<target::ext::base::singlethread::SingleThreadRangeSteppingOps<'_, Self>>289 fn support_range_step(
290 &mut self,
291 ) -> Option<target::ext::base::singlethread::SingleThreadRangeSteppingOps<'_, Self>> {
292 Some(self)
293 }
294 }
295
296 impl target::ext::base::singlethread::SingleThreadSingleStep for Emu {
step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error>297 fn step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> {
298 if signal.is_some() {
299 return Err("no support for stepping with signal");
300 }
301
302 self.exec_mode = ExecMode::Step;
303
304 Ok(())
305 }
306 }
307
308 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>309 fn read_register(
310 &mut self,
311 _tid: (),
312 reg_id: custom_arch::ArmCoreRegIdCustom,
313 buf: &mut [u8],
314 ) -> TargetResult<usize, Self> {
315 match reg_id {
316 custom_arch::ArmCoreRegIdCustom::Core(reg_id) => {
317 if let Some(i) = cpu_reg_id(reg_id) {
318 let w = self.cpu.reg_get(self.cpu.mode(), i);
319 buf.copy_from_slice(&w.to_le_bytes());
320 Ok(buf.len())
321 } else {
322 Err(().into())
323 }
324 }
325 custom_arch::ArmCoreRegIdCustom::Custom => {
326 buf.copy_from_slice(&self.custom_reg.to_le_bytes());
327 Ok(buf.len())
328 }
329 custom_arch::ArmCoreRegIdCustom::Time => {
330 buf.copy_from_slice(
331 &(std::time::SystemTime::now()
332 .duration_since(std::time::UNIX_EPOCH)
333 .unwrap()
334 .as_millis() as u32)
335 .to_le_bytes(),
336 );
337 Ok(buf.len())
338 }
339 custom_arch::ArmCoreRegIdCustom::Unavailable => Ok(0),
340 }
341 }
342
write_register( &mut self, _tid: (), reg_id: custom_arch::ArmCoreRegIdCustom, val: &[u8], ) -> TargetResult<(), Self>343 fn write_register(
344 &mut self,
345 _tid: (),
346 reg_id: custom_arch::ArmCoreRegIdCustom,
347 val: &[u8],
348 ) -> TargetResult<(), Self> {
349 let w = u32::from_le_bytes(
350 val.try_into()
351 .map_err(|_| TargetError::Fatal("invalid data"))?,
352 );
353 match reg_id {
354 custom_arch::ArmCoreRegIdCustom::Core(reg_id) => {
355 if let Some(i) = cpu_reg_id(reg_id) {
356 self.cpu.reg_set(self.cpu.mode(), i, w);
357 Ok(())
358 } else {
359 Err(().into())
360 }
361 }
362 custom_arch::ArmCoreRegIdCustom::Custom => {
363 self.custom_reg = w;
364 Ok(())
365 }
366 // ignore writes
367 custom_arch::ArmCoreRegIdCustom::Unavailable
368 | custom_arch::ArmCoreRegIdCustom::Time => Ok(()),
369 }
370 }
371 }
372
373 impl target::ext::base::reverse_exec::ReverseCont<()> for Emu {
reverse_cont(&mut self) -> Result<(), Self::Error>374 fn reverse_cont(&mut self) -> Result<(), Self::Error> {
375 // FIXME: actually implement reverse step
376 eprintln!(
377 "FIXME: Not actually reverse-continuing. Performing forwards continue instead..."
378 );
379 self.exec_mode = ExecMode::Continue;
380 Ok(())
381 }
382 }
383
384 impl target::ext::base::reverse_exec::ReverseStep<()> for Emu {
reverse_step(&mut self, _tid: ()) -> Result<(), Self::Error>385 fn reverse_step(&mut self, _tid: ()) -> Result<(), Self::Error> {
386 // FIXME: actually implement reverse step
387 eprintln!(
388 "FIXME: Not actually reverse-stepping. Performing single forwards step instead..."
389 );
390 self.exec_mode = ExecMode::Step;
391 Ok(())
392 }
393 }
394
395 impl target::ext::base::singlethread::SingleThreadRangeStepping for Emu {
resume_range_step(&mut self, start: u32, end: u32) -> Result<(), Self::Error>396 fn resume_range_step(&mut self, start: u32, end: u32) -> Result<(), Self::Error> {
397 self.exec_mode = ExecMode::RangeStep(start, end);
398 Ok(())
399 }
400 }
401
402 mod custom_arch {
403 use core::num::NonZeroUsize;
404 use gdbstub::arch::lldb::Encoding;
405 use gdbstub::arch::lldb::Format;
406 use gdbstub::arch::lldb::Generic;
407 use gdbstub::arch::lldb::Register;
408 use gdbstub::arch::lldb::RegisterInfo;
409 use gdbstub::arch::Arch;
410 use gdbstub::arch::RegId;
411 use gdbstub::arch::Registers;
412 use gdbstub_arch::arm::reg::id::ArmCoreRegId;
413 use gdbstub_arch::arm::reg::ArmCoreRegs;
414 use gdbstub_arch::arm::ArmBreakpointKind;
415
416 /// Implements `Arch` for ARMv4T
417 pub enum Armv4tCustom {}
418
419 #[derive(Debug, Default, Clone, Eq, PartialEq)]
420 pub struct ArmCoreRegsCustom {
421 pub core: ArmCoreRegs,
422 pub custom: u32,
423 }
424
425 impl Registers for ArmCoreRegsCustom {
426 type ProgramCounter = u32;
427
pc(&self) -> Self::ProgramCounter428 fn pc(&self) -> Self::ProgramCounter {
429 self.core.pc
430 }
431
gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))432 fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
433 self.core.gdb_serialize(&mut write_byte);
434
435 macro_rules! write_bytes {
436 ($bytes:expr) => {
437 for b in $bytes {
438 write_byte(Some(*b))
439 }
440 };
441 }
442
443 write_bytes!(&self.custom.to_le_bytes());
444 }
445
gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>446 fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
447 // ensure bytes.chunks_exact(4) won't panic
448 if bytes.len() % 4 != 0 {
449 return Err(());
450 }
451
452 use core::convert::TryInto;
453 let mut regs = bytes
454 .chunks_exact(4)
455 .map(|c| u32::from_le_bytes(c.try_into().unwrap()));
456
457 // copied from ArmCoreRegs
458 {
459 for reg in self.core.r.iter_mut() {
460 *reg = regs.next().ok_or(())?
461 }
462 self.core.sp = regs.next().ok_or(())?;
463 self.core.lr = regs.next().ok_or(())?;
464 self.core.pc = regs.next().ok_or(())?;
465
466 // Floating point registers (unused)
467 for _ in 0..25 {
468 regs.next().ok_or(())?;
469 }
470
471 self.core.cpsr = regs.next().ok_or(())?;
472 }
473
474 self.custom = regs.next().ok_or(())?;
475
476 if regs.next().is_some() {
477 return Err(());
478 }
479
480 Ok(())
481 }
482 }
483
484 #[derive(Debug)]
485 pub enum ArmCoreRegIdCustom {
486 Core(ArmCoreRegId),
487 Custom,
488 // not sent as part of `struct ArmCoreRegsCustom`, and only accessible via the single
489 // register read/write functions
490 Time,
491 /// This pseudo-register is valid but never available
492 Unavailable,
493 }
494
495 impl RegId for ArmCoreRegIdCustom {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>496 fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
497 let reg = match id {
498 26 => Self::Custom,
499 27 => Self::Time,
500 28 => Self::Unavailable,
501 _ => {
502 let (reg, size) = ArmCoreRegId::from_raw_id(id)?;
503 return Some((Self::Core(reg), size));
504 }
505 };
506 Some((reg, Some(NonZeroUsize::new(4)?)))
507 }
508 }
509
510 impl Arch for Armv4tCustom {
511 type Usize = u32;
512 type Registers = ArmCoreRegsCustom;
513 type RegId = ArmCoreRegIdCustom;
514 type BreakpointKind = ArmBreakpointKind;
515
516 // for _purely demonstrative purposes_, i'll return dummy data from this
517 // function, as it will be overwritten by TargetDescriptionXmlOverride.
518 //
519 // See `examples/armv4t/gdb/target_description_xml_override.rs`
520 //
521 // in an actual implementation, you'll want to return an actual string here!
target_description_xml() -> Option<&'static str>522 fn target_description_xml() -> Option<&'static str> {
523 Some("never gets returned")
524 }
525
526 // (LLDB extension)
527 //
528 // for _purely demonstrative purposes_, even though this provides a working
529 // example, it will get overwritten by RegisterInfoOverride.
530 //
531 // See `examples/armv4t/gdb/register_info_override.rs`
lldb_register_info(reg_id: usize) -> Option<RegisterInfo<'static>>532 fn lldb_register_info(reg_id: usize) -> Option<RegisterInfo<'static>> {
533 match ArmCoreRegIdCustom::from_raw_id(reg_id) {
534 Some((_, None)) | None => Some(RegisterInfo::Done),
535 Some((r, Some(size))) => {
536 let name = match r {
537 // For the purpose of demonstration, we end the qRegisterInfo packet
538 // exchange when reaching the Time register id, so that this register can
539 // only be explicitly queried via the single-register read packet.
540 ArmCoreRegIdCustom::Time => return Some(RegisterInfo::Done),
541 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(i)) => match i {
542 0 => "r0",
543 1 => "r1",
544 2 => "r2",
545 3 => "r3",
546 4 => "r4",
547 5 => "r5",
548 6 => "r6",
549 7 => "r7",
550 8 => "r8",
551 9 => "r9",
552 10 => "r10",
553 11 => "r11",
554 12 => "r12",
555 _ => "unknown",
556 },
557 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) => "sp",
558 ArmCoreRegIdCustom::Core(ArmCoreRegId::Lr) => "lr",
559 ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) => "pc",
560 ArmCoreRegIdCustom::Core(ArmCoreRegId::Fpr(_i)) => "padding",
561 ArmCoreRegIdCustom::Core(ArmCoreRegId::Fps) => "padding",
562 ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr) => "cpsr",
563 ArmCoreRegIdCustom::Custom => "custom",
564 ArmCoreRegIdCustom::Unavailable => "Unavailable",
565 _ => "unknown",
566 };
567 let encoding = match r {
568 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => Encoding::Uint,
569 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
570 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
571 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
572 | ArmCoreRegIdCustom::Unavailable
573 | ArmCoreRegIdCustom::Custom => Encoding::Uint,
574 _ => Encoding::Vector,
575 };
576 let format = match r {
577 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => Format::Hex,
578 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
579 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
580 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
581 | ArmCoreRegIdCustom::Unavailable
582 | ArmCoreRegIdCustom::Custom => Format::Hex,
583 _ => Format::VectorUInt8,
584 };
585 let set = match r {
586 ArmCoreRegIdCustom::Core(ArmCoreRegId::Gpr(_i)) => {
587 "General Purpose Registers"
588 }
589 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp)
590 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc)
591 | ArmCoreRegIdCustom::Core(ArmCoreRegId::Cpsr)
592 | ArmCoreRegIdCustom::Unavailable
593 | ArmCoreRegIdCustom::Custom => "General Purpose Registers",
594 _ => "Floating Point Registers",
595 };
596 let generic = match r {
597 ArmCoreRegIdCustom::Core(ArmCoreRegId::Sp) => Some(Generic::Sp),
598 ArmCoreRegIdCustom::Core(ArmCoreRegId::Pc) => Some(Generic::Pc),
599 _ => None,
600 };
601 let reg = Register {
602 name,
603 alt_name: None,
604 bitsize: (usize::from(size)) * 8,
605 offset: reg_id * (usize::from(size)),
606 encoding,
607 format,
608 set,
609 gcc: None,
610 dwarf: Some(reg_id),
611 generic,
612 container_regs: None,
613 invalidate_regs: None,
614 };
615 Some(RegisterInfo::Register(reg))
616 }
617 }
618 }
619 }
620 }
621