Better error reporting when loading dex files

Collect all partial error messages and return them as cause
exceptions for the top-level exception returned.

Change-Id: I9661b8aed2a571dc88bf0f06d447108eeaed1409
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 4b6d82b..315f274 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -66,6 +66,28 @@
   }
 }
 
+static void ThrowWrappedException(const ThrowLocation* throw_location,
+                                  const char* exception_descriptor,
+                                  mirror::Class* referrer, const char* fmt, va_list* args = NULL)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::ostringstream msg;
+  if (args != NULL) {
+    std::string vmsg;
+    StringAppendV(&vmsg, fmt, *args);
+    msg << vmsg;
+  } else {
+    msg << fmt;
+  }
+  AddReferrerLocation(msg, referrer);
+  Thread* self = Thread::Current();
+  if (throw_location == NULL) {
+    ThrowLocation computed_throw_location = self->GetCurrentLocationForThrow();
+    self->ThrowNewWrappedException(computed_throw_location, exception_descriptor, msg.str().c_str());
+  } else {
+    self->ThrowNewWrappedException(*throw_location, exception_descriptor, msg.str().c_str());
+  }
+}
+
 // AbstractMethodError
 
 void ThrowAbstractMethodError(mirror::ArtMethod* method) {
@@ -243,6 +265,13 @@
   va_end(args);
 }
 
+void ThrowWrappedIOException(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  ThrowWrappedException(NULL, "Ljava/io/IOException;", NULL, fmt, &args);
+  va_end(args);
+}
+
 // LinkageError
 
 void ThrowLinkageError(mirror::Class* referrer, const char* fmt, ...) {