Working ClassLoader

Change-Id: Ia1122165e47f846a1d4506111849f830d9f14c1b
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 8113c2b..4d99647 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -26,7 +26,11 @@
           "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
-          "  --image=<file.art>: specifies the required input image filename.\n"
+          "  --oat=<file.oat>: specifies an input oat filename.\n"
+          "      Example: --image=/system/framework/boot.oat\n"
+          "\n");
+  fprintf(stderr,
+          "  --image=<file.art>: specifies an input image filename.\n"
           "      Example: --image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
@@ -52,15 +56,168 @@
   "kStaticResolutionStubArray",
   "kUnknownMethodResolutionStubArray",
   "kCalleeSaveMethod",
+  "kRefsOnlySaveMethod",
+  "kRefsAndArgsSaveMethod",
   "kOatLocation",
   "kDexCaches",
   "kClassRoots",
 };
 
 class OatDump {
+ public:
+  static void Dump(const std::string& oat_filename,
+                   const std::string& host_prefix,
+                   std::ostream& os,
+                   const OatFile& oat_file) {
+    const OatHeader& oat_header = oat_file.GetOatHeader();
+
+    os << "MAGIC:\n";
+    os << oat_header.GetMagic() << "\n\n";
+
+    os << "CHECKSUM:\n";
+    os << StringPrintf("%08x\n\n", oat_header.GetChecksum());
+
+    os << "DEX FILE COUNT:\n";
+    os << oat_header.GetDexFileCount() << "\n\n";
+
+    os << "EXECUTABLE OFFSET:\n";
+    os << StringPrintf("%08x\n\n", oat_header.GetExecutableOffset());
+
+    os << "BASE:\n";
+    os << oat_file.GetBase() << "\n\n";
+
+    os << "LIMIT:\n";
+    os << oat_file.GetLimit() << "\n\n";
+
+    os << std::flush;
+
+    std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file.GetOatDexFiles() ;
+    for (size_t i = 0; i < oat_dex_files.size(); i++) {
+      const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+      CHECK(oat_dex_file != NULL);
+      DumpOatDexFile(host_prefix, os, oat_file, *oat_dex_file);
+    }
+  }
+
+ private:
+  static void DumpOatDexFile(const std::string& host_prefix,
+                             std::ostream& os,
+                             const OatFile& oat_file,
+                             const OatFile::OatDexFile& oat_dex_file) {
+    os << "OAT DEX FILE:\n";
+    std::string dex_file_location = oat_dex_file.GetDexFileLocation();
+    os << "location: " << dex_file_location;
+    if (!host_prefix.empty()) {
+      dex_file_location = host_prefix + dex_file_location;
+      os << " (" << dex_file_location << ")\n";
+    }
+    os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
+    const DexFile* dex_file = DexFile::Open(dex_file_location, "");
+    if (dex_file == NULL) {
+      os << "NOT FOUND\n\n";
+      return;
+    }
+    for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+      const char* descriptor = dex_file->GetClassDescriptor(class_def);
+      os << StringPrintf("%d: %s (type_ide=%d)\n", class_def_index, descriptor, class_def.class_idx_);
+      UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
+      CHECK(oat_class.get() != NULL);
+      DumpOatClass(os, oat_file, *oat_class.get(), *dex_file, class_def);
+    }
+
+    os << std::flush;
+  }
+
+  static void DumpOatClass(std::ostream& os,
+                           const OatFile& oat_file,
+                           const OatFile::OatClass& oat_class,
+                           const DexFile& dex_file,
+                           const DexFile::ClassDef& class_def) {
+    const byte* class_data = dex_file.GetClassData(class_def);
+    DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+    size_t num_static_fields = header.static_fields_size_;
+    size_t num_instance_fields = header.instance_fields_size_;
+    size_t num_direct_methods = header.direct_methods_size_;
+    size_t num_virtual_methods = header.virtual_methods_size_;
+    uint32_t method_index = 0;
+
+    // just skipping through the fields to advance class_data
+    if (num_static_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_static_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+      }
+    }
+    if (num_instance_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_instance_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+      }
+    }
+
+    if (num_direct_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_direct_methods; ++i, method_index++) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+        DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+      }
+    }
+    if (num_virtual_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_virtual_methods; ++i, method_index++) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+        DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+      }
+    }
+    os << std::flush;
+  }
+  static void DumpOatMethod(std::ostream& os,
+                            uint32_t method_index,
+                            const OatFile& oat_file,
+                            const OatFile::OatMethod& oat_method,
+                            const DexFile& dex_file,
+                            const DexFile::Method& dex_method) {
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method.method_idx_);
+    const char* name = dex_file.GetMethodName(method_id);
+    std::string signature = dex_file.GetMethodSignature(method_id);
+    os << StringPrintf("\t%d: %s %s (method_idx=%d)\n",
+                       method_index, name, signature.c_str(), dex_method.method_idx_);
+    os << StringPrintf("\t\tcode: %p (offset=%08x)\n",
+                       oat_method.code_,
+                       reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase());
+    os << StringPrintf("\t\tframe_size_in_bytes: %d\n",
+                       oat_method.frame_size_in_bytes_);
+    os << StringPrintf("\t\treturn_pc_offset_in_bytes: %d\n",
+                       oat_method.return_pc_offset_in_bytes_);
+    os << StringPrintf("\t\tcore_spill_mask: %08x\n",
+                       oat_method.core_spill_mask_);
+    os << StringPrintf("\t\tfp_spill_mask: %08x\n",
+                       oat_method.fp_spill_mask_);
+    os << StringPrintf("\t\tmapping_table: %p (offset=%08x)\n",
+                       oat_method.mapping_table_,
+                       reinterpret_cast<const byte*>(oat_method.mapping_table_) - oat_file.GetBase());
+    os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
+                       oat_method.vmap_table_,
+                       reinterpret_cast<const byte*>(oat_method.vmap_table_) - oat_file.GetBase());
+    os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
+                       oat_method.invoke_stub_,
+                       reinterpret_cast<const byte*>(oat_method.invoke_stub_) - oat_file.GetBase());
+  }
+
+};
+
+class ImageDump {
 
  public:
   static void Dump(const std::string& image_filename,
+                   const std::string& host_prefix,
                    std::ostream& os,
                    Space& image_space,
                    const ImageHeader& image_header) {
@@ -70,10 +227,17 @@
     os << "IMAGE BASE:\n";
     os << reinterpret_cast<void*>(image_header.GetImageBaseAddr()) << "\n\n";
 
+    os << "OAT CHECKSUM:\n";
+    os << StringPrintf("%08x\n\n", image_header.GetOatChecksum());
+
     os << "OAT BASE:\n";
     os << reinterpret_cast<void*>(image_header.GetOatBaseAddr()) << "\n\n";
 
+    os << "OAT LIMIT:\n";
+    os << reinterpret_cast<void*>(image_header.GetOatLimitAddr()) << "\n\n";
+
     os << "ROOTS:\n";
+    os << reinterpret_cast<void*>(image_header.GetImageRoots()) << "\n";
     CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
     for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
       ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
@@ -93,10 +257,10 @@
     os << "\n";
 
     os << "OBJECTS:\n" << std::flush;
-    OatDump state(image_space, os);
+    ImageDump state(image_space, os);
     HeapBitmap* heap_bitmap = Heap::GetLiveBits();
     DCHECK(heap_bitmap != NULL);
-    heap_bitmap->Walk(OatDump::Callback, &state);
+    heap_bitmap->Walk(ImageDump::Callback, &state);
     os << "\n";
 
     os << "STATS:\n" << std::flush;
@@ -107,22 +271,41 @@
     size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
     state.stats_.alignment_bytes += alignment_bytes;
     state.stats_.Dump(os);
+    os << "\n";
 
     os << std::flush;
+
+    os << "OAT LOCATION:\n" << std::flush;
+    Object* oat_location_object = image_header.GetImageRoot(ImageHeader::kOatLocation);
+    std::string oat_location = oat_location_object->AsString()->ToModifiedUtf8();
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    os << oat_location;
+    if (!host_prefix.empty()) {
+      oat_location = host_prefix + oat_location;
+      os << " (" << oat_location << ")\n";
+    }
+    const OatFile* oat_file = class_linker->FindOatFile(oat_location);
+    if (oat_file == NULL) {
+      os << "NOT FOUND\n";
+      os << std::flush;
+      return;
+    }
+    os << "\n";
+    os << std::flush;
+
+    OatDump::Dump(oat_location, host_prefix, os, *oat_file);
   }
 
  private:
 
-  OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {
-  }
+  ImageDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {}
 
-  ~OatDump() {
-  }
+  ~ImageDump() {}
 
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
     DCHECK(arg != NULL);
-    OatDump* state = reinterpret_cast<OatDump*>(arg);
+    ImageDump* state = reinterpret_cast<ImageDump*>(arg);
     if (!state->InDumpSpace(obj)) {
       return;
     }
@@ -319,7 +502,6 @@
                          / static_cast<double>(dex_instruction_bytes));
       os << "\n";
       os << std::flush;
