mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
[log minidump] add option to log minidump in handler_main
- Add option to log minidump in handler_main, also add option to disable to dump minidump and generate report. - Implement log minidump in CrashReportExceptionHandler. Bug: crashpad:308 Change-Id: I8d2f7e118912011a8416f1ec36c9ee9d561d06e6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1995825 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
f36f46d1ec
commit
915862984c
@ -233,6 +233,12 @@ establish the Crashpad client environment before running a program.
|
|||||||
for use with collection servers that don’t accept uploads compressed in this
|
for use with collection servers that don’t accept uploads compressed in this
|
||||||
way.
|
way.
|
||||||
|
|
||||||
|
* **--no-write-minidump-to-database**
|
||||||
|
|
||||||
|
Do not write the minidump to database. Normally, the minidump is written to
|
||||||
|
database for upload. Use this option with **--write-minidump-to-log** to
|
||||||
|
only write the minidump to log. This option is only available to Android.
|
||||||
|
|
||||||
* **--pipe-name**=_PIPE_
|
* **--pipe-name**=_PIPE_
|
||||||
|
|
||||||
Listen on the given pipe name for connections from clients. _PIPE_ must be of
|
Listen on the given pipe name for connections from clients. _PIPE_ must be of
|
||||||
@ -286,6 +292,12 @@ establish the Crashpad client environment before running a program.
|
|||||||
is still used for Crashpad settings. This option is only valid on Chromium
|
is still used for Crashpad settings. This option is only valid on Chromium
|
||||||
OS.
|
OS.
|
||||||
|
|
||||||
|
* **--write-minidump-to-log**
|
||||||
|
|
||||||
|
Write the minidump to log. By default the minidump is only written to
|
||||||
|
database. Use this option with **--no-write-minidump-to-database** to only
|
||||||
|
write the minidump to log. This option is only available to Android.
|
||||||
|
|
||||||
* **--help**
|
* **--help**
|
||||||
|
|
||||||
Display help and exit.
|
Display help and exit.
|
||||||
|
@ -143,6 +143,10 @@ void Usage(const base::FilePath& me) {
|
|||||||
" --no-periodic-tasks don't scan for new reports or prune the database\n"
|
" --no-periodic-tasks don't scan for new reports or prune the database\n"
|
||||||
" --no-rate-limit don't rate limit crash uploads\n"
|
" --no-rate-limit don't rate limit crash uploads\n"
|
||||||
" --no-upload-gzip don't use gzip compression when uploading\n"
|
" --no-upload-gzip don't use gzip compression when uploading\n"
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
" --no-write-minidump-to-database\n"
|
||||||
|
" don't write minidump to database\n"
|
||||||
|
#endif // OS_ANDROID
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
" --pipe-name=PIPE communicate with the client over PIPE\n"
|
" --pipe-name=PIPE communicate with the client over PIPE\n"
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
@ -173,6 +177,9 @@ void Usage(const base::FilePath& me) {
|
|||||||
" crash_reporter, thus skipping metrics consent\n"
|
" crash_reporter, thus skipping metrics consent\n"
|
||||||
" checks\n"
|
" checks\n"
|
||||||
#endif // OS_CHROMEOS
|
#endif // OS_CHROMEOS
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
" --write-minidump-to-log write minidump to log\n"
|
||||||
|
#endif // OS_ANDROID
|
||||||
" --help display this help and exit\n"
|
" --help display this help and exit\n"
|
||||||
" --version output version information and exit\n",
|
" --version output version information and exit\n",
|
||||||
me.value().c_str());
|
me.value().c_str());
|
||||||
@ -195,6 +202,10 @@ struct Options {
|
|||||||
VMAddress sanitization_information_address;
|
VMAddress sanitization_information_address;
|
||||||
int initial_client_fd;
|
int initial_client_fd;
|
||||||
bool shared_client_connection;
|
bool shared_client_connection;
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
bool write_minidump_to_log;
|
||||||
|
bool write_minidump_to_database;
|
||||||
|
#endif // OS_ANDROID
|
||||||
#elif defined(OS_WIN)
|
#elif defined(OS_WIN)
|
||||||
std::string pipe_name;
|
std::string pipe_name;
|
||||||
InitialClientData initial_client_data;
|
InitialClientData initial_client_data;
|
||||||
@ -551,6 +562,9 @@ int HandlerMain(int argc,
|
|||||||
kOptionNoPeriodicTasks,
|
kOptionNoPeriodicTasks,
|
||||||
kOptionNoRateLimit,
|
kOptionNoRateLimit,
|
||||||
kOptionNoUploadGzip,
|
kOptionNoUploadGzip,
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
kOptionNoWriteMinidumpToDatabase,
|
||||||
|
#endif // OS_ANDROID
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
kOptionPipeName,
|
kOptionPipeName,
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
@ -568,6 +582,9 @@ int HandlerMain(int argc,
|
|||||||
kOptionMinidumpDirForTests,
|
kOptionMinidumpDirForTests,
|
||||||
kOptionAlwaysAllowFeedback,
|
kOptionAlwaysAllowFeedback,
|
||||||
#endif // OS_CHROMEOS
|
#endif // OS_CHROMEOS
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
kOptionWriteMinidumpToLog,
|
||||||
|
#endif // OS_ANDROID
|
||||||
|
|
||||||
// Standard options.
|
// Standard options.
|
||||||
kOptionHelp = -2,
|
kOptionHelp = -2,
|
||||||
@ -609,6 +626,12 @@ int HandlerMain(int argc,
|
|||||||
{"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
|
{"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
|
||||||
{"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
|
{"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
|
||||||
{"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
|
{"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
{"no-write-minidump-to-database",
|
||||||
|
no_argument,
|
||||||
|
nullptr,
|
||||||
|
kOptionNoWriteMinidumpToDatabase},
|
||||||
|
#endif // OS_ANDROID
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
{"pipe-name", required_argument, nullptr, kOptionPipeName},
|
{"pipe-name", required_argument, nullptr, kOptionPipeName},
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
@ -647,6 +670,9 @@ int HandlerMain(int argc,
|
|||||||
nullptr,
|
nullptr,
|
||||||
kOptionAlwaysAllowFeedback},
|
kOptionAlwaysAllowFeedback},
|
||||||
#endif // OS_CHROMEOS
|
#endif // OS_CHROMEOS
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
{"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog},
|
||||||
|
#endif // OS_ANDROID
|
||||||
{"help", no_argument, nullptr, kOptionHelp},
|
{"help", no_argument, nullptr, kOptionHelp},
|
||||||
{"version", no_argument, nullptr, kOptionVersion},
|
{"version", no_argument, nullptr, kOptionVersion},
|
||||||
{nullptr, 0, nullptr, 0},
|
{nullptr, 0, nullptr, 0},
|
||||||
@ -663,6 +689,9 @@ int HandlerMain(int argc,
|
|||||||
options.periodic_tasks = true;
|
options.periodic_tasks = true;
|
||||||
options.rate_limit = true;
|
options.rate_limit = true;
|
||||||
options.upload_gzip = true;
|
options.upload_gzip = true;
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
options.write_minidump_to_database = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
||||||
@ -749,6 +778,12 @@ int HandlerMain(int argc,
|
|||||||
options.upload_gzip = false;
|
options.upload_gzip = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
case kOptionNoWriteMinidumpToDatabase: {
|
||||||
|
options.write_minidump_to_database = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif // OS_ANDROID
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
case kOptionPipeName: {
|
case kOptionPipeName: {
|
||||||
options.pipe_name = optarg;
|
options.pipe_name = optarg;
|
||||||
@ -803,6 +838,12 @@ int HandlerMain(int argc,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif // OS_CHROMEOS
|
#endif // OS_CHROMEOS
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
case kOptionWriteMinidumpToLog: {
|
||||||
|
options.write_minidump_to_log = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif // OS_ANDROID
|
||||||
case kOptionHelp: {
|
case kOptionHelp: {
|
||||||
Usage(me);
|
Usage(me);
|
||||||
MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
|
MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
|
||||||
@ -863,6 +904,14 @@ int HandlerMain(int argc,
|
|||||||
me, "--shared-client-connection requires --initial-client-fd");
|
me, "--shared-client-connection requires --initial-client-fd");
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
|
#if defined(OS_ANDROID)
|
||||||
|
if (!options.write_minidump_to_log && !options.write_minidump_to_database) {
|
||||||
|
ToolSupport::UsageHint(me,
|
||||||
|
"--no_write_minidump_to_database is required to use "
|
||||||
|
"with --write_minidump_to_log.");
|
||||||
|
ExitFailure();
|
||||||
|
}
|
||||||
|
#endif // OS_ANDROID
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
|
|
||||||
if (options.database.empty()) {
|
if (options.database.empty()) {
|
||||||
@ -966,8 +1015,17 @@ int HandlerMain(int argc,
|
|||||||
// TODO(scottmg): Process level file attachments, and for all platforms.
|
// TODO(scottmg): Process level file attachments, and for all platforms.
|
||||||
nullptr,
|
nullptr,
|
||||||
#endif
|
#endif
|
||||||
user_stream_sources);
|
#if defined(OS_ANDROID)
|
||||||
|
options.write_minidump_to_database,
|
||||||
|
options.write_minidump_to_log,
|
||||||
|
#endif // OS_ANDROID
|
||||||
|
#if defined(OS_LINUX)
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
#endif // OS_LINUX
|
||||||
#endif // OS_CHROMEOS
|
#endif // OS_CHROMEOS
|
||||||
|
user_stream_sources);
|
||||||
|
|
||||||
|
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
if (options.exception_information_address) {
|
if (options.exception_information_address) {
|
||||||
|
@ -23,23 +23,56 @@
|
|||||||
#include "minidump/minidump_file_writer.h"
|
#include "minidump/minidump_file_writer.h"
|
||||||
#include "snapshot/linux/process_snapshot_linux.h"
|
#include "snapshot/linux/process_snapshot_linux.h"
|
||||||
#include "snapshot/sanitized/process_snapshot_sanitized.h"
|
#include "snapshot/sanitized/process_snapshot_sanitized.h"
|
||||||
|
#include "util/file/file_reader.h"
|
||||||
|
#include "util/file/output_stream_file_writer.h"
|
||||||
#include "util/linux/direct_ptrace_connection.h"
|
#include "util/linux/direct_ptrace_connection.h"
|
||||||
#include "util/linux/ptrace_client.h"
|
#include "util/linux/ptrace_client.h"
|
||||||
#include "util/misc/implicit_cast.h"
|
#include "util/misc/implicit_cast.h"
|
||||||
#include "util/misc/metrics.h"
|
#include "util/misc/metrics.h"
|
||||||
#include "util/misc/uuid.h"
|
#include "util/misc/uuid.h"
|
||||||
|
#include "util/stream/base94_output_stream.h"
|
||||||
|
#include "util/stream/log_output_stream.h"
|
||||||
|
#include "util/stream/zlib_output_stream.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool WriteMinidumpLogFromFile(FileReaderInterface* file_reader) {
|
||||||
|
ZlibOutputStream stream(ZlibOutputStream::Mode::kCompress,
|
||||||
|
std::make_unique<Base94OutputStream>(
|
||||||
|
Base94OutputStream::Mode::kEncode,
|
||||||
|
std::make_unique<LogOutputStream>()));
|
||||||
|
FileOperationResult read_result;
|
||||||
|
do {
|
||||||
|
uint8_t buffer[4096];
|
||||||
|
read_result = file_reader->Read(buffer, sizeof(buffer));
|
||||||
|
if (read_result < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (read_result > 0 && (!stream.Write(buffer, read_result)))
|
||||||
|
return false;
|
||||||
|
} while (read_result > 0);
|
||||||
|
return stream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
CrashReportExceptionHandler::CrashReportExceptionHandler(
|
CrashReportExceptionHandler::CrashReportExceptionHandler(
|
||||||
CrashReportDatabase* database,
|
CrashReportDatabase* database,
|
||||||
CrashReportUploadThread* upload_thread,
|
CrashReportUploadThread* upload_thread,
|
||||||
const std::map<std::string, std::string>* process_annotations,
|
const std::map<std::string, std::string>* process_annotations,
|
||||||
|
bool write_minidump_to_database,
|
||||||
|
bool write_minidump_to_log,
|
||||||
const UserStreamDataSources* user_stream_data_sources)
|
const UserStreamDataSources* user_stream_data_sources)
|
||||||
: database_(database),
|
: database_(database),
|
||||||
upload_thread_(upload_thread),
|
upload_thread_(upload_thread),
|
||||||
process_annotations_(process_annotations),
|
process_annotations_(process_annotations),
|
||||||
user_stream_data_sources_(user_stream_data_sources) {}
|
write_minidump_to_database_(write_minidump_to_database),
|
||||||
|
write_minidump_to_log_(write_minidump_to_log),
|
||||||
|
user_stream_data_sources_(user_stream_data_sources) {
|
||||||
|
DCHECK(write_minidump_to_database_ | write_minidump_to_log_);
|
||||||
|
}
|
||||||
|
|
||||||
CrashReportExceptionHandler::~CrashReportExceptionHandler() = default;
|
CrashReportExceptionHandler::~CrashReportExceptionHandler() = default;
|
||||||
|
|
||||||
@ -116,6 +149,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
|||||||
}
|
}
|
||||||
process_snapshot->SetClientID(client_id);
|
process_snapshot->SetClientID(client_id);
|
||||||
|
|
||||||
|
return write_minidump_to_database_
|
||||||
|
? WriteMinidumpToDatabase(process_snapshot.get(),
|
||||||
|
sanitized_snapshot.get(),
|
||||||
|
write_minidump_to_log_,
|
||||||
|
local_report_id)
|
||||||
|
: WriteMinidumpToLog(process_snapshot.get(),
|
||||||
|
sanitized_snapshot.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrashReportExceptionHandler::WriteMinidumpToDatabase(
|
||||||
|
ProcessSnapshotLinux* process_snapshot,
|
||||||
|
ProcessSnapshotSanitized* sanitized_snapshot,
|
||||||
|
bool write_minidump_to_log,
|
||||||
|
UUID* local_report_id) {
|
||||||
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
std::unique_ptr<CrashReportDatabase::NewReport> new_report;
|
||||||
CrashReportDatabase::OperationStatus database_status =
|
CrashReportDatabase::OperationStatus database_status =
|
||||||
database_->PrepareNewCrashReport(&new_report);
|
database_->PrepareNewCrashReport(&new_report);
|
||||||
@ -129,9 +176,8 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
|||||||
process_snapshot->SetReportID(new_report->ReportID());
|
process_snapshot->SetReportID(new_report->ReportID());
|
||||||
|
|
||||||
ProcessSnapshot* snapshot =
|
ProcessSnapshot* snapshot =
|
||||||
sanitized_snapshot
|
sanitized_snapshot ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot)
|
||||||
? implicit_cast<ProcessSnapshot*>(sanitized_snapshot.get())
|
: implicit_cast<ProcessSnapshot*>(process_snapshot);
|
||||||
: implicit_cast<ProcessSnapshot*>(process_snapshot.get());
|
|
||||||
|
|
||||||
MinidumpFileWriter minidump;
|
MinidumpFileWriter minidump;
|
||||||
minidump.InitializeFromSnapshot(snapshot);
|
minidump.InitializeFromSnapshot(snapshot);
|
||||||
@ -144,6 +190,16 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool write_minidump_to_log_succeed = false;
|
||||||
|
if (write_minidump_to_log) {
|
||||||
|
if (auto* file_reader = new_report->Reader()) {
|
||||||
|
if (WriteMinidumpLogFromFile(file_reader))
|
||||||
|
write_minidump_to_log_succeed = true;
|
||||||
|
else
|
||||||
|
LOG(ERROR) << "WriteMinidumpLogFromFile failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
database_status =
|
database_status =
|
||||||
database_->FinishedWritingCrashReport(std::move(new_report), &uuid);
|
database_->FinishedWritingCrashReport(std::move(new_report), &uuid);
|
||||||
@ -163,7 +219,30 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess);
|
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess);
|
||||||
return true;
|
|
||||||
|
return write_minidump_to_log ? write_minidump_to_log_succeed : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrashReportExceptionHandler::WriteMinidumpToLog(
|
||||||
|
ProcessSnapshotLinux* process_snapshot,
|
||||||
|
ProcessSnapshotSanitized* sanitized_snapshot) {
|
||||||
|
ProcessSnapshot* snapshot =
|
||||||
|
sanitized_snapshot ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot)
|
||||||
|
: implicit_cast<ProcessSnapshot*>(process_snapshot);
|
||||||
|
MinidumpFileWriter minidump;
|
||||||
|
minidump.InitializeFromSnapshot(snapshot);
|
||||||
|
AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump);
|
||||||
|
|
||||||
|
OutputStreamFileWriter writer(std::make_unique<ZlibOutputStream>(
|
||||||
|
ZlibOutputStream::Mode::kCompress,
|
||||||
|
std::make_unique<Base94OutputStream>(
|
||||||
|
Base94OutputStream::Mode::kEncode,
|
||||||
|
std::make_unique<LogOutputStream>())));
|
||||||
|
if (!minidump.WriteMinidump(&writer, false /* allow_seek */)) {
|
||||||
|
LOG(ERROR) << "WriteMinidump failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return writer.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
|
class ProcessSnapshotLinux;
|
||||||
|
class ProcessSnapshotSanitized;
|
||||||
|
|
||||||
//! \brief An exception handler that writes crash reports for exceptions
|
//! \brief An exception handler that writes crash reports for exceptions
|
||||||
//! to a CrashReportDatabase.
|
//! to a CrashReportDatabase.
|
||||||
class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||||
@ -50,6 +53,10 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
|||||||
//! To interoperate with Breakpad servers, the recommended practice is to
|
//! To interoperate with Breakpad servers, the recommended practice is to
|
||||||
//! specify values for the `"prod"` and `"ver"` keys as process
|
//! specify values for the `"prod"` and `"ver"` keys as process
|
||||||
//! annotations.
|
//! annotations.
|
||||||
|
//! \param[in] write_minidump_to_database Whether the minidump shall be
|
||||||
|
//! written to database.
|
||||||
|
//! \param[in] write_minidump_to_log Whether the minidump shall be written to
|
||||||
|
//! log.
|
||||||
//! \param[in] user_stream_data_sources Data sources to be used to extend
|
//! \param[in] user_stream_data_sources Data sources to be used to extend
|
||||||
//! crash reports. For each crash report that is written, the data sources
|
//! crash reports. For each crash report that is written, the data sources
|
||||||
//! are called in turn. These data sources may contribute additional
|
//! are called in turn. These data sources may contribute additional
|
||||||
@ -58,6 +65,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
|||||||
CrashReportDatabase* database,
|
CrashReportDatabase* database,
|
||||||
CrashReportUploadThread* upload_thread,
|
CrashReportUploadThread* upload_thread,
|
||||||
const std::map<std::string, std::string>* process_annotations,
|
const std::map<std::string, std::string>* process_annotations,
|
||||||
|
bool write_minidump_to_database,
|
||||||
|
bool write_minidump_to_log,
|
||||||
const UserStreamDataSources* user_stream_data_sources);
|
const UserStreamDataSources* user_stream_data_sources);
|
||||||
|
|
||||||
~CrashReportExceptionHandler() override;
|
~CrashReportExceptionHandler() override;
|
||||||
@ -87,9 +96,18 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
|||||||
pid_t* requesting_thread_id,
|
pid_t* requesting_thread_id,
|
||||||
UUID* local_report_id = nullptr);
|
UUID* local_report_id = nullptr);
|
||||||
|
|
||||||
|
bool WriteMinidumpToDatabase(ProcessSnapshotLinux* process_snapshot,
|
||||||
|
ProcessSnapshotSanitized* sanitized_snapshot,
|
||||||
|
bool write_minidump_to_log,
|
||||||
|
UUID* local_report_id);
|
||||||
|
bool WriteMinidumpToLog(ProcessSnapshotLinux* process_snapshot,
|
||||||
|
ProcessSnapshotSanitized* sanitized_snapshot);
|
||||||
|
|
||||||
CrashReportDatabase* database_; // weak
|
CrashReportDatabase* database_; // weak
|
||||||
CrashReportUploadThread* upload_thread_; // weak
|
CrashReportUploadThread* upload_thread_; // weak
|
||||||
const std::map<std::string, std::string>* process_annotations_; // weak
|
const std::map<std::string, std::string>* process_annotations_; // weak
|
||||||
|
bool write_minidump_to_database_;
|
||||||
|
bool write_minidump_to_log_;
|
||||||
const UserStreamDataSources* user_stream_data_sources_; // weak
|
const UserStreamDataSources* user_stream_data_sources_; // weak
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler);
|
DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler);
|
||||||
|
@ -211,17 +211,30 @@ bool MinidumpFileWriter::AddUserExtensionStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) {
|
bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) {
|
||||||
|
return WriteMinidump(file_writer, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MinidumpFileWriter::WriteMinidump(FileWriterInterface* file_writer,
|
||||||
|
bool allow_seek) {
|
||||||
DCHECK_EQ(state(), kStateMutable);
|
DCHECK_EQ(state(), kStateMutable);
|
||||||
|
|
||||||
FileOffset start_offset = file_writer->Seek(0, SEEK_CUR);
|
FileOffset start_offset = -1;
|
||||||
if (start_offset < 0) {
|
if (allow_seek) {
|
||||||
return false;
|
start_offset = file_writer->Seek(0, SEEK_CUR);
|
||||||
|
if (start_offset < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header_.Signature = MINIDUMP_SIGNATURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MinidumpWritable::WriteEverything(file_writer)) {
|
if (!MinidumpWritable::WriteEverything(file_writer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allow_seek)
|
||||||
|
return true;
|
||||||
|
|
||||||
FileOffset end_offset = file_writer->Seek(0, SEEK_CUR);
|
FileOffset end_offset = file_writer->Seek(0, SEEK_CUR);
|
||||||
if (end_offset < 0) {
|
if (end_offset < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -134,6 +134,21 @@ class MinidumpFileWriter final : public internal::MinidumpWritable {
|
|||||||
//! mistaken for valid ones.
|
//! mistaken for valid ones.
|
||||||
bool WriteEverything(FileWriterInterface* file_writer) override;
|
bool WriteEverything(FileWriterInterface* file_writer) override;
|
||||||
|
|
||||||
|
//! \brief Writes this object to a minidump file.
|
||||||
|
//!
|
||||||
|
//! Same as \a WriteEverything, but give the option to disable the seek. It
|
||||||
|
//! is typically used to write to stream backed \a FileWriterInterface which
|
||||||
|
//! doesn't support seek.
|
||||||
|
//!
|
||||||
|
//! \param[in] file_writer The file writer to receive the minidump file’s
|
||||||
|
//! content.
|
||||||
|
//!
|
||||||
|
//! \param[in] allow_seek Whether seek is allowed.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success. `false` on failure, with an appropriate message
|
||||||
|
//! logged.
|
||||||
|
bool WriteMinidump(FileWriterInterface* file_writer, bool allow_seek);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// MinidumpWritable:
|
// MinidumpWritable:
|
||||||
bool Freeze() override;
|
bool Freeze() override;
|
||||||
|
@ -36,7 +36,9 @@
|
|||||||
#include "snapshot/test/test_system_snapshot.h"
|
#include "snapshot/test/test_system_snapshot.h"
|
||||||
#include "snapshot/test/test_thread_snapshot.h"
|
#include "snapshot/test/test_thread_snapshot.h"
|
||||||
#include "test/gtest_death.h"
|
#include "test/gtest_death.h"
|
||||||
|
#include "util/file/output_stream_file_writer.h"
|
||||||
#include "util/file/string_file.h"
|
#include "util/file/string_file.h"
|
||||||
|
#include "util/stream/output_stream_interface.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
namespace test {
|
||||||
@ -88,6 +90,22 @@ class TestStream final : public internal::MinidumpStreamWriter {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(TestStream);
|
DISALLOW_COPY_AND_ASSIGN(TestStream);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class StringFileOutputStream : public OutputStreamInterface {
|
||||||
|
public:
|
||||||
|
StringFileOutputStream() = default;
|
||||||
|
~StringFileOutputStream() override = default;
|
||||||
|
bool Write(const uint8_t* data, size_t size) override {
|
||||||
|
return string_file_.Write(data, size);
|
||||||
|
}
|
||||||
|
bool Flush() override { return true; }
|
||||||
|
const StringFile& string_file() const { return string_file_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringFile string_file_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(StringFileOutputStream);
|
||||||
|
};
|
||||||
|
|
||||||
TEST(MinidumpFileWriter, OneStream) {
|
TEST(MinidumpFileWriter, OneStream) {
|
||||||
MinidumpFileWriter minidump_file;
|
MinidumpFileWriter minidump_file;
|
||||||
constexpr time_t kTimestamp = 0x155d2fb8;
|
constexpr time_t kTimestamp = 0x155d2fb8;
|
||||||
@ -578,6 +596,51 @@ TEST(MinidumpFileWriter, SameStreamType) {
|
|||||||
EXPECT_EQ(memcmp(stream_data, expected_stream.c_str(), kStream0Size), 0);
|
EXPECT_EQ(memcmp(stream_data, expected_stream.c_str(), kStream0Size), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MinidumpFileWriter, WriteMinidumpDisallowSeek) {
|
||||||
|
MinidumpFileWriter minidump_file;
|
||||||
|
constexpr time_t kTimestamp = 0x155d2fb8;
|
||||||
|
minidump_file.SetTimestamp(kTimestamp);
|
||||||
|
|
||||||
|
constexpr size_t kStreamSize = 5;
|
||||||
|
constexpr MinidumpStreamType kStreamType =
|
||||||
|
static_cast<MinidumpStreamType>(0x4d);
|
||||||
|
constexpr uint8_t kStreamValue = 0x5a;
|
||||||
|
auto stream =
|
||||||
|
std::make_unique<TestStream>(kStreamType, kStreamSize, kStreamValue);
|
||||||
|
ASSERT_TRUE(minidump_file.AddStream(std::move(stream)));
|
||||||
|
|
||||||
|
std::unique_ptr<StringFileOutputStream> string_file_output_stream =
|
||||||
|
std::make_unique<StringFileOutputStream>();
|
||||||
|
const StringFile& string_file = string_file_output_stream->string_file();
|
||||||
|
OutputStreamFileWriter output_stream(std::move(string_file_output_stream));
|
||||||
|
ASSERT_TRUE(minidump_file.WriteMinidump(&output_stream, false));
|
||||||
|
ASSERT_TRUE(output_stream.Flush());
|
||||||
|
|
||||||
|
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
|
||||||
|
constexpr size_t kStreamOffset =
|
||||||
|
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
|
||||||
|
constexpr size_t kFileSize = kStreamOffset + kStreamSize;
|
||||||
|
|
||||||
|
ASSERT_EQ(string_file.string().size(), kFileSize);
|
||||||
|
|
||||||
|
const MINIDUMP_DIRECTORY* directory;
|
||||||
|
const MINIDUMP_HEADER* header =
|
||||||
|
MinidumpHeaderAtStart(string_file.string(), &directory);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, kTimestamp));
|
||||||
|
ASSERT_TRUE(directory);
|
||||||
|
|
||||||
|
EXPECT_EQ(directory[0].StreamType, kStreamType);
|
||||||
|
EXPECT_EQ(directory[0].Location.DataSize, kStreamSize);
|
||||||
|
EXPECT_EQ(directory[0].Location.Rva, kStreamOffset);
|
||||||
|
|
||||||
|
const uint8_t* stream_data = MinidumpWritableAtLocationDescriptor<uint8_t>(
|
||||||
|
string_file.string(), directory[0].Location);
|
||||||
|
ASSERT_TRUE(stream_data);
|
||||||
|
|
||||||
|
std::string expected_stream(kStreamSize, kStreamValue);
|
||||||
|
EXPECT_EQ(memcmp(stream_data, expected_stream.c_str(), kStreamSize), 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -56,7 +56,6 @@ crashpad_executable("base94_encoder") {
|
|||||||
":tool_support",
|
":tool_support",
|
||||||
"../build:default_exe_manifest_win",
|
"../build:default_exe_manifest_win",
|
||||||
"../third_party/mini_chromium:base",
|
"../third_party/mini_chromium:base",
|
||||||
"../third_party/zlib",
|
|
||||||
"../util",
|
"../util",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,8 @@ static_library("util") {
|
|||||||
"file/file_writer.cc",
|
"file/file_writer.cc",
|
||||||
"file/file_writer.h",
|
"file/file_writer.h",
|
||||||
"file/filesystem.h",
|
"file/filesystem.h",
|
||||||
|
"file/output_stream_file_writer.cc",
|
||||||
|
"file/output_stream_file_writer.h",
|
||||||
"file/scoped_remove_file.cc",
|
"file/scoped_remove_file.cc",
|
||||||
"file/scoped_remove_file.h",
|
"file/scoped_remove_file.h",
|
||||||
"file/string_file.cc",
|
"file/string_file.cc",
|
||||||
@ -466,13 +468,13 @@ static_library("util") {
|
|||||||
include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ]
|
include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
public_deps = [ "../compat" ]
|
public_deps = [
|
||||||
|
"../compat",
|
||||||
deps += [
|
|
||||||
"../third_party/mini_chromium:base",
|
|
||||||
"../third_party/zlib",
|
"../third_party/zlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
deps += [ "../third_party/mini_chromium:base" ]
|
||||||
|
|
||||||
if (crashpad_is_mac) {
|
if (crashpad_is_mac) {
|
||||||
libs = [
|
libs = [
|
||||||
"bsm",
|
"bsm",
|
||||||
|
68
util/file/output_stream_file_writer.cc
Normal file
68
util/file/output_stream_file_writer.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2020 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "util/file/output_stream_file_writer.h"
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "util/stream/output_stream_interface.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
OutputStreamFileWriter::OutputStreamFileWriter(
|
||||||
|
std::unique_ptr<OutputStreamInterface> output_stream)
|
||||||
|
: output_stream_(std::move(output_stream)),
|
||||||
|
flush_needed_(false),
|
||||||
|
flushed_(false) {}
|
||||||
|
|
||||||
|
OutputStreamFileWriter::~OutputStreamFileWriter() {
|
||||||
|
DCHECK(!flush_needed_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutputStreamFileWriter::Write(const void* data, size_t size) {
|
||||||
|
DCHECK(!flushed_);
|
||||||
|
flush_needed_ =
|
||||||
|
output_stream_->Write(static_cast<const uint8_t*>(data), size);
|
||||||
|
return flush_needed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutputStreamFileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
|
||||||
|
DCHECK(!flushed_);
|
||||||
|
flush_needed_ = true;
|
||||||
|
if (iovecs->empty()) {
|
||||||
|
LOG(ERROR) << "no iovecs";
|
||||||
|
flush_needed_ = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const WritableIoVec& iov : *iovecs) {
|
||||||
|
if (!output_stream_->Write(static_cast<const uint8_t*>(iov.iov_base),
|
||||||
|
iov.iov_len)) {
|
||||||
|
flush_needed_ = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOffset OutputStreamFileWriter::Seek(FileOffset offset, int whence) {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutputStreamFileWriter::Flush() {
|
||||||
|
flush_needed_ = false;
|
||||||
|
flushed_ = true;
|
||||||
|
return output_stream_->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
62
util/file/output_stream_file_writer.h
Normal file
62
util/file/output_stream_file_writer.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2020 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CRASHPAD_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_
|
||||||
|
#define CRASHPAD_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "base/macros.h"
|
||||||
|
#include "util/file/file_writer.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
class OutputStreamInterface;
|
||||||
|
|
||||||
|
//! \brief A file writer backed by a OutputSteamInterface.
|
||||||
|
//! \note The \a Seek related methods don't work and shouldn't be invoked.
|
||||||
|
class OutputStreamFileWriter : public FileWriterInterface {
|
||||||
|
public:
|
||||||
|
//! \param[in] output_stream The output stream that this object writes to.
|
||||||
|
explicit OutputStreamFileWriter(
|
||||||
|
std::unique_ptr<OutputStreamInterface> output_stream);
|
||||||
|
~OutputStreamFileWriter() override;
|
||||||
|
|
||||||
|
// FileWriterInterface:
|
||||||
|
bool Write(const void* data, size_t size) override;
|
||||||
|
bool WriteIoVec(std::vector<WritableIoVec>* iovecs) override;
|
||||||
|
|
||||||
|
// FileSeekerInterface:
|
||||||
|
|
||||||
|
//! \copydoc FileWriterInterface::Seek()
|
||||||
|
//!
|
||||||
|
//! \note This method doesn't work and shouldn't be invoked.
|
||||||
|
FileOffset Seek(FileOffset offset, int whence) override;
|
||||||
|
|
||||||
|
//! \brief Flush data to output_stream.
|
||||||
|
//!
|
||||||
|
//! Either \a Write() or \a WriteIoVec() can't be called afterwards.
|
||||||
|
bool Flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<OutputStreamInterface> output_stream_;
|
||||||
|
bool flush_needed_;
|
||||||
|
bool flushed_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(OutputStreamFileWriter);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_
|
Loading…
x
Reference in New Issue
Block a user