@@ -1045,6 +1045,59 @@ impl VcpuFd {
1045
1045
Ok ( ( ) )
1046
1046
}
1047
1047
1048
+ /// Sets processor-specific debug registers and configures the vcpu for handling
1049
+ /// certain guest debug events using the `KVM_SET_GUEST_DEBUG` ioctl.
1050
+ ///
1051
+ /// # Arguments
1052
+ ///
1053
+ /// * `debug_struct` - control bitfields and debug registers, depending on the specific architecture.
1054
+ /// For details check the `kvm_guest_debug` structure in the
1055
+ /// [KVM API doc](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt).
1056
+ ///
1057
+ /// # Example
1058
+ ///
1059
+ /// ```rust
1060
+ /// # extern crate kvm_ioctls;
1061
+ /// # extern crate kvm_bindings;
1062
+ /// # use kvm_ioctls::Kvm;
1063
+ /// # use kvm_bindings::{
1064
+ /// # KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_USE_SW_BP, kvm_guest_debug_arch, kvm_guest_debug
1065
+ /// # };
1066
+ /// let kvm = Kvm::new().unwrap();
1067
+ /// let vm = kvm.create_vm().unwrap();
1068
+ /// let vcpu = vm.create_vcpu(0).unwrap();
1069
+ ///
1070
+ /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
1071
+ /// let debug_struct = kvm_guest_debug {
1072
+ /// // Configure the vcpu so that a KVM_DEBUG_EXIT would be generated
1073
+ /// // when encountering a software breakpoint during execution
1074
+ /// control: KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP,
1075
+ /// pad: 0,
1076
+ /// // Reset all x86-specific debug registers
1077
+ /// arch: kvm_guest_debug_arch {
1078
+ /// debugreg: [0, 0, 0, 0, 0, 0, 0, 0],
1079
+ /// },
1080
+ /// };
1081
+ ///
1082
+ /// vcpu.set_guest_debug(&debug_struct).unwrap();
1083
+ /// }
1084
+ /// ```
1085
+ ///
1086
+ #[ cfg( any(
1087
+ target_arch = "x86" ,
1088
+ target_arch = "x86_64" ,
1089
+ target_arch = "arm64" ,
1090
+ target_arch = "s390" ,
1091
+ target_arch = "ppc"
1092
+ ) ) ]
1093
+ pub fn set_guest_debug ( & self , debug_struct : & kvm_guest_debug ) -> Result < ( ) > {
1094
+ let ret = unsafe { ioctl_with_ref ( self , KVM_SET_GUEST_DEBUG ( ) , debug_struct) } ;
1095
+ if ret < 0 {
1096
+ return Err ( errno:: Error :: last ( ) ) ;
1097
+ }
1098
+ Ok ( ( ) )
1099
+ }
1100
+
1048
1101
/// Sets the value of one register for this vCPU.
1049
1102
///
1050
1103
/// The id of the register is encoded as specified in the kernel documentation
@@ -1732,6 +1785,7 @@ mod tests {
1732
1785
0xc6 , 0x06 , 0x00 , 0x20 , 0x00 , /* movl $0, (0x2000); Dirty one page in guest mem. */
1733
1786
0xf4 , /* hlt */
1734
1787
] ;
1788
+ let expected_rips: [ u64 ; 3 ] = [ 0x1003 , 0x1005 , 0x1007 ] ;
1735
1789
1736
1790
let mem_size = 0x4000 ;
1737
1791
let load_addr = mmap_anonymous ( mem_size) ;
@@ -1772,6 +1826,16 @@ mod tests {
1772
1826
vcpu_regs. rflags = 2 ;
1773
1827
vcpu_fd. set_regs ( & vcpu_regs) . unwrap ( ) ;
1774
1828
1829
+ let mut debug_struct = kvm_guest_debug {
1830
+ control : KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP ,
1831
+ pad : 0 ,
1832
+ arch : kvm_guest_debug_arch {
1833
+ debugreg : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
1834
+ } ,
1835
+ } ;
1836
+ vcpu_fd. set_guest_debug ( & debug_struct) . unwrap ( ) ;
1837
+
1838
+ let mut instr_idx = 0 ;
1775
1839
loop {
1776
1840
match vcpu_fd. run ( ) . expect ( "run failed" ) {
1777
1841
VcpuExit :: IoIn ( addr, data) => {
@@ -1792,6 +1856,20 @@ mod tests {
1792
1856
assert_eq ! ( data. len( ) , 1 ) ;
1793
1857
assert_eq ! ( data[ 0 ] , 0 ) ;
1794
1858
}
1859
+ VcpuExit :: Debug => {
1860
+ if instr_idx == expected_rips. len ( ) - 1 {
1861
+ // Disabling debugging/single-stepping
1862
+ debug_struct. control = 0 ;
1863
+ vcpu_fd. set_guest_debug ( & debug_struct) . unwrap ( ) ;
1864
+ } else {
1865
+ if instr_idx >= expected_rips. len ( ) {
1866
+ assert ! ( false ) ;
1867
+ }
1868
+ }
1869
+ let vcpu_regs = vcpu_fd. get_regs ( ) . unwrap ( ) ;
1870
+ assert_eq ! ( vcpu_regs. rip, expected_rips[ instr_idx] ) ;
1871
+ instr_idx += 1 ;
1872
+ }
1795
1873
VcpuExit :: Hlt => {
1796
1874
// The code snippet dirties 2 pages:
1797
1875
// * one when the code itself is loaded in memory;
0 commit comments