debug_worker/gdb/targets/
mod.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::VmProxy;
5use gdbstub::target::Target;
6use gdbstub::target::TargetError;
7use gdbstub::target::ext::target_description_xml_override::TargetDescriptionXmlOverrideOps;
8use std::marker::PhantomData;
9use std::ops::Deref;
10use std::ops::DerefMut;
11use vmm_core_defs::debug_rpc::DebuggerVpState;
12
13mod base;
14mod breakpoints;
15mod target_aarch64;
16mod target_i8086;
17mod target_x86_64_qemu;
18
19pub trait ToTargetResult<T, E> {
20    fn fatal(self) -> Result<T, TargetError<E>>;
21    fn nonfatal(self) -> Result<T, TargetError<E>>;
22}
23
24impl<T, E> ToTargetResult<T, anyhow::Error> for Result<T, E>
25where
26    E: Into<anyhow::Error>,
27{
28    fn fatal(self) -> Result<T, TargetError<anyhow::Error>> {
29        self.map_err(|err| {
30            let err: anyhow::Error = err.into();
31            tracing::error!(
32                error = err.as_ref() as &dyn std::error::Error,
33                "gdb fatal error"
34            );
35            TargetError::Fatal(err)
36        })
37    }
38
39    fn nonfatal(self) -> Result<T, TargetError<anyhow::Error>> {
40        self.map_err(|err| {
41            let err = err.into();
42            tracing::warn!(
43                error = err.as_ref() as &dyn std::error::Error,
44                "gdb nonfatal error"
45            );
46            TargetError::Io(std::io::Error::other(err))
47        })
48    }
49}
50
51pub struct ArchError;
52
53impl<E> From<ArchError> for TargetError<E> {
54    fn from(_: ArchError) -> Self {
55        TargetError::NonFatal
56    }
57}
58
59/// Architecture-specific handling.
60pub trait TargetArch:
61    gdbstub::arch::Arch<Usize = Self::Address, BreakpointKind = usize> + Sized
62{
63    type Address: Copy + Into<u64> + TryFrom<u64>;
64
65    /// Extract a single register.
66    fn register(
67        state: &DebuggerVpState,
68        reg_id: Self::RegId,
69        buf: &mut [u8],
70    ) -> Result<usize, ArchError>;
71
72    /// Extract the register file.
73    fn registers(state: &DebuggerVpState, regs: &mut Self::Registers) -> Result<(), ArchError>;
74
75    /// Update the register state from the register file.
76    ///
77    /// Returns false
78    fn update_registers(
79        state: &mut DebuggerVpState,
80        regs: &Self::Registers,
81    ) -> Result<(), ArchError>;
82
83    /// Update a single register.
84    fn update_register(
85        state: &mut DebuggerVpState,
86        reg_id: Self::RegId,
87        val: &[u8],
88    ) -> Result<(), ArchError>;
89
90    /// Get the target description XML override implementation.
91    fn support_target_description_xml_override<'a, 'b>(
92        target: &'a mut VmTarget<'b, Self>,
93    ) -> Option<TargetDescriptionXmlOverrideOps<'a, VmTarget<'b, Self>>> {
94        let _ = target;
95        None
96    }
97}
98
99/// A [`VmProxy`] associated with a specific architecture `T`.
100pub struct VmTarget<'a, T>(&'a mut VmProxy, PhantomData<T>);
101
102impl<'a, T: TargetArch> VmTarget<'a, T> {
103    pub fn new(vm_proxy: &'a mut VmProxy) -> Self {
104        Self(vm_proxy, PhantomData)
105    }
106}
107
108impl<T> Deref for VmTarget<'_, T> {
109    type Target = VmProxy;
110
111    fn deref(&self) -> &Self::Target {
112        self.0
113    }
114}
115
116impl<T> DerefMut for VmTarget<'_, T> {
117    fn deref_mut(&mut self) -> &mut Self::Target {
118        self.0
119    }
120}
121
122impl<T: TargetArch> Target for VmTarget<'_, T> {
123    type Arch = T;
124    type Error = anyhow::Error;
125
126    // ExdiGdbSrv doesn't currently support RLE
127    fn use_rle(&self) -> bool {
128        false
129    }
130
131    #[inline(always)]
132    fn base_ops(&mut self) -> gdbstub::target::ext::base::BaseOps<'_, Self::Arch, Self::Error> {
133        gdbstub::target::ext::base::BaseOps::MultiThread(self)
134    }
135
136    #[inline(always)]
137    fn support_target_description_xml_override(
138        &mut self,
139    ) -> Option<TargetDescriptionXmlOverrideOps<'_, Self>> {
140        T::support_target_description_xml_override(self)
141    }
142
143    #[inline(always)]
144    fn support_breakpoints(
145        &mut self,
146    ) -> Option<gdbstub::target::ext::breakpoints::BreakpointsOps<'_, Self>> {
147        Some(self)
148    }
149
150    // We can rely on the GDB client overwrite the guest instruction stream when setting
151    // software breakpoints. No need to reimplement that logic inside our stub.
152    // NOTE: (8/20/2024) WinDbg's GDB client does not support this mode, and sents explicit sw breakpoint requests to the stub
153    // NOTE: (8/20/2024) Does not work correctly when the paravisor is hosting the gdbstub (software breakpoints are not being trapped into VTL2)
154    fn guard_rail_implicit_sw_breakpoints(&self) -> bool {
155        true
156    }
157}