summaryrefslogtreecommitdiffstats
path: root/chrome/app
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 01:18:35 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-28 01:18:35 +0000
commitabaa71c990b2d9dd514e9f2eefb1d2cf7b720562 (patch)
tree202c89d876e45f30c44132122f885877210230b7 /chrome/app
parentb80d5016c18ad5816bbff0698ff3407e77feabf1 (diff)
downloadchromium_src-abaa71c990b2d9dd514e9f2eefb1d2cf7b720562.zip
chromium_src-abaa71c990b2d9dd514e9f2eefb1d2cf7b720562.tar.gz
chromium_src-abaa71c990b2d9dd514e9f2eefb1d2cf7b720562.tar.bz2
Linux: add internal core dump reporting.
In order to get a handle on a number of browser crashes, this patch adds an options for Google internal folks to upload full core files when the browser crashes. The core files are uploaded to an internal IP address and will be available to other developers. This is only enabled for Chrome branded builds and then, only if --google-internal-crash-reporting is given on the command line. http://codereview.chromium.org/160212 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21782 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/app')
-rw-r--r--chrome/app/breakpad_linux.cc169
-rw-r--r--chrome/app/breakpad_linux.h15
-rw-r--r--chrome/app/chrome_dll_main.cc18
3 files changed, 202 insertions, 0 deletions
diff --git a/chrome/app/breakpad_linux.cc b/chrome/app/breakpad_linux.cc
index 199371e..c5dd0d3 100644
--- a/chrome/app/breakpad_linux.cc
+++ b/chrome/app/breakpad_linux.cc
@@ -4,9 +4,13 @@
#include "chrome/app/breakpad_linux.h"
+#include <arpa/inet.h>
#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/uio.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
@@ -15,11 +19,15 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/file_version_info_linux.h"
+#include "base/format_macros.h"
#include "base/global_descriptors_posix.h"
+#include "base/json_writer.h"
#include "base/linux_util.h"
#include "base/path_service.h"
#include "base/rand_util.h"
+#include "base/scoped_fd.h"
#include "base/string_util.h"
+#include "base/values.h"
#include "breakpad/linux/directory_reader.h"
#include "breakpad/linux/exception_handler.h"
#include "breakpad/linux/linux_libc_support.h"
@@ -618,3 +626,164 @@ void InitCrashReporter() {
EnableRendererCrashDumping();
}
}
+
+// -----------------------------------------------------------------------------
+
+bool EnableCoreDumping(std::string* core_dump_directory) {
+ // First we check that the core files will get dumped to the
+ // current-directory in a file called 'core'. We could try to support other
+ // setups by simulating the kernel's code, but it's extra complexity and we
+ // only intend for this code to be run internally.
+ static const char kCorePatternFd[] = "/proc/sys/kernel/core_pattern";
+
+ ScopedFd core_pattern_fd(open(kCorePatternFd, O_RDONLY));
+ if (core_pattern_fd.get() < 0) {
+ LOG(WARNING) << "Cannot open " << kCorePatternFd << ": " << strerror(errno);
+ return false;
+ }
+
+ char buf[6];
+ if (read(core_pattern_fd.get(), buf, sizeof(buf)) != 5 ||
+ memcmp(buf, "core\n", 5)) {
+ LOG(WARNING) << "Your core pattern is not set to 'core\n', cannot dump";
+ return false;
+ }
+ core_pattern_fd.Close();
+
+ // We check that the rlimit on core file size is unlimited.
+ struct rlimit core_dump_limit;
+ if (getrlimit(RLIMIT_CORE, &core_dump_limit)) {
+ LOG(WARNING) << "Failed to get core dump limit: " << strerror(errno);
+ return false;
+ }
+
+ if (core_dump_limit.rlim_cur != RLIM_INFINITY) {
+ if (core_dump_limit.rlim_max != RLIM_INFINITY) {
+ LOG(WARNING) << "Cannot core dump: hard limit on core dumps found";
+ return false;
+ }
+
+ core_dump_limit.rlim_cur = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_CORE, &core_dump_limit)) {
+ LOG(WARNING) << "Failed to set core dump limit: " << strerror(errno);
+ return false;
+ }
+ }
+
+ // Finally, we move the current directory into a temp dir and return the path
+ // to the temp dir so that we can clean up afterwards.
+ char temp_dir_template[] = "/tmp/chromium-core-dump-XXXXXX";
+ if (mkdtemp(temp_dir_template) == NULL) {
+ LOG(WARNING) << "Failed to create temp dir for core dumping: "
+ << strerror(errno);
+ return false;
+ }
+
+ if (chdir(temp_dir_template)) {
+ LOG(WARNING) << "Cannot chdir into temp directory: " << strerror(errno);
+ return false;
+ }
+
+ *core_dump_directory = temp_dir_template;
+
+ return true;
+}
+
+static void UploadCoreFile(const pid_t child, std::string* core_filename) {
+ *core_filename = "core";
+ ScopedFd fd(open(core_filename->c_str(), O_RDONLY));
+ if (fd.get() < 0) {
+ *core_filename = StringPrintf("core.%d", child);
+ fd.Set(open(core_filename->c_str(), O_RDONLY));
+ if (fd.get() < 0) {
+ LOG(WARNING) << "Cannot open resulting core dump from browser: "
+ << strerror(errno);
+ return;
+ }
+ }
+
+ struct stat st;
+ if (fstat(fd.get(), &st)) {
+ LOG(WARNING) << "Failed to stat core file: " << strerror(errno);
+ return;
+ }
+
+ const uint32_t core_size = st.st_size;
+
+ static const char kMyBinary[] = "/proc/self/exe";
+ ScopedFd self_fd(open(kMyBinary, O_RDONLY));
+ if (self_fd.get() < 0) {
+ LOG(WARNING) << "Cannot open " << kMyBinary << ": " << strerror(errno);
+ return;
+ }
+
+ if (fstat(self_fd.get(), &st)) {
+ LOG(WARNING) << "Failed to stat " << kMyBinary << ": " << strerror(errno);
+ return;
+ }
+
+ const uint64_t binary_size = st.st_size;
+
+ DictionaryValue header;
+ header.SetString(L"core-size", StringPrintf("%" PRIu32, core_size));
+ header.SetString(L"chrome-version", FILE_VERSION);
+ header.SetString(L"binary-size", StringPrintf("%" PRIu64, binary_size));
+ header.SetString(L"user", getenv("USER"));
+#if defined(GOOGLE_CHROME_BUILD)
+ header.SetBoolean(L"offical-build", true);
+#endif
+
+ std::string json;
+ JSONWriter::Write(&header, true /* pretty print */, &json);
+ const uint32_t json_size = json.size();
+
+ ScopedFd sock(socket(PF_INET, SOCK_STREAM, 0));
+ if (sock.get() < 0) {
+ LOG(WARNING) << "Cannot open socket: " << strerror(errno);
+ return;
+ }
+
+ static const char kUploadIP[] = "172.22.68.141";
+ static const uint16_t kUploadPort = 9999;
+
+ struct sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(kUploadIP);
+ sin.sin_port = htons(kUploadPort);
+
+ if (connect(sock.get(), (struct sockaddr*) &sin, sizeof(sin))) {
+ LOG(WARNING) << "Failed to connect to upload server (" << kUploadIP
+ << ":" << kUploadPort << "): " << strerror(errno);
+ return;
+ }
+
+ if (HANDLE_EINTR(write(sock.get(), &json_size, sizeof(json_size))) !=
+ static_cast<ssize_t>(sizeof(json_size)) ||
+ HANDLE_EINTR(write(sock.get(), json.data(), json_size)) !=
+ static_cast<ssize_t>(json_size) ||
+ HANDLE_EINTR(write(sock.get(), &core_size, sizeof(core_size))) !=
+ static_cast<ssize_t>(sizeof(core_size)) ||
+ HANDLE_EINTR(sendfile(sock.get(), fd.get(), NULL, core_size)) !=
+ static_cast<ssize_t>(core_size)) {
+ LOG(WARNING) << "Failed to write all data to server";
+ return;
+ }
+}
+
+void MonitorForCoreDumpsAndReport(const std::string& core_dump_directory,
+ const pid_t child) {
+ int status;
+ const pid_t result = HANDLE_EINTR(waitpid(child, &status, 0));
+ if (result < 1) {
+ LOG(ERROR) << "Failed to wait for browser child: " << strerror(errno);
+ return;
+ }
+
+ if (WIFSIGNALED(status) && WCOREDUMP(status)) {
+ std::string core_filename;
+ UploadCoreFile(child, &core_filename);
+ unlink(core_filename.c_str());
+ }
+
+ rmdir(core_dump_directory.c_str());
+}
diff --git a/chrome/app/breakpad_linux.h b/chrome/app/breakpad_linux.h
index 518cf42..0c3ccde 100644
--- a/chrome/app/breakpad_linux.h
+++ b/chrome/app/breakpad_linux.h
@@ -5,6 +5,8 @@
#ifndef CHROME_APP_BREAKPAD_LINUX_H_
#define CHROME_APP_BREAKPAD_LINUX_H_
+#include <string>
+
extern void InitCrashReporter();
#if defined(GOOGLE_CHROME_BUILD)
@@ -25,6 +27,19 @@ struct BreakpadInfo {
};
extern int UploadCrashDump(const BreakpadInfo& info);
+
+// Checks that the kernel's core filename pattern is "core" and moves the
+// current working directory to a temp directory.
+// Returns true iff core dumping has been successfully enabled for the current
+// process.
+bool EnableCoreDumping(std::string* core_dump_directory);
+// Blocks until the given child has exited. If the kernel indicates that the
+// child dumped core, then the core is expected a file called "core" and is
+// uploaded to a collection server. The core file is deleted and the given
+// directory is removed.
+void MonitorForCoreDumpsAndReport(const std::string& core_dump_directory,
+ const pid_t child);
+
#endif // defined(GOOGLE_CHROME_BUILD)
#endif // CHROME_APP_BREAKPAD_LINUX_H_
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc
index 652217e..b375474 100644
--- a/chrome/app/chrome_dll_main.cc
+++ b/chrome/app/chrome_dll_main.cc
@@ -51,6 +51,9 @@
#if defined(OS_MACOSX)
#include "chrome/app/breakpad_mac.h"
#endif
+#if defined(OS_LINUX)
+#include "chrome/app/breakpad_linux.h"
+#endif
#include "chrome/app/scoped_ole_initializer.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
@@ -346,6 +349,21 @@ int ChromeMain(int argc, const char** argv) {
int ret = execlp("man", "man", binary.BaseName().value().c_str(), NULL);
LOG(FATAL) << "execlp failed: " << strerror(ret);
}
+
+#if defined(GOOGLE_CHROME_BUILD)
+ if (parsed_command_line.HasSwitch(switches::kGoogleInternalCrashReporting)) {
+ // Enable full core dump reporting. Internal only.
+ std::string core_dump_directory;
+ if (EnableCoreDumping(&core_dump_directory)) {
+ LOG(WARNING) << "Full core dump reporting enabled.";
+ const pid_t child = fork();
+ if (child != 0) {
+ MonitorForCoreDumpsAndReport(core_dump_directory, child);
+ _exit(0);
+ }
+ }
+ }
+#endif
#endif
#if defined(OS_POSIX)