Add --gdb flag to vm run,run-app and run-microdroid commands

This flag will be passed through to crosvm, which in turn will start a
gdb server at the given port. This will allow us to attach gdb to guest
kernel.

There are following rules on how --gdb flag can be used:

1. Only caller with USE_CUSTOM_VIRTUAL_MACHINE permission (a.k.a. shell)
   can specify gdbPort in the payload config
2. The --gdb flag is only supported for non-protected VMs.
3. The --gdb flag is only supported for fully debuggable app payloads.

Bug: 242057159
Test: run-microdroid --gdb 3456
Change-Id: Iea93d8e6b37d23801d84cc1dc5fc1a250b54a047
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 6c08a19..1d9f50b 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -28,6 +28,7 @@
 use create_idsig::command_create_idsig;
 use create_partition::command_create_partition;
 use run::{command_run, command_run_app, command_run_microdroid};
+use std::num::NonZeroU16;
 use std::path::{Path, PathBuf};
 
 #[derive(Debug)]
@@ -101,6 +102,11 @@
         /// Paths to extra idsig files.
         #[clap(long = "extra-idsig")]
         extra_idsigs: Vec<PathBuf>,
+
+        /// Port at which crosvm will start a gdb server to debug guest kernel.
+        /// Note: this is only supported on Android kernels android14-5.15 and higher.
+        #[clap(long)]
+        gdb: Option<NonZeroU16>,
     },
     /// Run a virtual machine with Microdroid inside
     RunMicrodroid {
@@ -152,6 +158,11 @@
         /// Comma separated list of task profile names to apply to the VM
         #[clap(long)]
         task_profiles: Vec<String>,
+
+        /// Port at which crosvm will start a gdb server to debug guest kernel.
+        /// Note: this is only supported on Android kernels android14-5.15 and higher.
+        #[clap(long)]
+        gdb: Option<NonZeroU16>,
     },
     /// Run a virtual machine
     Run {
@@ -177,6 +188,11 @@
         /// Path to file for VM log output.
         #[clap(long)]
         log: Option<PathBuf>,
+
+        /// Port at which crosvm will start a gdb server to debug guest kernel.
+        /// Note: this is only supported on Android kernels android14-5.15 and higher.
+        #[clap(long)]
+        gdb: Option<NonZeroU16>,
     },
     /// List running virtual machines
     List,
@@ -260,6 +276,7 @@
             cpu_topology,
             task_profiles,
             extra_idsigs,
+            gdb,
         } => command_run_app(
             name,
             get_service()?.as_ref(),
@@ -278,6 +295,7 @@
             cpu_topology,
             task_profiles,
             &extra_idsigs,
+            gdb,
         ),
         Opt::RunMicrodroid {
             name,
@@ -291,6 +309,7 @@
             mem,
             cpu_topology,
             task_profiles,
+            gdb,
         } => command_run_microdroid(
             name,
             get_service()?.as_ref(),
@@ -304,8 +323,9 @@
             mem,
             cpu_topology,
             task_profiles,
+            gdb,
         ),
-        Opt::Run { name, config, cpu_topology, task_profiles, console, log } => {
+        Opt::Run { name, config, cpu_topology, task_profiles, console, log, gdb } => {
             command_run(
                 name,
                 get_service()?.as_ref(),
@@ -315,6 +335,7 @@
                 /* mem */ None,
                 cpu_topology,
                 task_profiles,
+                gdb,
             )
         }
         Opt::List => command_list(get_service()?.as_ref()),
diff --git a/vm/src/run.rs b/vm/src/run.rs
index fa84591..5d785de 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -32,6 +32,7 @@
 use std::fs;
 use std::fs::File;
 use std::io;
+use std::num::NonZeroU16;
 use std::os::unix::io::{AsRawFd, FromRawFd};
 use std::path::{Path, PathBuf};
 use vmclient::{ErrorCode, VmInstance};
@@ -58,6 +59,7 @@
     cpu_topology: CpuTopology,
     task_profiles: Vec<String>,
     extra_idsigs: &[PathBuf],
+    gdb: Option<NonZeroU16>,
 ) -> Result<(), Error> {
     let apk_file = File::open(apk).context("Failed to open APK file")?;
 
@@ -144,6 +146,7 @@
         memoryMib: mem.unwrap_or(0) as i32, // 0 means use the VM default
         cpuTopology: cpu_topology,
         taskProfiles: task_profiles,
+        gdbPort: gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
     });
     run(service, &config, &payload_config_str, console_path, log_path)
 }
@@ -185,6 +188,7 @@
     mem: Option<u32>,
     cpu_topology: CpuTopology,
     task_profiles: Vec<String>,
+    gdb: Option<NonZeroU16>,
 ) -> Result<(), Error> {
     let apk = find_empty_payload_apk_path()?;
     println!("found path {}", apk.display());
@@ -215,6 +219,7 @@
         cpu_topology,
         task_profiles,
         &extra_sig,
+        gdb,
     )
 }
 
@@ -229,6 +234,7 @@
     mem: Option<u32>,
     cpu_topology: CpuTopology,
     task_profiles: Vec<String>,
+    gdb: Option<NonZeroU16>,
 ) -> Result<(), Error> {
     let config_file = File::open(config_path).context("Failed to open config file")?;
     let mut config =
@@ -241,6 +247,9 @@
     } else {
         config.name = String::from("VmRun");
     }
+    if let Some(gdb) = gdb {
+        config.gdbPort = gdb.get() as i32;
+    }
     config.cpuTopology = cpu_topology;
     config.taskProfiles = task_profiles;
     run(