"InitGoogle"-style argv stashing.

This lets us give the command line in crash dumps when dex2oat dies in the
continuous build on the Mac. I've also taken the opportunity to use the
basename of argv[0] as the default log tag, so dex2oat will now show up in
logcat as "dex2oat" instead of "art" (and we can probably stop manually
prefixing dex2oat log output).

Also stash pthread_self() so we can _correctly_ report "handle=" in the
SIGQUIT output.

Change-Id: Ia8249cd19bab5b816cb94a531a65becdfacaa98b
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 418bf3c..088cb45 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -449,7 +449,7 @@
 }
 
 static int dex2oat(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
 
   // Skip over argv[0].
   argv++;
diff --git a/src/logging.cc b/src/logging.cc
index 7d176a2..86c8bdf 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -24,14 +24,28 @@
 
 LogVerbosity gLogVerbosity;
 
-static bool gInitLoggingCalled = false;
 static LogSeverity gMinimumLogSeverity = INFO;
+static std::string* gCmdLine;
+static std::string* gProgramInvocationName;
+static std::string* gProgramInvocationShortName;
 
 static Mutex& GetLoggingLock() {
   static Mutex logging_lock("LogMessage lock");
   return logging_lock;
 }
 
+const char* GetCmdLine() {
+  return (gCmdLine != NULL) ? gCmdLine->c_str() : NULL;
+}
+
+const char* ProgramInvocationName() {
+  return (gProgramInvocationName != NULL) ? gProgramInvocationName->c_str() : "art";
+}
+
+const char* ProgramInvocationShortName() {
+  return (gProgramInvocationShortName != NULL) ? gProgramInvocationShortName->c_str() : "art";
+}
+
 // Configure logging based on ANDROID_LOG_TAGS environment variable.
 // We need to parse a string that looks like
 //
@@ -40,8 +54,19 @@
 // The tag (or '*' for the global level) comes first, followed by a colon
 // and a letter indicating the minimum priority level we're expected to log.
 // This can be used to reveal or conceal logs with specific tags.
-void InitLogging() {
-  gInitLoggingCalled = true;
+void InitLogging(char* argv[]) {
+  // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
+  // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
+  // commonly used.
+  gCmdLine = new std::string(argv[0]);
+  for (size_t i = 1; argv[i] != NULL; ++i) {
+    gCmdLine->append(" ");
+    gCmdLine->append(argv[i]);
+  }
+  gProgramInvocationName = new std::string(argv[0]);
+  const char* last_slash = strrchr(argv[0], '/');
+  gProgramInvocationShortName = new std::string((last_slash != NULL) ? last_slash + 1 : argv[0]);
+
   const char* tags = getenv("ANDROID_LOG_TAGS");
   if (tags == NULL) {
     return;
diff --git a/src/logging.h b/src/logging.h
index 337f12e..f7b687b 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -265,7 +265,11 @@
 };
 
 extern LogVerbosity gLogVerbosity;
-extern void InitLogging();
+extern void InitLogging(char* argv[]);
+
+extern const char* GetCmdLine();
+extern const char* ProgramInvocationName();
+extern const char* ProgramInvocationShortName();
 
 }  // namespace art
 
diff --git a/src/logging_android.cc b/src/logging_android.cc
index 8ba61f1..7007d7a 100644
--- a/src/logging_android.cc
+++ b/src/logging_android.cc
@@ -36,11 +36,12 @@
 }
 
 void LogMessage::LogLine(const char* message) {
+  const char* tag = ProgramInvocationShortName();
   int priority = kLogSeverityToAndroidLogPriority[data_->severity];
   if (priority == ANDROID_LOG_FATAL) {
-    LOG_PRI(priority, "art", "%s:%d] %s", data_->file, data_->line_number, message);
+    LOG_PRI(priority, tag, "%s:%d] %s", data_->file, data_->line_number, message);
   } else {
-    LOG_PRI(priority, "art", "%s", message);
+    LOG_PRI(priority, tag, "%s", message);
   }
 }
 
diff --git a/src/logging_linux.cc b/src/logging_linux.cc
index 5bb8764..0d7fc0b 100644
--- a/src/logging_linux.cc
+++ b/src/logging_linux.cc
@@ -35,7 +35,8 @@
 
 void LogMessage::LogLine(const char* message) {
   char severity = "VDIWEFF"[data_->severity];
-  fprintf(stderr, "%c %5d %5d %s:%d] %s\n", severity, getpid(), ::art::GetTid(),
+  fprintf(stderr, "%s %c %5d %5d %s:%d] %s\n",
+          ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(),
           data_->file, data_->line_number, message);
 }
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 1348df1..8dd4e45 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -1133,7 +1133,7 @@
 };
 
 static int oatdump(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
 
   // Skip over argv[0].
   argv++;
diff --git a/src/oatexec.cc b/src/oatexec.cc
index e8e2050..49c0706 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -102,7 +102,7 @@
 // Parse arguments.  Most of it just gets passed through to the runtime.
 // The JNI spec defines a handful of standard arguments.
 static int oatexec(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
   setvbuf(stdout, NULL, _IONBF, 0);
 
   // Skip over argv[0].
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index 95f183f..a4bdacc 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -233,6 +233,7 @@
                       signal_number == SIGFPE || signal_number == SIGSEGV);
 
   OS os_info;
+
   UContext thread_context(raw_context);
   Backtrace thread_backtrace;
 
@@ -243,6 +244,7 @@
                                       GetSignalCodeName(signal_number, info->si_code))
                       << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << "\n"
                       << "OS: " << Dumpable<OS>(os_info) << "\n"
+                      << "Cmdline: " << GetCmdLine() << "\n"
                       << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
                       << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index 33600ba..5c7a30f 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -36,21 +36,28 @@
 #include "thread_list.h"
 #include "utils.h"
 
-#if !defined(__APPLE__)
-#define HAVE_PROC_CMDLINE
-#endif
-
 namespace art {
 
-#if defined(HAVE_PROC_CMDLINE)
-static bool ReadCmdLine(std::string& result) {
-  if (!ReadFileToString("/proc/self/cmdline", &result)) {
-    return false;
+static void DumpCmdLine(std::ostream& os) {
+#if defined(__linux__)
+  // Show the original command line, and the current command line too if it's changed.
+  // On Android, /proc/self/cmdline will have been rewritten to something like "system_server".
+  std::string current_cmd_line;
+  if (ReadFileToString("/proc/self/cmdline", &current_cmd_line)) {
+    current_cmd_line.resize(current_cmd_line.size() - 1); // Lose the trailing '\0'.
+    std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
+
+    os << "Cmdline: " << current_cmd_line;
+    const char* stashed_cmd_line = GetCmdLine();
+    if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line) {
+      os << "Original command line: " << stashed_cmd_line;
+    }
   }
-  std::replace(result.begin(), result.end(), '\0', ' ');
-  return true;
-}
+  os << "\n";
+#else
+  os << "Cmdline: " << GetCmdLine() << "\n";
 #endif
+}
 
 SignalCatcher::SignalCatcher(const std::string& stack_trace_file)
     : stack_trace_file_(stack_trace_file),
@@ -59,12 +66,6 @@
       thread_(NULL) {
   SetHaltFlag(false);
 
-#if defined(HAVE_PROC_CMDLINE)
-  // 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_));
-#endif
-
   // Create a raw pthread; its start routine will attach to the runtime.
   CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Run, this), "signal catcher thread");
 
@@ -129,17 +130,7 @@
   os << "\n"
      << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
 
-#if defined(HAVE_PROC_CMDLINE)
-  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";
-  }
-#endif
+  DumpCmdLine(os);
 
   os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
 
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index da61ceb..131b07c 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -52,7 +52,6 @@
   ConditionVariable cond_;
   pthread_t pthread_;
   Thread* thread_;
