Include JNI details in the SIGQUIT output.

Also include the original command line (framework apps deliberately clobber
their argv[]).

Change-Id: I63e04cb637fa89764e8963f3d086806ae230e953
diff --git a/src/heap.cc b/src/heap.cc
index b4bc7ce..02e3ac7 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -51,7 +51,7 @@
   }
 }
 
-static bool GenerateImage(const std::string image_file_name) {
+static bool GenerateImage(const std::string& image_file_name) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
   Split(boot_class_path_string, ':', boot_class_path);
@@ -660,7 +660,7 @@
 void Heap::DumpForSigQuit(std::ostream& os) {
   os << "Heap: " << GetPercentFree() << "% free, "
      << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory())
-     << "; " << num_objects_allocated_ << " objects";
+     << "; " << num_objects_allocated_ << " objects\n";
 }
 
 size_t Heap::GetPercentFree() {
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index ccebca5..eacc73f 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -647,7 +647,7 @@
   return LookupStringId(std::string(string));
 }
 
-HprofStringId Hprof::LookupStringId(std::string string) {
+HprofStringId Hprof::LookupStringId(const std::string& string) {
   StringMapIterator it = strings_.find(string);
   if (it != strings_.end()) {
     return it->second;
diff --git a/src/hprof/hprof.h b/src/hprof/hprof.h
index bcdbef8..e2f7ce1 100644
--- a/src/hprof/hprof.h
+++ b/src/hprof/hprof.h
@@ -196,7 +196,7 @@
   HprofClassObjectId LookupClassId(Class* c);
   HprofStringId LookupStringId(String* string);
   HprofStringId LookupStringId(const char* string);
-  HprofStringId LookupStringId(std::string string);
+  HprofStringId LookupStringId(const std::string& string);
   HprofStringId LookupClassNameId(Class* c);
   static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut);
   static HprofBasicType PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t* sizeOut);
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 1e27604..846a717 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -659,6 +659,21 @@
     STLDeleteValues(&libraries_);
   }
 
+  void Dump(std::ostream& os) const {
+    bool first = true;
+    for (It it = libraries_.begin(); it != libraries_.end(); ++it) {
+      if (!first) {
+        os << ' ';
+      }
+      first = false;
+      os << it->first;
+    }
+  }
+
+  size_t size() const {
+    return libraries_.size();
+  }
+
   SharedLibrary* Get(const std::string& path) {
     It it = libraries_.find(path);
     return (it == libraries_.end()) ? NULL : it->second;
@@ -698,7 +713,7 @@
   }
 
  private:
-  typedef SafeMap<std::string, SharedLibrary*>::iterator It; // TODO: C++0x auto
+  typedef SafeMap<std::string, SharedLibrary*>::const_iterator It; // TODO: C++0x auto
 
   SafeMap<std::string, SharedLibrary*> libraries_;
 };
@@ -2783,6 +2798,34 @@
   functions = enabled ? GetCheckJniInvokeInterface() : &gJniInvokeInterface;
 }
 
+void JavaVMExt::DumpForSigQuit(std::ostream& os) {
+  os << "JNI: CheckJNI is " << (check_jni ? "on" : "off");
+  if (force_copy) {
+    os << " (with forcecopy)";
+  }
+  os << "; workarounds are " << (work_around_app_jni_bugs ? "on" : "off");
+  {
+    MutexLock mu(pins_lock);
+    os << "; pins=" << pin_table.Size();
+  }
+  {
+    MutexLock mu(globals_lock);
+    os << "; globals=" << globals.Capacity();
+  }
+  {
+    MutexLock mu(weak_globals_lock);
+    if (weak_globals.Capacity() > 0) {
+      os << " (plus " << weak_globals.Capacity() << " weak)";
+    }
+  }
+  os << '\n';
+
+  {
+    MutexLock mu(libraries_lock);
+    os << "Libraries: " << Dumpable<Libraries>(*libraries) << " (" << libraries->size() << ")\n";
+  }
+}
+
 void JavaVMExt::DumpReferenceTables() {
   {
     MutexLock mu(globals_lock);
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 312b754..e12a7cd 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -26,6 +26,7 @@
 #include "reference_table.h"
 #include "runtime.h"
 
+#include <iosfwd>
 #include <string>
 
 namespace art {
@@ -97,6 +98,8 @@
    */
   void* FindCodeForNativeMethod(Method* m);
 
+  void DumpForSigQuit(std::ostream& os);
+
   void DumpReferenceTables();
 
   void SetCheckJniEnabled(bool enabled);
diff --git a/src/runtime.cc b/src/runtime.cc
index 8fe760e..18d40f5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -491,10 +491,6 @@
     parsed->heap_growth_limit_ = parsed->heap_maximum_size_;
   }
 
-  LOG(INFO) << "Build type: "
-            << (kIsDebugBuild ? "debug" : "optimized")
-            << "; CheckJNI: " << (parsed->check_jni_ ? "on" : "off");
-
   return parsed.release();
 }
 
@@ -754,6 +750,7 @@
 void Runtime::DumpForSigQuit(std::ostream& os) {
   GetClassLinker()->DumpForSigQuit(os);
   GetInternTable()->DumpForSigQuit(os);
+  GetJavaVM()->DumpForSigQuit(os);
   GetHeap()->DumpForSigQuit(os);
   os << "\n";
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index 5a9bf4e..0703b61 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -38,6 +38,14 @@
 
 namespace art {
 
+static bool ReadCmdLine(std::string& result) {
+  if (!ReadFileToString("/proc/self/cmdline", &result)) {
+    return false;
+  }
+  std::replace(result.begin(), result.end(), '\0', ' ');
+  return true;
+}
+
 SignalCatcher::SignalCatcher(const std::string& stack_trace_file)
     : stack_trace_file_(stack_trace_file),
       lock_("SignalCatcher lock"),
@@ -45,6 +53,10 @@
       thread_(NULL) {
   SetHaltFlag(false);
 
+  // Stash the original command line for SIGQUIT reporting.
+  // By then, /proc/self/cmdline will have been rewritten to something like "system_server".
+  CHECK(ReadCmdLine(cmd_line_));
+
   // Create a raw pthread; its start routine will attach to the runtime.
   CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Run, this), "signal catcher thread");
 
@@ -109,11 +121,17 @@
   os << "\n"
      << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
 
-  std::string cmdline;
-  if (ReadFileToString("/proc/self/cmdline", &cmdline)) {
-    std::replace(cmdline.begin(), cmdline.end(), '\0', ' ');
-    os << "Cmd line: " << cmdline << "\n";
+  std::string current_cmd_line;
+  if (ReadCmdLine(current_cmd_line) && current_cmd_line != cmd_line_) {
+    os << "Cmdline: " << current_cmd_line;
   }
+  os << "\n";
+
+  if (current_cmd_line != cmd_line_) {
+    os << "Original command line: " << cmd_line_ << "\n";
+  }
+
+  os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
 
   runtime->DumpForSigQuit(os);
 
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index 131b07c..da61ceb 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -52,6 +52,7 @@
   ConditionVariable cond_;
   pthread_t pthread_;
   Thread* thread_;
+  std::string cmd_line_;
 };
 
 }  // namespace art
diff --git a/src/thread_linux.cc b/src/thread_linux.cc
index 314668d..8eb8813 100644
--- a/src/thread_linux.cc
+++ b/src/thread_linux.cc
@@ -19,7 +19,7 @@
 namespace art {
 
 void Thread::DumpNativeStack(std::ostream&) const {
-  // TODO: use glibc backtrace(3).
+  // TODO: use libcorkscrew; backtrace(3) only works for the calling thread.
 }
 
 void Thread::SetNativePriority(int) {