Throw IOException at source of failing to open a dex file.

Before is:
java.lang.ClassNotFoundException: Didn't find class "GCBench" on path: DexPathList[[zip file "/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar"],nativeLibraryDirectories=[/disk2/dalvik-dev/out/host/linux-x86/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        Suppressed: java.lang.ClassNotFoundException: GCBench
                at java.lang.Class.classForName(Native Method)
                at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 1 more
        Caused by: java.lang.NoClassDefFoundError: Class "LGCBench;" not found
                ... 5 more
And after is:
java.lang.ClassNotFoundException: Didn't find class "GCBench" on path: DexPathList[[zip file "/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar"],nativeLibraryDirectories=[/disk2/dalvik-dev/out/host/linux-x86/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        Suppressed: java.io.IOException: Zip archive '/disk2/dalvik-dev/out/host/linux-x86/framework/GCBench.jar' doesn't contain classes.dex
                at dalvik.system.DexFile.openDexFile(Native Method)
                at dalvik.system.DexFile.<init>(DexFile.java:80)
                at dalvik.system.DexFile.<init>(DexFile.java:59)
                at dalvik.system.DexPathList.loadDexFile(DexPathList.java:268)
                at dalvik.system.DexPathList.makeDexElements(DexPathList.java:235)
                at dalvik.system.DexPathList.<init>(DexPathList.java:113)
                at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
                at dalvik.system.PathClassLoader.<init>(PathClassLoader.java:38)
                at java.lang.ClassLoader.createSystemClassLoader(ClassLoader.java:128)
                at java.lang.ClassLoader.access$000(ClassLoader.java:65)
                at java.lang.ClassLoader$SystemClassLoader.<clinit>(ClassLoader.java:81)
                at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:137)
        Suppressed: java.lang.ClassNotFoundException: GCBench
                at java.lang.Class.classForName(Native Method)
                at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 1 more
        Caused by: java.lang.NoClassDefFoundError: Class "LGCBench;" not found
                ... 5 more

Also, move dex file verifier messages out of logs.
In the process the ClassLinker::dex_lock_ needed tidying to cover a smaller
scope. Bug 11301553.

Change-Id: I80058652e11e7ea63457cc01a0cb48afe1c15543
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 7ecaf01..7553dcc 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -48,19 +48,21 @@
 }
 
 OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents,
-                             const std::string& location) {
+                             const std::string& location,
+                             std::string* error_msg) {
   CHECK(!oat_contents.empty()) << location;
   CheckLocation(location);
   UniquePtr<OatFile> oat_file(new OatFile(location));
   oat_file->begin_ = &oat_contents[0];
   oat_file->end_ = &oat_contents[oat_contents.size()];
-  return oat_file->Setup() ? oat_file.release() : NULL;
+  return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
 }
 
 OatFile* OatFile::Open(const std::string& filename,
                        const std::string& location,
                        byte* requested_base,
-                       bool executable) {
+                       bool executable,
+                       std::string* error_msg) {
   CHECK(!filename.empty()) << location;
   CheckLocation(filename);
 #ifdef ART_USE_PORTABLE_COMPILER
@@ -70,7 +72,7 @@
   // open a generated dex file by name, remove the file, then open
   // another generated dex file with the same name. http://b/10614658
   if (executable) {
-    return OpenDlopen(filename, location, requested_base);
+    return OpenDlopen(filename, location, requested_base, error_msg);
   }
 #endif
   // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
@@ -83,21 +85,22 @@
   if (file.get() == NULL) {
     return NULL;
   }
-  return OpenElfFile(file.get(), location, requested_base, false, executable);
+  return OpenElfFile(file.get(), location, requested_base, false, executable, error_msg);
 }
 
-OatFile* OatFile::OpenWritable(File* file, const std::string& location) {
+OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
   CheckLocation(location);
-  return OpenElfFile(file, location, NULL, true, false);
+  return OpenElfFile(file, location, NULL, true, false, error_msg);
 }
 
 OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
                              const std::string& location,
-                             byte* requested_base) {
+                             byte* requested_base,
+                             std::string* error_msg) {
   UniquePtr<OatFile> oat_file(new OatFile(location));
-  bool success = oat_file->Dlopen(elf_filename, requested_base);
+  bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
   if (!success) {
-    return NULL;
+    return nullptr;
   }
   return oat_file.release();
 }
