@@ -27,7 +27,6 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs;
27
27
use gdbstub_arch:: x86:: X86_64_SSE as GdbArch ;
28
28
#[ cfg( target_arch = "x86_64" ) ]
29
29
use gdbstub_arch:: x86:: reg:: X86_64CoreRegs as CoreRegs ;
30
- use kvm_ioctls:: VcpuFd ;
31
30
use vm_memory:: { Bytes , GuestAddress , GuestMemoryError } ;
32
31
33
32
use super :: arch;
@@ -39,38 +38,18 @@ use crate::utils::u64_to_usize;
39
38
use crate :: vstate:: vcpu:: VcpuSendEventError ;
40
39
use crate :: { FcExitCode , VcpuEvent , VcpuResponse , Vmm } ;
41
40
42
- #[ derive( Debug ) ]
41
+ #[ derive( Debug , Default , Clone , Copy ) ]
43
42
/// Stores the current state of a Vcpu with a copy of the Vcpu file descriptor
44
43
struct VcpuState {
45
44
single_step : bool ,
46
45
paused : bool ,
47
- vcpu_fd : VcpuFd ,
48
46
}
49
47
50
48
impl 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
-
60
49
/// Disables single stepping on the Vcpu state
61
50
fn reset_vcpu_state ( & mut self ) {
62
51
self . single_step = false ;
63
52
}
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
- }
74
53
}
75
54
76
55
/// Errors from interactions between GDB and the VMM
@@ -179,13 +158,8 @@ impl FirecrackerTarget {
179
158
/// Creates a new Target for GDB stub. This is used as the layer between GDB and the VMM it
180
159
/// will handle requests from GDB and perform the appropriate actions, while also updating GDB
181
160
/// 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( ) ] ;
189
163
// By default vcpu 1 will be paused at the entry point
190
164
vcpu_state[ 0 ] . paused = true ;
191
165
@@ -202,16 +176,37 @@ impl FirecrackerTarget {
202
176
}
203
177
}
204
178
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
+
205
202
/// Retrieves the currently paused Vcpu id returns an error if there is no currently paused Vcpu
206
203
fn get_paused_vcpu_id ( & self ) -> Result < Tid , GdbTargetError > {
207
204
self . paused_vcpu . ok_or ( GdbTargetError :: NoPausedVcpu )
208
205
}
209
206
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 ( ) ?) )
215
210
}
216
211
217
212
/// Updates state to reference the currently paused Vcpu and store that the cpu is currently
@@ -224,9 +219,9 @@ impl FirecrackerTarget {
224
219
/// Resumes execution of all paused Vcpus, update them with current kvm debug info
225
220
/// and resumes
226
221
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
+ }
230
225
231
226
for cpu_id in 0 ..self . vcpu_state . len ( ) {
232
227
let tid = vcpuid_to_tid ( cpu_id) ?;
@@ -263,7 +258,7 @@ impl FirecrackerTarget {
263
258
return Ok ( ( ) ) ;
264
259
}
265
260
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) ] ;
267
262
268
263
cpu_handle. send_event ( VcpuEvent :: Pause ) ?;
269
264
let _ = cpu_handle. response_receiver ( ) . recv ( ) ?;
@@ -274,8 +269,10 @@ impl FirecrackerTarget {
274
269
275
270
/// A helper function to allow the event loop to inject this breakpoint back into the Vcpu
276
271
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 )
279
276
}
280
277
281
278
/// Resumes the Vcpu, will return early if the Vcpu is already running
@@ -288,7 +285,7 @@ impl FirecrackerTarget {
288
285
return Ok ( ( ) ) ;
289
286
}
290
287
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) ] ;
292
289
cpu_handle. send_event ( VcpuEvent :: Resume ) ?;
293
290
294
291
let response = cpu_handle. response_receiver ( ) . recv ( ) ?;
@@ -307,21 +304,24 @@ impl FirecrackerTarget {
307
304
& self ,
308
305
tid : Tid ,
309
306
) -> 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] ;
311
309
if vcpu_state. single_step {
312
310
return Ok ( Some ( MultiThreadStopReason :: SignalWithThread {
313
311
tid,
314
312
signal : Signal :: SIGTRAP ,
315
313
} ) ) ;
316
314
}
317
315
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 {
319
319
// If we error here we return an arbitrary Software Breakpoint, GDB will handle
320
320
// this gracefully
321
321
return Ok ( Some ( MultiThreadStopReason :: SwBreak ( tid) ) ) ;
322
322
} ;
323
323
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) ?;
325
325
if self . sw_breakpoints . contains_key ( & gpa) {
326
326
return Ok ( Some ( MultiThreadStopReason :: SwBreak ( tid) ) ) ;
327
327
}
@@ -364,14 +364,20 @@ impl Target for FirecrackerTarget {
364
364
impl MultiThreadBase for FirecrackerTarget {
365
365
/// Reads the registers for the Vcpu
366
366
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) ?;
368
371
369
372
Ok ( ( ) )
370
373
}
371
374
372
375
/// Writes to the registers for the Vcpu
373
376
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) ?;
375
381
376
382
Ok ( ( ) )
377
383
}
@@ -384,12 +390,14 @@ impl MultiThreadBase for FirecrackerTarget {
384
390
tid : Tid ,
385
391
) -> TargetResult < usize , Self > {
386
392
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 ;
388
396
389
397
let vmm = & self . vmm . lock ( ) . expect ( "Error locking vmm in read addr" ) ;
390
398
391
399
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| {
393
401
error ! ( "Error {e:?} translating gva on read address: {gva:#X}" ) ;
394
402
} ) ?;
395
403
@@ -420,11 +428,12 @@ impl MultiThreadBase for FirecrackerTarget {
420
428
mut data : & [ u8 ] ,
421
429
tid : Tid ,
422
430
) -> 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 ;
425
434
426
435
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| {
428
437
error ! ( "Error {e:?} translating gva on read address: {gva:#X}" ) ;
429
438
} ) ?;
430
439
@@ -546,8 +555,8 @@ impl HwBreakpoint for FirecrackerTarget {
546
555
return Ok ( false ) ;
547
556
}
548
557
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 ) ?;
551
560
552
561
Ok ( true )
553
562
}
@@ -563,8 +572,8 @@ impl HwBreakpoint for FirecrackerTarget {
563
572
Some ( pos) => self . hw_breakpoints . remove ( pos) ,
564
573
} ;
565
574
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 ) ?;
568
577
569
578
Ok ( true )
570
579
}
@@ -580,11 +589,8 @@ impl SwBreakpoint for FirecrackerTarget {
580
589
addr : <Self :: Arch as Arch >:: Usize ,
581
590
_kind : <Self :: Arch as Arch >:: BreakpointKind ,
582
591
) -> 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) ?;
588
594
589
595
if self . sw_breakpoints . contains_key ( & gpa) {
590
596
return Ok ( true ) ;
@@ -608,11 +614,8 @@ impl SwBreakpoint for FirecrackerTarget {
608
614
addr : <Self :: Arch as Arch >:: Usize ,
609
615
_kind : <Self :: Arch as Arch >:: BreakpointKind ,
610
616
) -> 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) ?;
616
619
617
620
if let Some ( removed) = self . sw_breakpoints . remove ( & gpa) {
618
621
self . write_addrs ( addr, & removed, self . get_paused_vcpu_id ( ) ?) ?;
0 commit comments