-
     }
   } stats_;
 
@@ -327,7 +509,7 @@
   const Space& dump_space_;
   std::ostream& os_;
 
-  DISALLOW_COPY_AND_ASSIGN(OatDump);
+  DISALLOW_COPY_AND_ASSIGN(ImageDump);
 };
 
 int oatdump(int argc, char** argv) {
@@ -336,10 +518,11 @@
   argc--;
 
   if (argc == 0) {
-    fprintf(stderr, "no arguments specified\n");
+    fprintf(stderr, "No arguments specified\n");
     usage();
   }
 
+  const char* oat_filename = NULL;
   const char* image_filename = NULL;
   const char* boot_image_filename = NULL;
   std::string host_prefix;
@@ -348,7 +531,9 @@
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
-    if (option.starts_with("--image=")) {
+    if (option.starts_with("--oat=")) {
+      oat_filename = option.substr(strlen("--oat=")).data();
+    } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--boot-image=")) {
       boot_image_filename = option.substr(strlen("--boot-image=")).data();
@@ -358,21 +543,36 @@
       const char* filename = option.substr(strlen("--output=")).data();
       out.reset(new std::ofstream(filename));
       if (!out->good()) {
-        fprintf(stderr, "failed to open output filename %s\n", filename);
+        fprintf(stderr, "Failed to open output filename %s\n", filename);
         usage();
       }
       os = out.get();
     } else {
-      fprintf(stderr, "unknown argument %s\n", option.data());
+      fprintf(stderr, "Unknown argument %s\n", option.data());
       usage();
     }
   }
 
