-
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gdbstub_arch: Add support for AArch64 (#109)
* gdbstub_arch: Add support for AArch64 Implement gdbstub::arch::Arch for the 64-bit mode of the ARMv8-A architecture. Signed-off-by: Pierre-Clément Tosi <[email protected]> * fixup! gdbstub_arch: Add support for AArch64 Signed-off-by: Pierre-Clément Tosi <[email protected]>
- Loading branch information
Showing
8 changed files
with
3,113 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<feature name="org.gnu.gdb.aarch64.core"> | ||
|
||
<!-- source: binutils-gdb/blob/master/gdb/features/aarch64-core.xml --> | ||
|
||
<!-- Copyright (C) 2009-2022 Free Software Foundation, Inc. | ||
Contributed by ARM Ltd. | ||
Copying and distribution of this file, with or without modification, | ||
are permitted in any medium without royalty provided the copyright | ||
notice and this notice are preserved. --> | ||
|
||
<reg name="x0" bitsize="64"/> | ||
<reg name="x1" bitsize="64"/> | ||
<reg name="x2" bitsize="64"/> | ||
<reg name="x3" bitsize="64"/> | ||
<reg name="x4" bitsize="64"/> | ||
<reg name="x5" bitsize="64"/> | ||
<reg name="x6" bitsize="64"/> | ||
<reg name="x7" bitsize="64"/> | ||
<reg name="x8" bitsize="64"/> | ||
<reg name="x9" bitsize="64"/> | ||
<reg name="x10" bitsize="64"/> | ||
<reg name="x11" bitsize="64"/> | ||
<reg name="x12" bitsize="64"/> | ||
<reg name="x13" bitsize="64"/> | ||
<reg name="x14" bitsize="64"/> | ||
<reg name="x15" bitsize="64"/> | ||
<reg name="x16" bitsize="64"/> | ||
<reg name="x17" bitsize="64"/> | ||
<reg name="x18" bitsize="64"/> | ||
<reg name="x19" bitsize="64"/> | ||
<reg name="x20" bitsize="64"/> | ||
<reg name="x21" bitsize="64"/> | ||
<reg name="x22" bitsize="64"/> | ||
<reg name="x23" bitsize="64"/> | ||
<reg name="x24" bitsize="64"/> | ||
<reg name="x25" bitsize="64"/> | ||
<reg name="x26" bitsize="64"/> | ||
<reg name="x27" bitsize="64"/> | ||
<reg name="x28" bitsize="64"/> | ||
<reg name="x29" bitsize="64"/> | ||
<reg name="x30" bitsize="64"/> | ||
<reg name="sp" bitsize="64" type="data_ptr"/> | ||
|
||
<reg name="pc" bitsize="64" type="code_ptr"/> | ||
|
||
<flags id="cpsr_flags" size="4"> | ||
<!-- Stack Pointer. --> | ||
<field name="SP" start="0" end="0"/> | ||
|
||
<!-- Exception Level. --> | ||
<field name="EL" start="2" end="3"/> | ||
<!-- Execution state. --> | ||
<field name="nRW" start="4" end="4"/> | ||
|
||
<!-- FIQ interrupt mask. --> | ||
<field name="F" start="6" end="6"/> | ||
<!-- IRQ interrupt mask. --> | ||
<field name="I" start="7" end="7"/> | ||
<!-- SError interrupt mask. --> | ||
<field name="A" start="8" end="8"/> | ||
<!-- Debug exception mask. --> | ||
<field name="D" start="9" end="9"/> | ||
|
||
<!-- ARMv8.5-A: Branch Target Identification BTYPE. --> | ||
<field name="BTYPE" start="10" end="11"/> | ||
|
||
<!-- ARMv8.0-A: Speculative Store Bypass. --> | ||
<field name="SSBS" start="12" end="12"/> | ||
|
||
<!-- Illegal Execution state. --> | ||
<field name="IL" start="20" end="20"/> | ||
<!-- Software Step. --> | ||
<field name="SS" start="21" end="21"/> | ||
<!-- ARMv8.1-A: Privileged Access Never. --> | ||
<field name="PAN" start="22" end="22"/> | ||
<!-- ARMv8.2-A: User Access Override. --> | ||
<field name="UAO" start="23" end="23"/> | ||
<!-- ARMv8.4-A: Data Independent Timing. --> | ||
<field name="DIT" start="24" end="24"/> | ||
<!-- ARMv8.5-A: Tag Check Override. --> | ||
<field name="TCO" start="25" end="25"/> | ||
|
||
<!-- Overflow Condition flag. --> | ||
<field name="V" start="28" end="28"/> | ||
<!-- Carry Condition flag. --> | ||
<field name="C" start="29" end="29"/> | ||
<!-- Zero Condition flag. --> | ||
<field name="Z" start="30" end="30"/> | ||
<!-- Negative Condition flag. --> | ||
<field name="N" start="31" end="31"/> | ||
</flags> | ||
<reg name="cpsr" bitsize="32" type="cpsr_flags"/> | ||
|
||
</feature> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<feature name="org.gnu.gdb.aarch64.fpu"> | ||
|
||
<!-- source: binutils-gdb/blob/master/gdb/features/aarch64-fpu.xml --> | ||
|
||
<!-- Copyright (C) 2009-2022 Free Software Foundation, Inc. | ||
Contributed by ARM Ltd. | ||
Copying and distribution of this file, with or without modification, | ||
are permitted in any medium without royalty provided the copyright | ||
notice and this notice are preserved. --> | ||
|
||
<vector id="v2d" type="ieee_double" count="2"/> | ||
<vector id="v2u" type="uint64" count="2"/> | ||
<vector id="v2i" type="int64" count="2"/> | ||
<vector id="v4f" type="ieee_single" count="4"/> | ||
<vector id="v4u" type="uint32" count="4"/> | ||
<vector id="v4i" type="int32" count="4"/> | ||
<vector id="v8f" type="ieee_half" count="8"/> | ||
<vector id="v8u" type="uint16" count="8"/> | ||
<vector id="v8i" type="int16" count="8"/> | ||
<vector id="v8bf16" type="bfloat16" count="8"/> | ||
<vector id="v16u" type="uint8" count="16"/> | ||
<vector id="v16i" type="int8" count="16"/> | ||
<vector id="v1u" type="uint128" count="1"/> | ||
<vector id="v1i" type="int128" count="1"/> | ||
<union id="vnd"> | ||
<field name="f" type="v2d"/> | ||
<field name="u" type="v2u"/> | ||
<field name="s" type="v2i"/> | ||
</union> | ||
<union id="vns"> | ||
<field name="f" type="v4f"/> | ||
<field name="u" type="v4u"/> | ||
<field name="s" type="v4i"/> | ||
</union> | ||
<union id="vnh"> | ||
<field name="bf" type="v8bf16"/> | ||
<field name="f" type="v8f"/> | ||
<field name="u" type="v8u"/> | ||
<field name="s" type="v8i"/> | ||
</union> | ||
<union id="vnb"> | ||
<field name="u" type="v16u"/> | ||
<field name="s" type="v16i"/> | ||
</union> | ||
<union id="vnq"> | ||
<field name="u" type="v1u"/> | ||
<field name="s" type="v1i"/> | ||
</union> | ||
<union id="aarch64v"> | ||
<field name="d" type="vnd"/> | ||
<field name="s" type="vns"/> | ||
<field name="h" type="vnh"/> | ||
<field name="b" type="vnb"/> | ||
<field name="q" type="vnq"/> | ||
</union> | ||
<reg name="v0" bitsize="128" type="aarch64v" regnum="34"/> | ||
<reg name="v1" bitsize="128" type="aarch64v" /> | ||
<reg name="v2" bitsize="128" type="aarch64v" /> | ||
<reg name="v3" bitsize="128" type="aarch64v" /> | ||
<reg name="v4" bitsize="128" type="aarch64v" /> | ||
<reg name="v5" bitsize="128" type="aarch64v" /> | ||
<reg name="v6" bitsize="128" type="aarch64v" /> | ||
<reg name="v7" bitsize="128" type="aarch64v" /> | ||
<reg name="v8" bitsize="128" type="aarch64v" /> | ||
<reg name="v9" bitsize="128" type="aarch64v" /> | ||
<reg name="v10" bitsize="128" type="aarch64v"/> | ||
<reg name="v11" bitsize="128" type="aarch64v"/> | ||
<reg name="v12" bitsize="128" type="aarch64v"/> | ||
<reg name="v13" bitsize="128" type="aarch64v"/> | ||
<reg name="v14" bitsize="128" type="aarch64v"/> | ||
<reg name="v15" bitsize="128" type="aarch64v"/> | ||
<reg name="v16" bitsize="128" type="aarch64v"/> | ||
<reg name="v17" bitsize="128" type="aarch64v"/> | ||
<reg name="v18" bitsize="128" type="aarch64v"/> | ||
<reg name="v19" bitsize="128" type="aarch64v"/> | ||
<reg name="v20" bitsize="128" type="aarch64v"/> | ||
<reg name="v21" bitsize="128" type="aarch64v"/> | ||
<reg name="v22" bitsize="128" type="aarch64v"/> | ||
<reg name="v23" bitsize="128" type="aarch64v"/> | ||
<reg name="v24" bitsize="128" type="aarch64v"/> | ||
<reg name="v25" bitsize="128" type="aarch64v"/> | ||
<reg name="v26" bitsize="128" type="aarch64v"/> | ||
<reg name="v27" bitsize="128" type="aarch64v"/> | ||
<reg name="v28" bitsize="128" type="aarch64v"/> | ||
<reg name="v29" bitsize="128" type="aarch64v"/> | ||
<reg name="v30" bitsize="128" type="aarch64v"/> | ||
<reg name="v31" bitsize="128" type="aarch64v"/> | ||
|
||
<flags id="fpsr_flags" size="4"> | ||
<!-- Invalid Operation cumulative floating-point exception bit. --> | ||
<field name="IOC" start="0" end="0"/> | ||
<!-- Divide by Zero cumulative floating-point exception bit. --> | ||
<field name="DZC" start="1" end="1"/> | ||
<!-- Overflow cumulative floating-point exception bit. --> | ||
<field name="OFC" start="2" end="2"/> | ||
<!-- Underflow cumulative floating-point exception bit. --> | ||
<field name="UFC" start="3" end="3"/> | ||
<!-- Inexact cumulative floating-point exception bit.. --> | ||
<field name="IXC" start="4" end="4"/> | ||
<!-- Input Denormal cumulative floating-point exception bit. --> | ||
<field name="IDC" start="7" end="7"/> | ||
<!-- Cumulative saturation bit, Advanced SIMD only. --> | ||
<field name="QC" start="27" end="27"/> | ||
<!-- When AArch32 is supported at any Exception level and AArch32 | ||
floating-point is implemented: Overflow condition flag for AArch32 | ||
floating-point comparison operations. --> | ||
<field name="V" start="28" end="28"/> | ||
<!-- When AArch32 is supported at any Exception level and AArch32 | ||
floating-point is implemented: | ||
Carry condition flag for AArch32 floating-point comparison operations. | ||
--> | ||
<field name="C" start="29" end="29"/> | ||
<!-- When AArch32 is supported at any Exception level and AArch32 | ||
floating-point is implemented: | ||
Zero condition flag for AArch32 floating-point comparison operations. | ||
--> | ||
<field name="Z" start="30" end="30"/> | ||
<!-- When AArch32 is supported at any Exception level and AArch32 | ||
floating-point is implemented: | ||
Negative condition flag for AArch32 floating-point comparison | ||
operations. --> | ||
<field name="N" start="31" end="31"/> | ||
</flags> | ||
<reg name="fpsr" bitsize="32" type="fpsr_flags"/> | ||
|
||
<flags id="fpcr_flags" size="4"> | ||
<!-- Flush Inputs to Zero (part of Armv8.7). --> | ||
<field name="FIZ" start="0" end="0"/> | ||
<!-- Alternate Handling (part of Armv8.7). --> | ||
<field name="AH" start="1" end="1"/> | ||
<!-- Controls how the output elements other than the lowest element of the | ||
vector are determined for Advanced SIMD scalar instructions (part of | ||
Armv8.7). --> | ||
<field name="NEP" start="2" end="2"/> | ||
<!-- Invalid Operation floating-point exception trap enable. --> | ||
<field name="IOE" start="8" end="8"/> | ||
<!-- Divide by Zero floating-point exception trap enable. --> | ||
<field name="DZE" start="9" end="9"/> | ||
<!-- Overflow floating-point exception trap enable. --> | ||
<field name="OFE" start="10" end="10"/> | ||
<!-- Underflow floating-point exception trap enable. --> | ||
<field name="UFE" start="11" end="11"/> | ||
<!-- Inexact floating-point exception trap enable. --> | ||
<field name="IXE" start="12" end="12"/> | ||
<!-- Input Denormal floating-point exception trap enable. --> | ||
<field name="IDE" start="15" end="15"/> | ||
<!-- Flush-to-zero mode control bit on half-precision data-processing | ||
instructions. --> | ||
<field name="FZ16" start="19" end="19"/> | ||
<!-- Rounding Mode control field. --> | ||
<field name="RMode" start="22" end="23"/> | ||
<!-- Flush-to-zero mode control bit. --> | ||
<field name="FZ" start="24" end="24"/> | ||
<!-- Default NaN mode control bit. --> | ||
<field name="DN" start="25" end="25"/> | ||
<!-- Alternative half-precision control bit. --> | ||
<field name="AHP" start="26" end="26"/> | ||
</flags> | ||
<reg name="fpcr" bitsize="32" type="fpcr_flags"/> | ||
</feature> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
//! Implementation for the [AArch64](https://developer.arm.com/documentation/102374) | ||
//! ARM architecture. | ||
//! | ||
//! See PR [#109](https://github.com/daniel5151/gdbstub/pull/109) for more info. | ||
//! | ||
//! *Note*: doesn't support the AArch32 execution mode. | ||
//! *Note*: the target XML currently advertises all system registers to the GDB | ||
//! client. | ||
use gdbstub::arch::{Arch, SingleStepGdbBehavior}; | ||
|
||
pub mod reg; | ||
|
||
/// Implements `Arch` for ARM AArch64. | ||
pub struct AArch64 {} | ||
|
||
impl Arch for AArch64 { | ||
type Usize = u64; | ||
type Registers = reg::AArch64CoreRegs; | ||
type RegId = reg::id::AArch64RegId; | ||
type BreakpointKind = usize; | ||
|
||
fn target_description_xml() -> Option<&'static str> { | ||
static DESCRIPTION_XML: &str = concat!( | ||
r#"<target version="1.0">"#, | ||
"<architecture>aarch64</architecture>", | ||
include_str!("core.xml"), // feature "org.gnu.gdb.aarch64.core" | ||
include_str!("fpu.xml"), // feature "org.gnu.gdb.aarch64.fpu" | ||
include_str!("sysregs.xml"), | ||
"</target>", | ||
); | ||
|
||
Some(DESCRIPTION_XML) | ||
} | ||
|
||
#[inline(always)] | ||
fn single_step_gdb_behavior() -> SingleStepGdbBehavior { | ||
SingleStepGdbBehavior::Required | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use core::convert::TryInto; | ||
|
||
use gdbstub::arch::Registers; | ||
|
||
/// AArch64 core registers. | ||
/// | ||
/// Registers from the `org.gnu.gdb.aarch64.core` and `org.gnu.gdb.aarch64.fpu` | ||
/// [AArch64 Standard GDB Target Features](https://sourceware.org/gdb/onlinedocs/gdb/AArch64-Features.html). | ||
#[derive(Debug, Default, Clone, Eq, PartialEq)] | ||
pub struct AArch64CoreRegs { | ||
/// General Purpose Registers (X0-X30) | ||
pub x: [u64; 31], | ||
/// Stack Pointer | ||
pub sp: u64, | ||
/// Program Counter | ||
pub pc: u64, | ||
/// Process State (GDB uses the AArch32 CPSR name) | ||
pub cpsr: u32, | ||
/// FP & SIMD Registers (V0-V31) | ||
pub v: [u128; 32], | ||
/// Floating-point Control Register | ||
pub fpcr: u32, | ||
/// Floating-point Status Register | ||
pub fpsr: u32, | ||
} | ||
|
||
impl Registers for AArch64CoreRegs { | ||
type ProgramCounter = u64; | ||
|
||
fn pc(&self) -> Self::ProgramCounter { | ||
self.pc | ||
} | ||
|
||
fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) { | ||
macro_rules! write_bytes { | ||
($var: expr) => { | ||
for b in $var.to_le_bytes() { | ||
write_byte(Some(b)) | ||
} | ||
}; | ||
} | ||
|
||
for reg in self.x.iter() { | ||
write_bytes!(reg); | ||
} | ||
write_bytes!(self.sp); | ||
write_bytes!(self.pc); | ||
write_bytes!(self.cpsr); | ||
for reg in self.v.iter() { | ||
write_bytes!(reg); | ||
} | ||
write_bytes!(self.fpcr); | ||
write_bytes!(self.fpsr); | ||
} | ||
|
||
fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { | ||
const CPSR_OFF: usize = core::mem::size_of::<u64>() * 33; | ||
const FPSIMD_OFF: usize = CPSR_OFF + core::mem::size_of::<u32>(); | ||
const FPCR_OFF: usize = FPSIMD_OFF + core::mem::size_of::<u128>() * 32; | ||
const END: usize = FPCR_OFF + core::mem::size_of::<u32>() * 2; | ||
|
||
if bytes.len() < END { | ||
return Err(()); | ||
} | ||
|
||
let mut regs = bytes[0..CPSR_OFF] | ||
.chunks_exact(core::mem::size_of::<u64>()) | ||
.map(|c| u64::from_le_bytes(c.try_into().unwrap())); | ||
|
||
for reg in self.x.iter_mut() { | ||
*reg = regs.next().ok_or(())? | ||
} | ||
self.sp = regs.next().ok_or(())?; | ||
self.pc = regs.next().ok_or(())?; | ||
|
||
let mut regs = bytes[CPSR_OFF..FPSIMD_OFF] | ||
.chunks_exact(core::mem::size_of::<u32>()) | ||
.map(|c| u32::from_le_bytes(c.try_into().unwrap())); | ||
|
||
self.cpsr = regs.next().ok_or(())?; | ||
|
||
let mut regs = bytes[FPSIMD_OFF..FPCR_OFF] | ||
.chunks_exact(core::mem::size_of::<u128>()) | ||
.map(|c| u128::from_le_bytes(c.try_into().unwrap())); | ||
|
||
for reg in self.v.iter_mut() { | ||
*reg = regs.next().ok_or(())? | ||
} | ||
|
||
let mut regs = bytes[FPCR_OFF..] | ||
.chunks_exact(core::mem::size_of::<u32>()) | ||
.map(|c| u32::from_le_bytes(c.try_into().unwrap())); | ||
|
||
self.fpcr = regs.next().ok_or(())?; | ||
self.fpsr = regs.next().ok_or(())?; | ||
|
||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.