@@ -27,7 +27,6 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs;
2727use gdbstub_arch:: x86:: X86_64_SSE as GdbArch ;
2828#[ cfg( target_arch = "x86_64" ) ]
2929use gdbstub_arch:: x86:: reg:: X86_64CoreRegs as CoreRegs ;
30- use kvm_ioctls:: VcpuFd ;
3130use vm_memory:: { Bytes , GuestAddress , GuestMemoryError } ;
3231
3332use super :: arch;
@@ -39,38 +38,18 @@ use crate::utils::u64_to_usize;
3938use crate :: vstate:: vcpu:: VcpuSendEventError ;
4039use crate :: { FcExitCode , VcpuEvent , VcpuResponse , Vmm } ;
4140
42- #[ derive( Debug ) ]
41+ #[ derive( Debug , Default , Clone , Copy ) ]
4342/// Stores the current state of a Vcpu with a copy of the Vcpu file descriptor
4443struct VcpuState {
4544 single_step : bool ,
4645 paused : bool ,
47- vcpu_fd : VcpuFd ,
4846}
4947
5048impl VcpuState {
51- /// Constructs a new instance of a VcpuState from a VcpuFd
52- fn from_vcpu_fd ( vcpu_fd : VcpuFd ) -> Self {
53- Self {
54- single_step : false ,
55- paused : false ,
56- vcpu_fd,
57- }
58- }
59-
6049 /// Disables single stepping on the Vcpu state
6150 fn reset_vcpu_state ( & mut self ) {
6251 self . single_step = false ;
6352 }
64-
65- /// Updates the kvm debug flags set against the Vcpu with a check
66- fn update_kvm_debug ( & self , hw_breakpoints : & [ GuestAddress ] ) -> Result < ( ) , GdbTargetError > {
67- if !self . paused {
68- info ! ( "Attempted to update kvm debug on a non paused Vcpu" ) ;
69- return Ok ( ( ) ) ;
70- }
71-
72- arch:: vcpu_set_debug ( & self . vcpu_fd , hw_breakpoints, self . single_step )
73- }
7453}
7554
7655/// Errors from interactions between GDB and the VMM
@@ -179,13 +158,8 @@ impl FirecrackerTarget {
179158 /// Creates a new Target for GDB stub. This is used as the layer between GDB and the VMM it
180159 /// will handle requests from GDB and perform the appropriate actions, while also updating GDB
181160 /// with the state of the VMM / Vcpu's as we hit debug events
182- pub fn new (
183- vmm : Arc < Mutex < Vmm > > ,
184- vcpu_fds : Vec < VcpuFd > ,
185- gdb_event : Receiver < usize > ,
186- entry_addr : GuestAddress ,
187- ) -> Self {
188- let mut vcpu_state: Vec < _ > = vcpu_fds. into_iter ( ) . map ( VcpuState :: from_vcpu_fd) . collect ( ) ;
161+ pub fn new ( vmm : Arc < Mutex < Vmm > > , gdb_event : Receiver < usize > , entry_addr : GuestAddress ) -> Self {
162+ let mut vcpu_state = vec ! [ VcpuState :: default ( ) ; vmm. lock( ) . unwrap( ) . vcpus_handles. len( ) ] ;
189163 // By default vcpu 1 will be paused at the entry point
190164 vcpu_state[ 0 ] . paused = true ;
191165
@@ -202,16 +176,37 @@ impl FirecrackerTarget {
202176 }
203177 }
204178
179+ // Update KVM debug info for a specific vcpu index.
180+ fn update_vcpu_kvm_debug (
181+ & self ,
182+ vcpu_idx : usize ,
183+ hw_breakpoints : & [ GuestAddress ] ,
184+ ) -> Result < ( ) , GdbTargetError > {
185+ let state = & self . vcpu_state [ vcpu_idx] ;
186+ if !state. paused {
187+ info ! ( "Attempted to update kvm debug on a non paused Vcpu" ) ;
188+ return Ok ( ( ) ) ;
189+ }
190+
191+ let vcpu_fd = & self . vmm . lock ( ) . unwrap ( ) . vcpus_handles [ vcpu_idx] . vcpu_fd ;
192+ arch:: vcpu_set_debug ( vcpu_fd, hw_breakpoints, state. single_step )
193+ }
194+
195+ /// Translate guest virtual address to guest pysical address.
196+ fn translate_gva ( & self , vcpu_idx : usize , addr : u64 ) -> Result < u64 , GdbTargetError > {
197+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
198+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
199+ arch:: translate_gva ( vcpu_fd, addr, & vmm)
200+ }
201+
205202 /// Retrieves the currently paused Vcpu id returns an error if there is no currently paused Vcpu
206203 fn get_paused_vcpu_id ( & self ) -> Result < Tid , GdbTargetError > {
207204 self . paused_vcpu . ok_or ( GdbTargetError :: NoPausedVcpu )
208205 }
209206
210- /// Retrieves the currently paused Vcpu state returns an error if there is no currently paused
211- /// Vcpu
212- fn get_paused_vcpu ( & self ) -> Result < & VcpuState , GdbTargetError > {
213- let vcpu_index = tid_to_vcpuid ( self . get_paused_vcpu_id ( ) ?) ;
214- Ok ( & self . vcpu_state [ vcpu_index] )
207+ /// Returns the index of the paused vcpu.
208+ fn get_paused_vcpu_idx ( & self ) -> Result < usize , GdbTargetError > {
209+ Ok ( tid_to_vcpuid ( self . get_paused_vcpu_id ( ) ?) )
215210 }
216211
217212 /// Updates state to reference the currently paused Vcpu and store that the cpu is currently
@@ -224,9 +219,9 @@ impl FirecrackerTarget {
224219 /// Resumes execution of all paused Vcpus, update them with current kvm debug info
225220 /// and resumes
226221 fn resume_all_vcpus ( & mut self ) -> Result < ( ) , GdbTargetError > {
227- self . vcpu_state
228- . iter ( )
229- . try_for_each ( |state| state . update_kvm_debug ( & self . hw_breakpoints ) ) ? ;
222+ for idx in 0 .. self . vcpu_state . len ( ) {
223+ self . update_vcpu_kvm_debug ( idx , & self . hw_breakpoints ) ? ;
224+ }
230225
231226 for cpu_id in 0 ..self . vcpu_state . len ( ) {
232227 let tid = vcpuid_to_tid ( cpu_id) ?;
@@ -263,7 +258,7 @@ impl FirecrackerTarget {
263258 return Ok ( ( ) ) ;
264259 }
265260
266- let cpu_handle = & self . vmm . lock ( ) ?. vcpus_handles [ tid_to_vcpuid ( tid) ] ;
261+ let cpu_handle = & mut self . vmm . lock ( ) ?. vcpus_handles [ tid_to_vcpuid ( tid) ] ;
267262
268263 cpu_handle. send_event ( VcpuEvent :: Pause ) ?;
269264 let _ = cpu_handle. response_receiver ( ) . recv ( ) ?;
@@ -274,8 +269,10 @@ impl FirecrackerTarget {
274269
275270 /// A helper function to allow the event loop to inject this breakpoint back into the Vcpu
276271 pub fn inject_bp_to_guest ( & mut self , tid : Tid ) -> Result < ( ) , GdbTargetError > {
277- let vcpu_state = & mut self . vcpu_state [ tid_to_vcpuid ( tid) ] ;
278- arch:: vcpu_inject_bp ( & vcpu_state. vcpu_fd , & self . hw_breakpoints , false )
272+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
273+ let vcpu_idx = tid_to_vcpuid ( tid) ;
274+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
275+ arch:: vcpu_inject_bp ( vcpu_fd, & self . hw_breakpoints , false )
279276 }
280277
281278 /// Resumes the Vcpu, will return early if the Vcpu is already running
@@ -288,7 +285,7 @@ impl FirecrackerTarget {
288285 return Ok ( ( ) ) ;
289286 }
290287
291- let cpu_handle = & self . vmm . lock ( ) ?. vcpus_handles [ tid_to_vcpuid ( tid) ] ;
288+ let cpu_handle = & mut self . vmm . lock ( ) ?. vcpus_handles [ tid_to_vcpuid ( tid) ] ;
292289 cpu_handle. send_event ( VcpuEvent :: Resume ) ?;
293290
294291 let response = cpu_handle. response_receiver ( ) . recv ( ) ?;
@@ -307,21 +304,24 @@ impl FirecrackerTarget {
307304 & self ,
308305 tid : Tid ,
309306 ) -> Result < Option < BaseStopReason < Tid , u64 > > , GdbTargetError > {
310- let vcpu_state = & self . vcpu_state [ tid_to_vcpuid ( tid) ] ;
307+ let vcpu_idx = tid_to_vcpuid ( tid) ;
308+ let vcpu_state = & self . vcpu_state [ vcpu_idx] ;
311309 if vcpu_state. single_step {
312310 return Ok ( Some ( MultiThreadStopReason :: SignalWithThread {
313311 tid,
314312 signal : Signal :: SIGTRAP ,
315313 } ) ) ;
316314 }
317315
318- let Ok ( ip) = arch:: get_instruction_pointer ( & vcpu_state. vcpu_fd ) else {
316+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
317+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
318+ let Ok ( ip) = arch:: get_instruction_pointer ( vcpu_fd) else {
319319 // If we error here we return an arbitrary Software Breakpoint, GDB will handle
320320 // this gracefully
321321 return Ok ( Some ( MultiThreadStopReason :: SwBreak ( tid) ) ) ;
322322 } ;
323323
324- let gpa = arch:: translate_gva ( & vcpu_state . vcpu_fd , ip, & self . vmm . lock ( ) . unwrap ( ) ) ?;
324+ let gpa = arch:: translate_gva ( vcpu_fd, ip, & vmm) ?;
325325 if self . sw_breakpoints . contains_key ( & gpa) {
326326 return Ok ( Some ( MultiThreadStopReason :: SwBreak ( tid) ) ) ;
327327 }
@@ -364,14 +364,20 @@ impl Target for FirecrackerTarget {
364364impl MultiThreadBase for FirecrackerTarget {
365365 /// Reads the registers for the Vcpu
366366 fn read_registers ( & mut self , regs : & mut CoreRegs , tid : Tid ) -> TargetResult < ( ) , Self > {
367- arch:: read_registers ( & self . vcpu_state [ tid_to_vcpuid ( tid) ] . vcpu_fd , regs) ?;
367+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
368+ let vcpu_idx = tid_to_vcpuid ( tid) ;
369+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
370+ arch:: read_registers ( vcpu_fd, regs) ?;
368371
369372 Ok ( ( ) )
370373 }
371374
372375 /// Writes to the registers for the Vcpu
373376 fn write_registers ( & mut self , regs : & CoreRegs , tid : Tid ) -> TargetResult < ( ) , Self > {
374- arch:: write_registers ( & self . vcpu_state [ tid_to_vcpuid ( tid) ] . vcpu_fd , regs) ?;
377+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
378+ let vcpu_idx = tid_to_vcpuid ( tid) ;
379+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
380+ arch:: write_registers ( vcpu_fd, regs) ?;
375381
376382 Ok ( ( ) )
377383 }
@@ -384,12 +390,14 @@ impl MultiThreadBase for FirecrackerTarget {
384390 tid : Tid ,
385391 ) -> TargetResult < usize , Self > {
386392 let data_len = data. len ( ) ;
387- let vcpu_state = & self . vcpu_state [ tid_to_vcpuid ( tid) ] ;
393+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
394+ let vcpu_idx = tid_to_vcpuid ( tid) ;
395+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
388396
389397 let vmm = & self . vmm . lock ( ) . expect ( "Error locking vmm in read addr" ) ;
390398
391399 while !data. is_empty ( ) {
392- let gpa = arch:: translate_gva ( & vcpu_state . vcpu_fd , gva, & vmm) . map_err ( |e| {
400+ let gpa = arch:: translate_gva ( vcpu_fd, gva, & vmm) . map_err ( |e| {
393401 error ! ( "Error {e:?} translating gva on read address: {gva:#X}" ) ;
394402 } ) ?;
395403
@@ -420,11 +428,12 @@ impl MultiThreadBase for FirecrackerTarget {
420428 mut data : & [ u8 ] ,
421429 tid : Tid ,
422430 ) -> TargetResult < ( ) , Self > {
423- let vcpu_state = & self . vcpu_state [ tid_to_vcpuid ( tid) ] ;
424- let vmm = & self . vmm . lock ( ) . expect ( "Error locking vmm in write addr" ) ;
431+ let vmm = self . vmm . lock ( ) . unwrap ( ) ;
432+ let vcpu_idx = tid_to_vcpuid ( tid) ;
433+ let vcpu_fd = & vmm. vcpus_handles [ vcpu_idx] . vcpu_fd ;
425434
426435 while !data. is_empty ( ) {
427- let gpa = arch:: translate_gva ( & vcpu_state . vcpu_fd , gva, & vmm) . map_err ( |e| {
436+ let gpa = arch:: translate_gva ( vcpu_fd, gva, & vmm) . map_err ( |e| {
428437 error ! ( "Error {e:?} translating gva on read address: {gva:#X}" ) ;
429438 } ) ?;
430439
@@ -546,8 +555,8 @@ impl HwBreakpoint for FirecrackerTarget {
546555 return Ok ( false ) ;
547556 }
548557
549- let state = self . get_paused_vcpu ( ) ?;
550- state . update_kvm_debug ( & self . hw_breakpoints ) ?;
558+ let vcpu_idx = self . get_paused_vcpu_idx ( ) ?;
559+ self . update_vcpu_kvm_debug ( vcpu_idx , & self . hw_breakpoints ) ?;
551560
552561 Ok ( true )
553562 }
@@ -563,8 +572,8 @@ impl HwBreakpoint for FirecrackerTarget {
563572 Some ( pos) => self . hw_breakpoints . remove ( pos) ,
564573 } ;
565574
566- let state = self . get_paused_vcpu ( ) ?;
567- state . update_kvm_debug ( & self . hw_breakpoints ) ?;
575+ let vcpu_idx = self . get_paused_vcpu_idx ( ) ?;
576+ self . update_vcpu_kvm_debug ( vcpu_idx , & self . hw_breakpoints ) ?;
568577
569578 Ok ( true )
570579 }
@@ -580,11 +589,8 @@ impl SwBreakpoint for FirecrackerTarget {
580589 addr : <Self :: Arch as Arch >:: Usize ,
581590 _kind : <Self :: Arch as Arch >:: BreakpointKind ,
582591 ) -> TargetResult < bool , Self > {
583- let gpa = arch:: translate_gva (
584- & self . get_paused_vcpu ( ) ?. vcpu_fd ,
585- addr,
586- & self . vmm . lock ( ) . unwrap ( ) ,
587- ) ?;
592+ let vcpu_idx = self . get_paused_vcpu_idx ( ) ?;
593+ let gpa = self . translate_gva ( vcpu_idx, addr) ?;
588594
589595 if self . sw_breakpoints . contains_key ( & gpa) {
590596 return Ok ( true ) ;
@@ -608,11 +614,8 @@ impl SwBreakpoint for FirecrackerTarget {
608614 addr : <Self :: Arch as Arch >:: Usize ,
609615 _kind : <Self :: Arch as Arch >:: BreakpointKind ,
610616 ) -> TargetResult < bool , Self > {
611- let gpa = arch:: translate_gva (
612- & self . get_paused_vcpu ( ) ?. vcpu_fd ,
613- addr,
614- & self . vmm . lock ( ) . unwrap ( ) ,
615- ) ?;
617+ let vcpu_idx = self . get_paused_vcpu_idx ( ) ?;
618+ let gpa = self . translate_gva ( vcpu_idx, addr) ?;
616619
617620 if let Some ( removed) = self . sw_breakpoints . remove ( & gpa) {
618621 self . write_addrs ( addr, & removed, self . get_paused_vcpu_id ( ) ?) ?;
0 commit comments