linux: Support GDB remote serial protocol for x86_64

Add a flag '--gdb <port>' to provide GDB remote protocol interface so
a developer can attach GDB to the guest kernel.
In this CL, we support read/write operations for registers and memories.

BUG=chromium:1141812
TEST=Attach gdb and see register values on workstation and intel DUT

Change-Id: Ia07763870d94e87867f6df43f039196aa703ee59
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2440221
Commit-Queue: Keiichi Watanabe <keiichiw@chromium.org>
Tested-by: Keiichi Watanabe <keiichiw@chromium.org>
Auto-Submit: Keiichi Watanabe <keiichiw@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
diff --git a/src/main.rs b/src/main.rs
index 7af6e61..2d9cd90 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1438,7 +1438,17 @@
             let params = parse_battery_options(value)?;
             cfg.battery_type = Some(params);
         }
-
+        #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+        "gdb" => {
+            let port = value
+                .unwrap()
+                .parse()
+                .map_err(|_| argument::Error::InvalidValue {
+                    value: value.unwrap().to_owned(),
+                    expected: String::from("expected a valid port number"),
+                })?;
+            cfg.gdb = Some(port);
+        }
         "help" => return Err(argument::Error::PrintHelp),
         _ => unreachable!(),
     }
@@ -1480,6 +1490,14 @@
             }
         }
     }
+    #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
+    if cfg.gdb.is_some() {
+        if cfg.vcpu_count.unwrap_or(1) != 1 {
+            return Err(argument::Error::ExpectedArgument(
+                "`gdb` requires the number of vCPU to be 1".to_owned(),
+            ));
+        }
+    }
     set_default_serial_parameters(&mut cfg.serial_parameters);
     Ok(())
 }
@@ -1627,6 +1645,7 @@
                                   Possible key values:
                                   type=goldfish - type of battery emulation, defaults to goldfish
                                   "),
+          Argument::value("gdb", "PORT", "(EXPERIMENTAL) gdb on the given port"),
           Argument::short_flag('h', "help", "Print help message.")];
 
     let mut cfg = Config::default();