@@ -106,11 +109,13 @@
                               const std::string& location,
                               byte* requested_base,
                               bool writable,
-                              bool executable) {
+                              bool executable,
+                              std::string* error_msg) {
   UniquePtr<OatFile> oat_file(new OatFile(location));
-  bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable);
+  bool success = oat_file->ElfFileOpen(file, requested_base, writable, executable, error_msg);
   if (!success) {
-    return NULL;
+    CHECK(!error_msg->empty());
+    return nullptr;
   }
   return oat_file.release();
 }
@@ -127,120 +132,117 @@
   }
 }
 
-bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base) {
+bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base,
+                     std::string* error_msg) {
   char* absolute_path = realpath(elf_filename.c_str(), NULL);
   if (absolute_path == NULL) {
-    VLOG(class_linker) << "Failed to find absolute path for " << elf_filename;
+    *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
     return false;
   }
   dlopen_handle_ = dlopen(absolute_path, RTLD_NOW);
   free(absolute_path);
   if (dlopen_handle_ == NULL) {
-    VLOG(class_linker) << "Failed to dlopen " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
     return false;
   }
   begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata"));
   if (begin_ == NULL) {
-    LOG(WARNING) << "Failed to find oatdata symbol in " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(),
+                              dlerror());
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="
-                 << reinterpret_cast<const void*>(begin_) << " != expected="
-                 << reinterpret_cast<const void*>(requested_base)
-                 << " /proc/self/maps:\n" << maps;
+    *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
+                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              begin_, requested_base);
+    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatlastword"));
   if (end_ == NULL) {
-    LOG(WARNING) << "Failed to find oatlastword symbol in " << elf_filename << ": " << dlerror();
+    *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(),
+                              dlerror());
     return false;
   }
   // Readjust to be non-inclusive upper bound.
   end_ += sizeof(uint32_t);
-  return Setup();
+  return Setup(error_msg);
 }
 
-bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable) {
-  elf_file_.reset(ElfFile::Open(file, writable, true));
-  if (elf_file_.get() == NULL) {
-    if (writable) {
-      PLOG(WARNING) << "Failed to open ELF file for " << file->GetPath();
-    }
+bool OatFile::ElfFileOpen(File* file, byte* requested_base, bool writable, bool executable,
+                          std::string* error_msg) {
+  elf_file_.reset(ElfFile::Open(file, writable, true, error_msg));
+  if (elf_file_.get() == nullptr) {
+    DCHECK(!error_msg->empty());
     return false;
   }
-  bool loaded = elf_file_->Load(executable);
+  bool loaded = elf_file_->Load(executable, error_msg);
   if (!loaded) {
-    LOG(WARNING) << "Failed to load ELF file " << file->GetPath();
+    DCHECK(!error_msg->empty());
     return false;
   }
   begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");
   if (begin_ == NULL) {
-    LOG(WARNING) << "Failed to find oatdata symbol in " << file->GetPath();
+    *error_msg = StringPrintf("Failed to find oatdata symbol in '%s'", file->GetPath().c_str());
     return false;
   }
   if (requested_base != NULL && begin_ != requested_base) {
-    std::string maps;
-    ReadFileToString("/proc/self/maps", &maps);
-    LOG(WARNING) << "Failed to find oatdata symbol at expected address: oatdata="
-                 << reinterpret_cast<const void*>(begin_) << " != expected="
-                 << reinterpret_cast<const void*>(requested_base)
-                 << " /proc/self/maps:\n" << maps;
+    *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
+                              "oatdata=%p != expected=%p /proc/self/maps:\n",
+                              begin_, requested_base);
+    ReadFileToString("/proc/self/maps", error_msg);
     return false;
   }
   end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");
   if (end_ == NULL) {
-    LOG(WARNING) << "Failed to find oatlastword symbol in " << file->GetPath();
+    *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s'", file->GetPath().c_str());
     return false;
   }
   // Readjust to be non-inclusive upper bound.
   end_ += sizeof(uint32_t);
-  return Setup();
+  return Setup(error_msg);
 }
 
-bool OatFile::Setup() {
+bool OatFile::Setup(std::string* error_msg) {
   if (!GetOatHeader().IsValid()) {
-    LOG(WARNING) << "Invalid oat magic for " << GetLocation();
+    *error_msg = StringPrintf("Invalid oat magic for '%s'", GetLocation().c_str());
     return false;
   }
   const byte* oat = Begin();
   oat += sizeof(OatHeader);
   if (oat > End()) {
-    LOG(ERROR) << "In oat file " << GetLocation() << " found truncated OatHeader";
+    *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str());
     return false;
   }
 
   oat += GetOatHeader().GetImageFileLocationSize();
   if (oat > End()) {
-    LOG(ERROR) << "In oat file " << GetLocation() << " found truncated image file location: "
-               << reinterpret_cast<const void*>(Begin())
-               << "+" << sizeof(OatHeader)
-               << "+" << GetOatHeader().GetImageFileLocationSize()
-               << "<=" << reinterpret_cast<const void*>(End());
+    *error_msg = StringPrintf("In oat file '%s' found truncated image file location: "
+                              "%p + %zd + %ud <= %p", GetLocation().c_str(),
+                              Begin(), sizeof(OatHeader), GetOatHeader().GetImageFileLocationSize(),
+                              End());
     return false;
   }
 
   for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
     size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
-    if (dex_file_location_size == 0U) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " with empty location name";
+    if (UNLIKELY(dex_file_location_size == 0U)) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
+                                GetLocation().c_str(), i);
       return false;
     }
     oat += sizeof(dex_file_location_size);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " truncated after dex file location size";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file "
