Write shared data section for oatdump export dex

Write this out so that the resulting dex can be dumped and inspected.

Bug: 77469384
Test: test-art-host-gtest-oatdump_test

Change-Id: Iadeaca0eaaf7c75a938dfc776801cf94c89d07f6
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index b342abe..b483e5f 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -300,11 +300,13 @@
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
   oatdumpd-host \
-  oatdumpds-host
+  oatdumpds-host \
+  dexdump2-host
 ART_GTEST_oatdump_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  oatdumpd-target
+  oatdumpd-target \
+  dexdump2-target
 ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS)
 ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS)
 ART_GTEST_oatdump_app_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS) \
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 433ed9a..3bff123 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1180,6 +1180,17 @@
       }
     }
 
+    // Update header for shared section.
+    uint32_t shared_section_offset = 0u;
+    uint32_t shared_section_size = 0u;
+    if (dex_file->IsCompactDexFile()) {
+      CompactDexFile::Header* const header =
+          reinterpret_cast<CompactDexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()));
+      shared_section_offset = header->data_off_;
+      shared_section_size = header->data_size_;
+      // The shared section will be serialized right after the dex file.
+      header->data_off_ = header->file_size_;
+    }
     // Verify output directory exists
     if (!OS::DirectoryExists(options_.export_dex_location_)) {
       // TODO: Extend OS::DirectoryExists if symlink support is required
@@ -1226,16 +1237,22 @@
       return false;
     }
 
-    bool success = false;
-      success = file->WriteFully(dex_file->Begin(), fsize);
-    // }
-
+    bool success = file->WriteFully(dex_file->Begin(), fsize);
     if (!success) {
       os << "Failed to write dex file";
       file->Erase();
       return false;
     }
 
+    if (shared_section_size != 0) {
+      success = file->WriteFully(dex_file->Begin() + shared_section_offset, shared_section_size);
+      if (!success) {
+        os << "Failed to write shared data section";
+        file->Erase();
+        return false;
+      }
+    }
+
     if (file->FlushCloseOrErase() != 0) {
       os << "Flush and close failed";
       return false;
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 0034469..18cb2fd 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -75,6 +75,11 @@
   std::string error_msg;
   ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly, &error_msg))
       << error_msg;
+  const std::string dex_location = tmp_dir_+ "/core-oj-hostdex.jar_export.dex";
+  const std::string dexdump2 = GetExecutableFilePath("dexdump2",
+                                                     /*is_debug*/false,
+                                                     /*is_static*/false);
+  ASSERT_TRUE(ForkAndExecAndWait({dexdump2, "-d", dex_location}, &error_msg)) << error_msg;
 }
 TEST_F(OatDumpTest, TestExportDexStatic) {
   TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index fac0bb2..b85730d 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -70,20 +70,24 @@
     kStatic,   // oatdump(d)s, dex2oat(d)s
   };
 
-  // Returns path to the oatdump/dex2oat binary.
-  std::string GetExecutableFilePath(Flavor flavor, const char* name) {
+  // Returns path to the oatdump/dex2oat/dexdump binary.
+  std::string GetExecutableFilePath(const char* name, bool is_debug, bool is_static) {
     std::string root = GetTestAndroidRoot();
     root += "/bin/";
     root += name;
-    if (kIsDebugBuild) {
+    if (is_debug) {
       root += "d";
     }
-    if (flavor == kStatic) {
+    if (is_static) {
       root += "s";
     }
     return root;
   }
 
+  std::string GetExecutableFilePath(Flavor flavor, const char* name) {
+    return GetExecutableFilePath(name, kIsDebugBuild, flavor == kStatic);
+  }
+
   enum Mode {
     kModeOat,
     kModeOatWithBootImage,
@@ -127,17 +131,7 @@
     };
     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
 
-    pid_t pid;
-    int pipe_fd;
-    bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg);
-    if (result) {
-      close(pipe_fd);
-      int status = 0;
-      if (waitpid(pid, &status, 0) != -1) {
-        result = (status == 0);
-      }
-    }
-    return result;
+    return ForkAndExecAndWait(exec_argv, error_msg);
   }
 
   // Run the test with custom arguments.
@@ -300,6 +294,21 @@
     }
   }
 
+  bool ForkAndExecAndWait(const std::vector<std::string>& exec_argv,
+                          /*out*/ std::string* error_msg) {
+    pid_t pid;
+    int pipe_fd;
+    bool result = ForkAndExec(exec_argv, &pid, &pipe_fd, error_msg);
+    if (result) {
+      close(pipe_fd);
+      int status = 0;
+      if (waitpid(pid, &status, 0) != -1) {
+        result = (status == 0);
+      }
+    }
+    return result;
+  }
+
   std::string tmp_dir_;
 
  private: