blob: a61339b3f204083864bf66666225c1ac662ec443 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The chrome collector collects crashes from the chrome binary.
// It's a bit special - instead of the kernel running it through
// /proc/sys/kernel/core_pattern, chrome invokes it directly and passes in a
// crash dump generated by Crashpad or the JavaScript error reporting system.
#ifndef CRASH_REPORTER_CHROME_COLLECTOR_H_
#define CRASH_REPORTER_CHROME_COLLECTOR_H_
#include <map>
#include <memory>
#include <string>
#include <base/files/file_path.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "crash-reporter/crash_collector.h"
// Chrome crash collector.
class ChromeCollector : public CrashCollector {
public:
explicit ChromeCollector(CrashSendingMode crash_sending_mode);
ChromeCollector(const ChromeCollector&) = delete;
ChromeCollector& operator=(const ChromeCollector&) = delete;
~ChromeCollector() override;
// Magic string to let Chrome know the crash report succeeded.
static const char kSuccessMagic[];
// Handle a specific chrome crash. Returns true on success.
bool HandleCrash(const base::FilePath& dump_file_path,
pid_t pid,
uid_t uid,
const std::string& exe_name);
// Handle a specific chrome crash through a memfd instead of a file.
// Returns true on success.
bool HandleCrashThroughMemfd(int memfd,
pid_t pid,
uid_t uid,
const std::string& executable_name,
const std::string& non_exe_error_key,
const std::string& dump_dir);
static CollectorInfo GetHandlerInfo(CrashSendingMode mode,
const std::string& dump_file_path,
int memfd,
pid_t pid,
uid_t uid,
const std::string& executable_name,
const std::string& non_exe_error_key,
const std::string& chrome_dump_dir);
void set_max_upload_bytes_for_test(int max_upload_bytes) {
max_upload_bytes_ = max_upload_bytes;
}
private:
friend class ChromeCollectorTest;
FRIEND_TEST(ChromeCollectorTest, GoodValues);
FRIEND_TEST(ChromeCollectorTest, GoodLacros);
FRIEND_TEST(ChromeCollectorTest, ParseCrashLogNoDump);
FRIEND_TEST(ChromeCollectorTest, ParseCrashLogJSStack);
FRIEND_TEST(ChromeCollectorTest, BadValues);
FRIEND_TEST(ChromeCollectorTest, Newlines);
FRIEND_TEST(ChromeCollectorTest, File);
FRIEND_TEST(ChromeCollectorTest, HandleCrash);
FRIEND_TEST(ChromeCollectorTest, HandleCrashWithEmbeddedNuls);
FRIEND_TEST(ChromeCollectorTest, HandleCrashWithWeirdFilename);
enum CrashType {
// An executable received a signal like SIGSEGV or SIGILL; the sort of thing
// that would lead to a core file on Linux. (Also covers Chrome's
// DumpWithoutCrashing function.)
kExecutableCrash,
// A JavaScript error is being reported.
kJavaScriptError
};
// Handle a specific chrome crash with dump data.
// Returns true on success.
bool HandleCrashWithDumpData(const std::string& data,
pid_t pid,
uid_t uid,
const std::string& executable_name,
const std::string& non_exe_error_key,
const std::string& dump_dir);
// Crashes are expected to be in a TLV-style format of:
// <name>:<length>:<value>
// Length is encoded as a decimal number. It can be zero, but must consist of
// at least one character
// For file values, name actually contains both a description and a filename,
// in a fixed format of: <description>"; filename="<filename>".
// The path to the payload (minidump or JS Exception) will be written to
// |payload|.
bool ParseCrashLog(const std::string& data,
const base::FilePath& dir,
const std::string& basename,
CrashType crash_type,
base::FilePath* payload,
bool* is_lacros_crash);
// Some classes of JavaScript errors do not have stacks. Since crash_sender
// cannot send error reports without a payload, create a simple payload that
// just states there was no stack.
bool CreateNoStackJSPayload(const base::FilePath& dir,
const std::string& dump_basename,
base::FilePath* payload_path);
// Callback for the call to debugd to get the DriErrorState. Debugd sends us
// the data in |dri_error_state_str|, which we then write to
// |dri_error_state_path|. On success, the (metadata key name, base file name)
// pair is added to |logs|. Regardless of success or failure,
// |completion_closure| is called once we are finished.
void HandleDriErrorState(base::FilePath dri_error_state_path,
std::map<std::string, base::FilePath>* logs,
base::RepeatingClosure completion_closure,
const std::string& dri_error_state_str);
// Helper for HandleDriErrorState. Decodes the information from debugd in
// |dri_error_state_str| and writes it to |error_state_path|. Separate
// function to make error handling easier. Returns true on success.
bool ProcessDriErrorState(const std::string& dri_error_state_str,
const base::FilePath& error_state_path);
// Callback if the debugd call to get DriErrorState fails. |error| is nullptr
// if the call never returned (normally means it timed out), otherwise it has
// the failure reason.
static void HandleDriErrorStateError(
base::RepeatingClosure completion_closure, brillo::Error* error);
// Callback for the call to debugd to get dmesg output. Debugd sends us
// the dmesg output in |dmesg_out|, which we then write to |dmseg_path|.
// On success, the (metadata key name, base file name) pair is added to
// |logs|. Regardless of success or failure, |completion_closure| is called
// once we are finished.
void HandleDmesg(base::FilePath dmseg_path,
std::map<std::string, base::FilePath>* logs,
base::RepeatingClosure completion_closure,
const std::string& dmesg_out);
// Helper for HandleDmesg. Strips out any sensitive data in |dmesg_out| and
// then writes it to |dmseg_path|. Separate function to make error handling
// easier. Returns true on success.
bool ProcessDmesgOutput(std::string dmesg_out,
const base::FilePath& dmseg_path);
// Callback if the debugd call to get dmesg output. |error| is nullptr
// if the call never returned (normally means it timed out), otherwise it has
// the failure reason.
static void HandleDmesgError(base::RepeatingClosure completion_closure,
brillo::Error* error);
// Writes additional logs for the crash to files based on |basename| within
// |dir|. |key_for_logs| is the key into crash_reporter_logs.conf file. Crash
// report metadata key names and the corresponding file names are returned.
std::map<std::string, base::FilePath> GetAdditionalLogs(
const base::FilePath& dir,
const std::string& basename,
const std::string& key_for_logs,
CrashType crash_type);
// Add the (|log_map_key|, base file name) pair to |logs| if we are not
// over kDefaultMaxUploadBytes. If we are over kDefaultMaxUploadBytes,
// delete the file |complete_file_name| instead and don't change |logs|.
// |complete_file_name| must be a file created by
// CrashCollector::WriteNewFile() or CrashCollector::WriteNewCompressedFile()
// so that CrashCollector::RemoveNewFile() works on it.
void AddLogIfNotTooBig(const char* log_map_key,
const base::FilePath& complete_file_name,
std::map<std::string, base::FilePath>* logs);
// The file where we write our special "done" marker (to indicate to Chrome
// that we are finished dumping). Always stdout in production.
FILE* output_file_ptr_;
// We skip uploading the supplemental files (logs, i915_error_state) if it
// would make the report larger than max_upload_bytes_. In production, this
// is always kDefaultMaxUploadBytes.
int max_upload_bytes_;
};
#endif // CRASH_REPORTER_CHROME_COLLECTOR_H_