+                                "location size", GetLocation().c_str(), i);
       return false;
     }
 
     const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
     oat += dex_file_location_size;
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " with truncated dex file location";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file "
+                                "location", GetLocation().c_str(), i);
       return false;
     }
 
@@ -248,55 +250,54 @@
 
     uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
     oat += sizeof(dex_file_checksum);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " truncated after dex file checksum";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after "
+                                "dex file checksum", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
     uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
-    if (dex_file_offset == 0U) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with zero dex file offset";
+    if (UNLIKELY(dex_file_offset == 0U)) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex "
+                                "file offset", GetLocation().c_str(), i, dex_file_location.c_str());
       return false;
     }
-    if (dex_file_offset > Size()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with dex file offset" << dex_file_offset << " > " << Size();
+    if (UNLIKELY(dex_file_offset > Size())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file "
+                                "offset %ud > %zd", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_offset, Size());
       return false;
     }
     oat += sizeof(dex_file_offset);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " truncated after dex file offset";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
+                                " after dex file offsets", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
     const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
-    if (!DexFile::IsMagicValid(dex_file_pointer)) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with invalid dex file magic: " << dex_file_pointer;
+    if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
+                                " dex file magic '%s'", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
-    if (!DexFile::IsVersionValid(dex_file_pointer)) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with invalid dex file version: " << dex_file_pointer;
+    if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
+                                " dex file version '%s'", GetLocation().c_str(), i,
+                                dex_file_location.c_str(), dex_file_pointer);
       return false;
     }
     const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
     const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat);
 
     oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
-    if (oat > End()) {
-      LOG(ERROR) << "In oat file " << GetLocation() << " found OatDexFile # " << i
-                 << " for "<< dex_file_location
-                 << " with truncated method offsets";
+    if (UNLIKELY(oat > End())) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated "
+                                " method offsets", GetLocation().c_str(), i,
+                                dex_file_location.c_str());
       return false;
     }
 
@@ -323,8 +324,8 @@
   return end_;
 }
 
-const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_location,
-                                                  const uint32_t* const dex_location_checksum,
+const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
+                                                  const uint32_t* dex_location_checksum,
                                                   bool warn_if_not_found) const {
   Table::const_iterator it = oat_dex_files_.find(dex_location);
   if (it != oat_dex_files_.end()) {
@@ -373,9 +374,9 @@
   return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
 }
 
-const DexFile* OatFile::OatDexFile::OpenDexFile() const {
+const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
   return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
-                       dex_file_location_checksum_);
+                       dex_file_location_checksum_, error_msg);
 }
 
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const {