-  if (image_filename == NULL) {
-   fprintf(stderr, "--image file name not specified\n");
+  if (image_filename == NULL && oat_filename == NULL) {
+   fprintf(stderr, "Either --image or --oat must be specified\n");
    return EXIT_FAILURE;
   }
 
+  if (image_filename != NULL && oat_filename != NULL) {
+   fprintf(stderr, "Either --image or --oat must be specified but not both\n");
+   return EXIT_FAILURE;
+  }
+
+  if (oat_filename != NULL) {
+    const OatFile* oat_file = OatFile::Open(oat_filename, "", NULL);
+    if (oat_file == NULL) {
+      fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
+      return EXIT_FAILURE;
+    }
+    OatDump::Dump(oat_filename, host_prefix, *os, *oat_file);
+    return EXIT_SUCCESS;
+  }
+
   Runtime::Options options;
   std::string image_option;
   std::string oat_option;
@@ -383,9 +583,11 @@
     boot_image_option += boot_image_filename;
     options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
   }
-  image_option += "-Ximage:";
-  image_option += image_filename;
-  options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+  if (image_filename != NULL) {
+    image_option += "-Ximage:";
+    image_option += image_filename;
+    options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+  }
 
   if (!host_prefix.empty()) {
     options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
@@ -393,7 +595,7 @@
 
   UniquePtr<Runtime> runtime(Runtime::Create(options, false));
   if (runtime.get() == NULL) {
-    fprintf(stderr, "could not create runtime\n");
+    fprintf(stderr, "Failed to create runtime\n");
     return EXIT_FAILURE;
   }
 
@@ -401,10 +603,10 @@
   CHECK(image_space != NULL);
   const ImageHeader& image_header = image_space->GetImageHeader();
   if (!image_header.IsValid()) {
-    fprintf(stderr, "invalid image header %s\n", image_filename);
+    fprintf(stderr, "Invalid image header %s\n", image_filename);
     return EXIT_FAILURE;
   }
-  OatDump::Dump(image_filename, *os, *image_space, image_header);
+  ImageDump::Dump(image_filename, host_prefix, *os, *image_space, image_header);
   return EXIT_SUCCESS;
 }