Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gdbstub_arch: Add support for AArch64 #109

Merged
merged 2 commits into from Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
94 changes: 94 additions & 0 deletions gdbstub_arch/src/aarch64/core.xml
@@ -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>
160 changes: 160 additions & 0 deletions gdbstub_arch/src/aarch64/fpu.xml
@@ -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>
40 changes: 40 additions & 0 deletions gdbstub_arch/src/aarch64/mod.rs
@@ -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
}
}
99 changes: 99 additions & 0 deletions gdbstub_arch/src/aarch64/reg/aarch64_core.rs
@@ -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(())
}
}