Add the ability to debug the kernel via tcp

Change-Id: If46ae529196cd0e2842cef73c1341508314118c9
Merged-In: If46ae529196cd0e2842cef73c1341508314118c9
Test: booted with debug flag
(cherry picked from commit 91f8142b22126f76db78a6804b47b4462d6fd3e1)
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 581bbe1..414ecb9 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -67,6 +67,8 @@
              "The size of the blank data image to generate, MB.");
 DEFINE_string(blank_data_image_fmt, "ext4",
               "The fs format for the blank data image. Used with mkfs.");
+DEFINE_string(qemu_gdb, "",
+	      "Debug flag to pass to qemu. e.g. --qemu_gdb=tcp::1234");
 
 DEFINE_int32(x_res, 720, "Width of the screen in pixels");
 DEFINE_int32(y_res, 1280, "Height of the screen in pixels");
@@ -485,9 +487,7 @@
   config->set_x_res(FLAGS_x_res);
   config->set_y_res(FLAGS_y_res);
   config->set_refresh_rate_hz(FLAGS_refresh_rate_hz);
-
-  config->set_adb_mode(FLAGS_adb_mode);
-
+  config->set_gdb_flag(FLAGS_qemu_gdb);
   if (FLAGS_kernel_path.size()) {
     config->set_kernel_image_path(FLAGS_kernel_path);
   } else {
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 82aa432..260f050 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -77,6 +77,7 @@
 const char* kRefreshRateHz = "refresh_rate_hz";
 
 const char* kKernelImagePath = "kernel_image_path";
+const char* kGdbFlag = "gdb_flag";
 const char* kKernelArgs = "kernel_args";
 const char* kRamdiskImagePath = "ramdisk_image_path";
 
@@ -158,11 +159,21 @@
 std::string CuttlefishConfig::kernel_image_path() const {
   return (*dictionary_)[kKernelImagePath].asString();
 }
+
 void CuttlefishConfig::set_kernel_image_path(
     const std::string& kernel_image_path) {
   (*dictionary_)[kKernelImagePath] = kernel_image_path;
 }
 
+std::string CuttlefishConfig::gdb_flag() const {
+  return (*dictionary_)[kGdbFlag].asString();
+}
+
+void CuttlefishConfig::set_gdb_flag(
+    const std::string& device) {
+  (*dictionary_)[kGdbFlag] = device;
+}
+
 std::string CuttlefishConfig::kernel_args() const {
   return (*dictionary_)[kKernelArgs].asString();
 }
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index e8e1a44..9250b3e 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -74,6 +74,9 @@
   std::string kernel_args() const;
   void set_kernel_args(const std::string& kernel_args);
 
+  std::string gdb_flag() const;
+  void set_gdb_flag(const std::string& gdb);
+
   std::string ramdisk_image_path() const;
   void set_ramdisk_image_path(const std::string& ramdisk_image_path);
 
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index 69a8c5e..4bca7c2 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -83,6 +83,10 @@
     -msg "timestamp=on"
 )
 
+if [[ -n "${gdb_flag}" ]]; then
+  args+=(-gdb "${gdb_flag}")
+fi
+
 if [[ -n "${ramdisk_image_path}" ]]; then
   args+=(-initrd "${ramdisk_image_path}")
 fi
diff --git a/host/libs/vm_manager/libvirt_manager.cpp b/host/libs/vm_manager/libvirt_manager.cpp
index 3d514a7..6b499c8 100644
--- a/host/libs/vm_manager/libvirt_manager.cpp
+++ b/host/libs/vm_manager/libvirt_manager.cpp
@@ -129,16 +129,24 @@
 
 // Configure QEmu specific arguments.
 // This section adds the <qemu:commandline> node.
-void ConfigureQEmuSpecificOptions(
-    xmlNode* root, std::initializer_list<std::string> qemu_args) {
+xmlNodePtr ConfigureQEmuSpecificOptions(
+    xmlNode* root, std::initializer_list<std::string> qemu_args,
+    xmlNode* existing_options = nullptr) {
   xmlNs* qemu_ns{xmlNewNs(
       root, xc("http://libvirt.org/schemas/domain/qemu/1.0"), xc("qemu"))};
 
-  auto cmd = xmlNewChild(root, qemu_ns, xc("commandline"), nullptr);
+  xmlNode* cmd;
+  if (existing_options) {
+    cmd = existing_options;
+  } else {
+    cmd = xmlNewChild(root, qemu_ns, xc("commandline"), nullptr);
+  }
+
   for (const auto& str : qemu_args) {
     auto arg = xmlNewChild(cmd, qemu_ns, xc("arg"), nullptr);
     xmlNewProp(arg, xc("value"), xc(str.c_str()));
   }
+  return cmd;
 }
 
 void ConfigureDeviceSource(xmlNode* device, DeviceSourceType type,
@@ -276,7 +284,7 @@
   ConfigureOperatingSystem(root, config->kernel_image_path(),
                            config->ramdisk_image_path(), config->kernel_args(),
                            config->dtb_path());
-  ConfigureQEmuSpecificOptions(
+  auto qemu_options = ConfigureQEmuSpecificOptions(
       root, {"-chardev",
              concat("socket,path=", config->ivshmem_qemu_socket_path(),
                     ",id=ivsocket"),
@@ -284,6 +292,11 @@
              concat("ivshmem-doorbell,chardev=ivsocket,vectors=",
                     config->ivshmem_vector_count()),
              "-cpu", "host"});
+  if (config->gdb_flag().size()) {
+    ConfigureQEmuSpecificOptions(root, {"-gdb", config->gdb_flag().c_str(),
+                                        "-S"},
+                                 qemu_options);
+  }
 
   if (config->disable_app_armor_security()) {
     auto seclabel = xmlNewChild(root, nullptr, xc("seclabel"), nullptr);
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 5b0948d..10fa693 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -65,6 +65,7 @@
   LogAndSetEnv("monitor_path",
                       config->PerInstancePath("qemu_monitor.sock"));
   LogAndSetEnv("kernel_image_path", config->kernel_image_path());
+  LogAndSetEnv("gdb_flag", config->gdb_flag());
   LogAndSetEnv("ramdisk_image_path", config->ramdisk_image_path());
   LogAndSetEnv("kernel_args", config->kernel_args());
   LogAndSetEnv("dtb_path", config->dtb_path());