7
7
use std:: convert:: TryFrom ;
8
8
use std:: fmt:: Debug ;
9
9
use std:: io:: { self , Seek , SeekFrom } ;
10
+ #[ cfg( feature = "gdb" ) ]
11
+ use std:: sync:: mpsc;
10
12
use std:: sync:: { Arc , Mutex } ;
11
13
12
14
use event_manager:: { MutEventSubscriber , SubscriberOps } ;
@@ -26,6 +28,9 @@ use vm_superio::Rtc;
26
28
use vm_superio:: Serial ;
27
29
use vmm_sys_util:: eventfd:: EventFd ;
28
30
31
+ #[ cfg( all( feature = "gdb" , target_arch = "aarch64" ) ) ]
32
+ compile_error ! ( "GDB feature not supported on ARM" ) ;
33
+
29
34
#[ cfg( target_arch = "x86_64" ) ]
30
35
use crate :: acpi;
31
36
use crate :: arch:: InitrdConfig ;
@@ -56,6 +61,8 @@ use crate::devices::virtio::net::Net;
56
61
use crate :: devices:: virtio:: rng:: Entropy ;
57
62
use crate :: devices:: virtio:: vsock:: { Vsock , VsockUnixBackend } ;
58
63
use crate :: devices:: BusDevice ;
64
+ #[ cfg( feature = "gdb" ) ]
65
+ use crate :: gdb;
59
66
use crate :: logger:: { debug, error} ;
60
67
use crate :: persist:: { MicrovmState , MicrovmStateError } ;
61
68
use crate :: resources:: VmResources ;
@@ -128,6 +135,12 @@ pub enum StartMicrovmError {
128
135
/// Error configuring ACPI: {0}
129
136
#[ cfg( target_arch = "x86_64" ) ]
130
137
Acpi ( #[ from] crate :: acpi:: AcpiError ) ,
138
+ /// Error starting GDB debug session
139
+ #[ cfg( feature = "gdb" ) ]
140
+ GdbServer ( gdb:: target:: GdbTargetError ) ,
141
+ /// Error cloning Vcpu fds
142
+ #[ cfg( feature = "gdb" ) ]
143
+ VcpuFdCloneError ( #[ from] crate :: vstate:: vcpu:: CopyKvmFdError ) ,
131
144
}
132
145
133
146
/// It's convenient to automatically convert `linux_loader::cmdline::Error`s
@@ -274,6 +287,18 @@ pub fn build_microvm_for_boot(
274
287
cpu_template. kvm_capabilities . clone ( ) ,
275
288
) ?;
276
289
290
+ #[ cfg( feature = "gdb" ) ]
291
+ let ( gdb_tx, gdb_rx) = mpsc:: channel ( ) ;
292
+ #[ cfg( feature = "gdb" ) ]
293
+ vcpus
294
+ . iter_mut ( )
295
+ . for_each ( |vcpu| vcpu. attach_debug_info ( gdb_tx. clone ( ) ) ) ;
296
+ #[ cfg( feature = "gdb" ) ]
297
+ let vcpu_fds = vcpus
298
+ . iter ( )
299
+ . map ( |vcpu| vcpu. copy_kvm_vcpu_fd ( vmm. vm ( ) ) )
300
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
301
+
277
302
// The boot timer device needs to be the first device attached in order
278
303
// to maintain the same MMIO address referenced in the documentation
279
304
// and tests.
@@ -321,16 +346,28 @@ pub fn build_microvm_for_boot(
321
346
boot_cmdline,
322
347
) ?;
323
348
349
+ let vmm = Arc :: new ( Mutex :: new ( vmm) ) ;
350
+
351
+ #[ cfg( feature = "gdb" ) ]
352
+ if let Some ( gdb_socket_addr) = & vm_resources. gdb_socket_addr {
353
+ gdb:: gdb_thread ( vmm. clone ( ) , vcpu_fds, gdb_rx, entry_addr, gdb_socket_addr)
354
+ . map_err ( GdbServer ) ?;
355
+ } else {
356
+ debug ! ( "No GDB socket provided not starting gdb server." ) ;
357
+ }
358
+
324
359
// Move vcpus to their own threads and start their state machine in the 'Paused' state.
325
- vmm. start_vcpus (
326
- vcpus,
327
- seccomp_filters
328
- . get ( "vcpu" )
329
- . ok_or_else ( || MissingSeccompFilters ( "vcpu" . to_string ( ) ) ) ?
330
- . clone ( ) ,
331
- )
332
- . map_err ( VmmError :: VcpuStart )
333
- . map_err ( Internal ) ?;
360
+ vmm. lock ( )
361
+ . unwrap ( )
362
+ . start_vcpus (
363
+ vcpus,
364
+ seccomp_filters
365
+ . get ( "vcpu" )
366
+ . ok_or_else ( || MissingSeccompFilters ( "vcpu" . to_string ( ) ) ) ?
367
+ . clone ( ) ,
368
+ )
369
+ . map_err ( VmmError :: VcpuStart )
370
+ . map_err ( Internal ) ?;
334
371
335
372
// Load seccomp filters for the VMM thread.
336
373
// Execution panics if filters cannot be loaded, use --no-seccomp if skipping filters
@@ -344,7 +381,6 @@ pub fn build_microvm_for_boot(
344
381
. map_err ( VmmError :: SeccompFilters )
345
382
. map_err ( Internal ) ?;
346
383
347
- let vmm = Arc :: new ( Mutex :: new ( vmm) ) ;
348
384
event_manager. add_subscriber ( vmm. clone ( ) ) ;
349
385
350
386
Ok ( vmm)
0 commit comments