-  std::string cmd_line_;
 };
 
 }  // namespace art
diff --git a/src/thread.cc b/src/thread.cc
index d854c3b..e1764ef 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -250,6 +250,7 @@
   CHECK(runtime != NULL);
 
   thin_lock_id_ = runtime->GetThreadList()->AllocThreadId();
+  pthread_self_ = pthread_self();
 
   InitTid();
   InitStackHwm();
@@ -457,10 +458,6 @@
     priority = GetNativePriority();
   }
 
-  int policy;
-  sched_param sp;
-  CHECK_PTHREAD_CALL(pthread_getschedparam, (pthread_self(), &policy, &sp), __FUNCTION__);
-
   std::string scheduler_group_name(GetSchedulerGroupName(tid));
   if (scheduler_group_name.empty()) {
     scheduler_group_name = "default";
@@ -483,7 +480,6 @@
     }
     os << '"' << thread_name << '"'
        << " prio=" << priority
-       << " tid=?"
        << " (not attached)\n";
   }
 
@@ -494,12 +490,18 @@
        << " obj=" << reinterpret_cast<void*>(thread->peer_)
        << " self=" << reinterpret_cast<const void*>(thread) << "\n";
   }
+
   os << "  | sysTid=" << tid
      << " nice=" << getpriority(PRIO_PROCESS, tid)
-     << " sched=" << policy << "/" << sp.sched_priority
-     << " cgrp=" << scheduler_group_name << "\n";
-
-  // TODO: fix this; it's never worked in art! << " handle=" << pthread_self() << "\n";
+     << " cgrp=" << scheduler_group_name;
+  if (thread != NULL) {
+    int policy;
+    sched_param sp;
+    CHECK_PTHREAD_CALL(pthread_getschedparam, (thread->pthread_self_, &policy, &sp), __FUNCTION__);
+    os << " sched=" << policy << "/" << sp.sched_priority
+       << " handle=" << reinterpret_cast<void*>(thread->pthread_self_);
+  }
+  os << "\n";
 
   // Grab the scheduler stats for this thread.
   std::string scheduler_stats;
diff --git a/src/thread.h b/src/thread.h
index 7d885c0..6a2b27e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -643,6 +643,9 @@
   // A cached copy of the java.lang.Thread's name.
   std::string* name_;
 
+  // A cached pthread_t for the pthread underlying this Thread*.
+  pthread_t pthread_self_;
+
   uint32_t held_mutexes_[kMaxMutexRank + 1];
 
  public:
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 3d0e0be..0dc06f8 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -86,8 +86,8 @@
   }
 
   dirent de;
-  dirent* result;
-  while (!readdir_r(d, &de, &result) && result != NULL) {
+  dirent* e;
+  while (!readdir_r(d, &de, &e) && e != NULL) {
     char* end;
     pid_t tid = strtol(de.d_name, &end, 10);
     if (!*end && !Contains(tid)) {