1+ use std:: collections:: HashMap ;
12use std:: sync:: { Arc , Mutex } ;
23
34use crossbeam_channel:: TryRecvError ;
@@ -10,7 +11,7 @@ use gdbstub::target::ext::base::singlethread::{
1011} ;
1112use gdbstub:: target:: ext:: base:: BaseOps ;
1213use gdbstub:: target:: ext:: breakpoints:: {
13- Breakpoints , BreakpointsOps , HwBreakpoint , HwBreakpointOps ,
14+ Breakpoints , BreakpointsOps , HwBreakpoint , HwBreakpointOps , SwBreakpoint , SwBreakpointOps ,
1415} ;
1516use gdbstub:: target:: ext:: section_offsets:: { Offsets , SectionOffsets } ;
1617use gdbstub:: target:: { Target , TargetError , TargetResult } ;
@@ -19,7 +20,7 @@ use gdbstub_arch::x86::X86_64_SSE as GdbTargetArch;
1920use hyperlight_common:: mem:: PAGE_SIZE ;
2021use kvm_bindings:: {
2122 kvm_guest_debug, kvm_regs, KVM_GUESTDBG_ENABLE , KVM_GUESTDBG_SINGLESTEP ,
22- KVM_GUESTDBG_USE_HW_BP ,
23+ KVM_GUESTDBG_USE_HW_BP , KVM_GUESTDBG_USE_SW_BP ,
2324} ;
2425use kvm_ioctls:: VcpuFd ;
2526
@@ -29,6 +30,13 @@ use crate::mem::layout::SandboxMemoryLayout;
2930use crate :: mem:: mgr:: SandboxMemoryManager ;
3031use crate :: mem:: shared_mem:: { GuestSharedMemory , SharedMemory } ;
3132
33+ /// Software Breakpoint size in memory
34+ const SW_BP_SIZE : usize = 1 ;
35+ /// Software Breakpoinnt opcode
36+ const SW_BP_OP : u8 = 0xCC ;
37+ /// Software Breakpoint written to memory
38+ const SW_BP : [ u8 ; SW_BP_SIZE ] = [ SW_BP_OP ] ;
39+
3240/// KVM Debug struct
3341/// This struct is used to abstract the internal details of the kvm
3442/// guest debugging settings
@@ -42,7 +50,7 @@ impl KvmDebug {
4250
4351 pub fn new ( ) -> Self {
4452 let dbg = kvm_guest_debug {
45- control : KVM_GUESTDBG_ENABLE ,
53+ control : KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP ,
4654 ..Default :: default ( )
4755 } ;
4856
@@ -106,6 +114,8 @@ pub struct HyperlightKvmSandboxTarget {
106114
107115 /// Array of addresses for HW breakpoints
108116 hw_breakpoints : Vec < u64 > ,
117+ /// Array of addresses for SW breakpoints
118+ sw_breakpoints : HashMap < u64 , [ u8 ; SW_BP_SIZE ] > ,
109119
110120 /// Hypervisor communication channels
111121 hyp_conn : GdbConnection ,
@@ -130,6 +140,7 @@ impl HyperlightKvmSandboxTarget {
130140 single_step : false ,
131141
132142 hw_breakpoints : vec ! [ ] ,
143+ sw_breakpoints : HashMap :: new ( ) ,
133144
134145 hyp_conn,
135146 }
@@ -437,6 +448,9 @@ impl Breakpoints for HyperlightKvmSandboxTarget {
437448 fn support_hw_breakpoint ( & mut self ) -> Option < HwBreakpointOps < Self > > {
438449 Some ( self )
439450 }
451+ fn support_sw_breakpoint ( & mut self ) -> Option < SwBreakpointOps < ' _ , Self > > {
452+ Some ( self )
453+ }
440454}
441455
442456impl HwBreakpoint for HyperlightKvmSandboxTarget {
@@ -496,6 +510,55 @@ impl HwBreakpoint for HyperlightKvmSandboxTarget {
496510 }
497511}
498512
513+ impl SwBreakpoint for HyperlightKvmSandboxTarget {
514+ /// Adds a software breakpoint by setting a specific operation code at the
515+ /// address so when the vCPU hits it, it knows it is a software breakpoint.
516+ ///
517+ /// The existing data at the address is saved so it can be restored when
518+ /// removing the breakpoint
519+ fn add_sw_breakpoint (
520+ & mut self ,
521+ addr : <Self :: Arch as Arch >:: Usize ,
522+ _kind : <Self :: Arch as Arch >:: BreakpointKind ,
523+ ) -> TargetResult < bool , Self > {
524+ log:: debug!( "Add sw breakpoint at address {:X}" , addr) ;
525+ let addr = self . translate_gva ( addr) . map_err ( TargetError :: Fatal ) ?;
526+
527+ if self . sw_breakpoints . contains_key ( & addr) {
528+ return Ok ( true ) ;
529+ }
530+
531+ let mut save_data = [ 0u8 ; SW_BP_SIZE ] ;
532+ self . read_addrs ( addr, & mut save_data) ?;
533+ self . write_addrs ( addr, & SW_BP ) ?;
534+
535+ self . sw_breakpoints . insert ( addr, save_data) ;
536+
537+ Ok ( true )
538+ }
539+
540+ /// Removes a software breakpoint by restoring the saved data at the corresponding
541+ /// address
542+ fn remove_sw_breakpoint (
543+ & mut self ,
544+ addr : <Self :: Arch as Arch >:: Usize ,
545+ _kind : <Self :: Arch as Arch >:: BreakpointKind ,
546+ ) -> TargetResult < bool , Self > {
547+ log:: debug!( "Remove sw breakpoint at address {:X}" , addr) ;
548+
549+ let addr = self . translate_gva ( addr) . map_err ( TargetError :: Fatal ) ?;
550+
551+ if self . sw_breakpoints . contains_key ( & addr) {
552+ let save_data = self
553+ . sw_breakpoints
554+ . remove ( & addr)
555+ . expect ( "Expected the hashmap to contain the address" ) ;
556+ self . write_addrs ( addr, & save_data) ?;
557+
558+ Ok ( true )
559+ } else {
560+ Ok ( false )
561+ }
499562 }
500563}
501564
@@ -518,4 +581,4 @@ impl SingleThreadSingleStep for HyperlightKvmSandboxTarget {
518581 self . set_single_step ( true ) ?;
519582 self . resume_vcpu ( )
520583 }
521- }
584+ }
0 commit comments