Handle Chrome crashes

Chrome will be modified to pass crashes to crash_reporter via a specially
formatted file, a TLV-style designed to be easily parsed, instead of
multipart/form-data. Extra attributes are added into the .meta file.

BUG=chromium:187808
TEST=new unit tests created

Change-Id: I0d65d118e0e348329d14bb4004c8f7bad5a44a97
Reviewed-on: https://gerrit.chromium.org/gerrit/49972
Reviewed-by: Chris Masone <cmasone@chromium.org>
Commit-Queue: Albert Chaulk <achaulk@chromium.org>
Tested-by: Albert Chaulk <achaulk@chromium.org>
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 990ef03..85c0933 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -226,6 +226,66 @@
   return true;
 }
 
+FilePath CrashCollector::GetProcessPath(pid_t pid) {
+  return FilePath(StringPrintf("/proc/%d", pid));
+}
+
+bool CrashCollector::GetSymlinkTarget(const FilePath &symlink,
+                                     FilePath *target) {
+  int max_size = 32;
+  scoped_array<char> buffer;
+  while (true) {
+    buffer.reset(new char[max_size + 1]);
+    ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size);
+    if (size < 0) {
+      int saved_errno = errno;
+      LOG(ERROR) << "Readlink failed on " << symlink.value() << " with "
+                 << saved_errno;
+      return false;
+    }
+    buffer[size] = 0;
+    if (size == max_size) {
+      // Avoid overflow when doubling.
+      if (max_size * 2 > max_size) {
+        max_size *= 2;
+        continue;
+      } else {
+        return false;
+      }
+    }
+    break;
+  }
+
+  *target = FilePath(buffer.get());
+  return true;
+}
+
+bool CrashCollector::GetExecutableBaseNameFromPid(pid_t pid,
+                                                 std::string *base_name) {
+  FilePath target;
+  FilePath process_path = GetProcessPath(pid);
+  FilePath exe_path = process_path.Append("exe");
+  if (!GetSymlinkTarget(exe_path, &target)) {
+    LOG(INFO) << "GetSymlinkTarget failed - Path " << process_path.value()
+              << " DirectoryExists: "
+              << file_util::DirectoryExists(process_path);
+    // Try to further diagnose exe readlink failure cause.
+    struct stat buf;
+    int stat_result = stat(exe_path.value().c_str(), &buf);
+    int saved_errno = errno;
+    if (stat_result < 0) {
+      LOG(INFO) << "stat " << exe_path.value() << " failed: " << stat_result
+                << " " << saved_errno;
+    } else {
+      LOG(INFO) << "stat " << exe_path.value() << " succeeded: st_mode="
+                << buf.st_mode;
+    }
+    return false;
+  }
+  *base_name = target.BaseName().value();
+  return true;
+}
+
 // Return true if the given crash directory has not already reached
 // maximum capacity.
 bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {