Skip to content

Commit a4bb6dd

Browse files
committed
add sw breakpoint support
Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent b175f41 commit a4bb6dd

File tree

3 files changed

+139
-2
lines changed

3 files changed

+139
-2
lines changed

src/hyperlight_host/src/hypervisor/gdb/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,31 @@ pub enum VcpuStopReason {
8484
/// Enumerates the possible actions that a debugger can ask from a Hypervisor
8585
pub enum DebugMsg {
8686
AddHwBreakpoint(u64),
87+
AddSwBreakpoint(u64),
8788
Continue,
8889
DisableDebug,
8990
GetCodeSectionOffset,
9091
ReadAddr(u64, usize),
9192
ReadRegisters,
9293
RemoveHwBreakpoint(u64),
94+
RemoveSwBreakpoint(u64),
9395
Step,
9496
WriteAddr(u64, Vec<u8>),
9597
WriteRegisters(X86_64Regs),
9698
}
9799

98100
#[derive(Debug)]
99-
/// Enumerates the possible responses that a hypervisor can provide to a debugger
101+
/// Enumerates the possible responses that a hypervisor can provide to a debugger
100102
pub enum DebugResponse {
101103
AddHwBreakpoint(bool),
104+
AddSwBreakpoint(bool),
102105
Continue,
103106
DisableDebug,
104107
GetCodeSectionOffset(u64),
105108
ReadAddr(Vec<u8>),
106109
ReadRegisters(X86_64Regs),
107110
RemoveHwBreakpoint(bool),
111+
RemoveSwBreakpoint(bool),
108112
Step,
109113
VcpuStopped(VcpuStopReason),
110114
WriteAddr,

src/hyperlight_host/src/hypervisor/gdb/x86_64_target.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use gdbstub::target::ext::base::singlethread::{
77
};
88
use gdbstub::target::ext::base::BaseOps;
99
use gdbstub::target::ext::breakpoints::{
10-
Breakpoints, BreakpointsOps, HwBreakpoint, HwBreakpointOps,
10+
Breakpoints, BreakpointsOps, HwBreakpoint, HwBreakpointOps, SwBreakpoint, SwBreakpointOps,
1111
};
1212
use gdbstub::target::ext::section_offsets::{Offsets, SectionOffsets};
1313
use gdbstub::target::{Target, TargetError, TargetResult};
@@ -83,6 +83,11 @@ impl Target for HyperlightSandboxTarget {
8383
type Arch = GdbTargetArch;
8484
type Error = GdbTargetError;
8585

86+
#[inline(always)]
87+
fn guard_rail_implicit_sw_breakpoints(&self) -> bool {
88+
true
89+
}
90+
8691
fn support_breakpoints(&mut self) -> Option<BreakpointsOps<Self>> {
8792
Some(self)
8893
}
@@ -215,6 +220,7 @@ impl SingleThreadBase for HyperlightSandboxTarget {
215220
Some(self)
216221
}
217222
}
223+
218224
impl SectionOffsets for HyperlightSandboxTarget {
219225
fn get_section_offsets(&mut self) -> Result<Offsets<<Self::Arch as Arch>::Usize>, Self::Error> {
220226
log::debug!("Get section offsets");
@@ -236,6 +242,9 @@ impl Breakpoints for HyperlightSandboxTarget {
236242
fn support_hw_breakpoint(&mut self) -> Option<HwBreakpointOps<Self>> {
237243
Some(self)
238244
}
245+
fn support_sw_breakpoint(&mut self) -> Option<SwBreakpointOps<'_, Self>> {
246+
Some(self)
247+
}
239248
}
240249

241250
impl HwBreakpoint for HyperlightSandboxTarget {
@@ -272,6 +281,40 @@ impl HwBreakpoint for HyperlightSandboxTarget {
272281
}
273282
}
274283

284+
impl SwBreakpoint for HyperlightSandboxTarget {
285+
fn add_sw_breakpoint(
286+
&mut self,
287+
addr: <Self::Arch as Arch>::Usize,
288+
_kind: <Self::Arch as Arch>::BreakpointKind,
289+
) -> TargetResult<bool, Self> {
290+
log::debug!("Add sw breakpoint at address {:X}", addr);
291+
292+
match self.send_command(DebugMsg::AddSwBreakpoint(addr))? {
293+
DebugResponse::AddSwBreakpoint(rsp) => Ok(rsp),
294+
msg => {
295+
log::error!("Unexpected message received: {:?}", msg);
296+
Err(TargetError::Fatal(GdbTargetError::UnexpectedMessage))
297+
}
298+
}
299+
}
300+
301+
fn remove_sw_breakpoint(
302+
&mut self,
303+
addr: <Self::Arch as Arch>::Usize,
304+
_kind: <Self::Arch as Arch>::BreakpointKind,
305+
) -> TargetResult<bool, Self> {
306+
log::debug!("Remove sw breakpoint at address {:X}", addr);
307+
308+
match self.send_command(DebugMsg::RemoveSwBreakpoint(addr))? {
309+
DebugResponse::RemoveSwBreakpoint(rsp) => Ok(rsp),
310+
msg => {
311+
log::error!("Unexpected message received: {:?}", msg);
312+
Err(TargetError::Fatal(GdbTargetError::UnexpectedMessage))
313+
}
314+
}
315+
}
316+
}
317+
275318
impl SingleThreadResume for HyperlightSandboxTarget {
276319
fn resume(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> {
277320
log::debug!("Resume");

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub(crate) fn is_hypervisor_present() -> bool {
6565

6666
#[cfg(gdb)]
6767
mod debug {
68+
use std::collections::HashMap;
6869
use std::sync::{Arc, Mutex};
6970

7071
use hyperlight_common::mem::PAGE_SIZE;
@@ -80,6 +81,13 @@ mod debug {
8081
use crate::mem::layout::SandboxMemoryLayout;
8182
use crate::{new_error, Result};
8283

84+
/// Software Breakpoint size in memory
85+
pub const SW_BP_SIZE: usize = 1;
86+
/// Software Breakpoinnt opcode
87+
const SW_BP_OP: u8 = 0xCC;
88+
/// Software Breakpoint written to memory
89+
pub const SW_BP: [u8; SW_BP_SIZE] = [SW_BP_OP];
90+
8391
/// KVM Debug struct
8492
/// This struct is used to abstract the internal details of the kvm
8593
/// guest debugging settings
@@ -90,6 +98,8 @@ mod debug {
9098

9199
/// Array of addresses for HW breakpoints
92100
hw_breakpoints: Vec<u64>,
101+
/// Saves the bytes modified to enable sw breakpoints
102+
sw_breakpoints: HashMap<u64, [u8; SW_BP_SIZE]>,
93103

94104
/// Sent to KVM for enabling guest debug
95105
pub dbg_cfg: kvm_guest_debug,
@@ -107,6 +117,7 @@ mod debug {
107117
Self {
108118
single_step: false,
109119
hw_breakpoints: vec![],
120+
sw_breakpoints: HashMap::new(),
110121
dbg_cfg: dbg,
111122
}
112123
}
@@ -380,6 +391,69 @@ mod debug {
380391
}
381392
}
382393

394+
pub fn add_sw_breakpoint(
395+
&mut self,
396+
addr: u64,
397+
dbg_mem_access_fn: Arc<Mutex<dyn DbgMemAccessHandlerCaller>>,
398+
) -> Result<bool> {
399+
let addr = {
400+
let debug = self
401+
.debug
402+
.as_ref()
403+
.ok_or_else(|| new_error!("Debug is not enabled"))?;
404+
let addr = self.translate_gva(addr)?;
405+
if debug.sw_breakpoints.contains_key(&addr) {
406+
return Ok(true);
407+
}
408+
409+
addr
410+
};
411+
412+
let mut save_data = [0; SW_BP_SIZE];
413+
self.read_addrs(addr, &mut save_data[..], dbg_mem_access_fn.clone())?;
414+
self.write_addrs(addr, &SW_BP, dbg_mem_access_fn.clone())?;
415+
416+
{
417+
let debug = self
418+
.debug
419+
.as_mut()
420+
.ok_or_else(|| new_error!("Debug is not enabled"))?;
421+
debug.sw_breakpoints.insert(addr, save_data);
422+
}
423+
424+
Ok(true)
425+
}
426+
427+
pub fn remove_sw_breakpoint(
428+
&mut self,
429+
addr: u64,
430+
dbg_mem_access_fn: Arc<Mutex<dyn DbgMemAccessHandlerCaller>>,
431+
) -> Result<bool> {
432+
let (ret, data) = {
433+
let addr = self.translate_gva(addr)?;
434+
let debug = self
435+
.debug
436+
.as_mut()
437+
.ok_or_else(|| new_error!("Debug is not enabled"))?;
438+
439+
if debug.sw_breakpoints.contains_key(&addr) {
440+
let save_data = debug
441+
.sw_breakpoints
442+
.remove(&addr)
443+
.expect("Expected the hashmap to contain the address");
444+
445+
(true, Some(save_data))
446+
} else {
447+
(false, None)
448+
}
449+
};
450+
451+
if ret {
452+
self.write_addrs(addr, &data.unwrap(), dbg_mem_access_fn.clone())?;
453+
}
454+
455+
Ok(ret)
456+
}
383457

384458
/// Get the reason the vCPU has stopped
385459
pub fn get_stop_reason(&self) -> Result<VcpuStopReason> {
@@ -394,6 +468,9 @@ mod debug {
394468

395469
let ip = self.get_instruction_pointer()?;
396470
let gpa = self.translate_gva(ip)?;
471+
if debug.sw_breakpoints.contains_key(&gpa) {
472+
return Ok(VcpuStopReason::SwBp);
473+
}
397474

398475
if debug.hw_breakpoints.contains(&gpa) {
399476
return Ok(VcpuStopReason::HwBp);
@@ -418,6 +495,13 @@ mod debug {
418495
.expect("Add hw breakpoint error");
419496
Ok(DebugResponse::AddHwBreakpoint(res))
420497
}
498+
DebugMsg::AddSwBreakpoint(addr) => {
499+
let res = self
500+
.add_sw_breakpoint(addr, dbg_mem_access_fn.clone())
501+
.expect("Add sw breakpoint error");
502+
503+
Ok(DebugResponse::AddSwBreakpoint(res))
504+
}
421505
DebugMsg::Continue => {
422506
self.set_single_step(false)?;
423507
Ok(DebugResponse::Continue)
@@ -454,6 +538,12 @@ mod debug {
454538
.expect("Remove hw breakpoint error");
455539
Ok(DebugResponse::RemoveHwBreakpoint(res))
456540
}
541+
DebugMsg::RemoveSwBreakpoint(addr) => {
542+
let res = self
543+
.remove_sw_breakpoint(addr, dbg_mem_access_fn.clone())
544+
.expect("Remove sw breakpoint error");
545+
Ok(DebugResponse::RemoveSwBreakpoint(res))
546+
}
457547
DebugMsg::Step => {
458548
self.set_single_step(true)?;
459549
Ok(DebugResponse::Step)

0 commit comments

Comments
 (0)