crashpad_database_util: add --new-report.

R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/1018853006
This commit is contained in:
Mark Mentovai 2015-04-03 18:57:01 -04:00
parent 678baca8bd
commit ab23906193
5 changed files with 129 additions and 45 deletions

View File

@ -17,8 +17,31 @@
namespace crashpad {
CrashReportDatabase::Report::Report()
: uuid(), file_path(), id(), creation_time(0), uploaded(false),
last_upload_attempt_time(0), upload_attempts(0) {
: uuid(),
file_path(),
id(),
creation_time(0),
uploaded(false),
last_upload_attempt_time(0),
upload_attempts(0) {
}
CrashReportDatabase::CallErrorWritingCrashReport::CallErrorWritingCrashReport(
CrashReportDatabase* database,
NewReport* new_report)
: database_(database),
new_report_(new_report) {
}
CrashReportDatabase::CallErrorWritingCrashReport::
~CallErrorWritingCrashReport() {
if (new_report_) {
database_->ErrorWritingCrashReport(new_report_);
}
}
void CrashReportDatabase::CallErrorWritingCrashReport::Disarm() {
new_report_ = nullptr;
}
} // namespace crashpad

View File

@ -106,6 +106,32 @@ class CrashReportDatabase {
base::FilePath path;
};
//! \brief A scoper to cleanly handle the interface requirement imposed by
//! PrepareNewCrashReport().
//!
//! Calls ErrorWritingCrashReport() upon destruction unless disarmed by
//! calling Disarm(). Armed upon construction.
class CallErrorWritingCrashReport {
public:
//! \brief Arms the object to call ErrorWritingCrashReport() on \a database
//! with an argument of \a new_report on destruction.
CallErrorWritingCrashReport(CrashReportDatabase* database,
NewReport* new_report);
//! \brief Calls ErrorWritingCrashReport() if the object is armed.
~CallErrorWritingCrashReport();
//! \brief Disarms the object so that CallErrorWritingCrashReport() will not
//! be called upon destruction.
void Disarm();
private:
CrashReportDatabase* database_; // weak
NewReport* new_report_; // weak
DISALLOW_COPY_AND_ASSIGN(CallErrorWritingCrashReport);
};
//! \brief The result code for operations performed on a database.
enum OperationStatus {
//! \brief No error occurred.
@ -156,12 +182,17 @@ class CrashReportDatabase {
//! \brief Creates a record of a new crash report.
//!
//! Callers can then write the crash report using the file handle provided.
//! The caller does not own this handle, and it must be explicitly closed with
//! The caller does not own the new crash report record or its file handle,
//! both of which must be explicitly disposed of by calling
//! FinishedWritingCrashReport() or ErrorWritingCrashReport().
//!
//! \param[out] report A file handle to which the crash report data should be
//! written. Only valid if this returns #kNoError. The caller must not
//! close this handle.
//! To arrange to call ErrorWritingCrashReport() during any early return, use
//! CallErrorWritingCrashReport.
//!
//! \param[out] report A NewReport object containing a file handle to which
//! the crash report data should be written. Only valid if this returns
//! #kNoError. The caller must not delete the NewReport object or close
//! the file handle within.
//!
//! \return The operation status code.
virtual OperationStatus PrepareNewCrashReport(NewReport** report) = 0;
@ -171,8 +202,9 @@ class CrashReportDatabase {
//! After calling this method, the database is permitted to move and rename
//! the file at NewReport::path.
//!
//! \param[in] report A handle obtained with PrepareNewCrashReport(). The
//! handle will be invalidated as part of this call.
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
//! NewReport object and file handle within will be invalidated as part of
//! this call.
//! \param[out] uuid The UUID of this crash report.
//!
//! \return The operation status code.
@ -186,8 +218,9 @@ class CrashReportDatabase {
//! After calling this method, the database is permitted to remove the file at
//! NewReport::path.
//!
//! \param[in] report A handle obtained with PrepareNewCrashReport(). The
//! handle will be invalidated as part of this call.
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
//! NewReport object and file handle within will be invalidated as part of
//! this call.
//!
//! \return The operation status code.
virtual OperationStatus ErrorWritingCrashReport(NewReport* report) = 0;

View File

@ -37,37 +37,6 @@
namespace crashpad {
namespace {
// Calls CrashReportDatabase::ErrorWritingCrashReport() upon destruction unless
// disarmed by calling Disarm(). Armed upon construction.
class CallErrorWritingCrashReport {
public:
CallErrorWritingCrashReport(CrashReportDatabase* database,
CrashReportDatabase::NewReport* new_report)
: database_(database),
new_report_(new_report) {
}
~CallErrorWritingCrashReport() {
if (new_report_) {
database_->ErrorWritingCrashReport(new_report_);
}
}
void Disarm() {
new_report_ = nullptr;
}
private:
CrashReportDatabase* database_; // weak
CrashReportDatabase::NewReport* new_report_; // weak
DISALLOW_COPY_AND_ASSIGN(CallErrorWritingCrashReport);
};
} // namespace
CrashReportExceptionHandler::CrashReportExceptionHandler(
CrashReportDatabase* database,
CrashReportUploadThread* upload_thread,
@ -177,8 +146,8 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
process_snapshot.SetReportID(new_report->uuid);
CallErrorWritingCrashReport call_error_writing_crash_report(database_,
new_report);
CrashReportDatabase::CallErrorWritingCrashReport
call_error_writing_crash_report(database_, new_report);
WeakFileHandleFileWriter file_writer(new_report->handle);

View File

@ -49,6 +49,8 @@ parent directory of 'PATH' exists.
*--show-client-id*::
Show the client ID stored in the databases settings. The client ID is formatted
as a UUID. The client ID is set when the database is created.
man_link:crashpad_handler[8] retrieves the client ID and stores it in crash
reports as they are written.
*--show-uploads-enabled*::
Show the status of the uploads-enabled bit stored in the databases settings.
@ -86,7 +88,8 @@ be formatted in string representation per RFC 4122 §3. All metadata for each
report found via a *--show-report* option will be shown. If 'UUID' is not found,
the string +"not found"+ will be printed. If this program is only requested to
show a single report and it is not found, it will treat this as a failure for
the purposes of determining its exit status.
the purposes of determining its exit status. This option may appear multiple
times.
*--set-report-uploads-enabled*='BOOL'::
Enable or disable report upload in the databases settings. 'BOOL' is a string
@ -101,6 +104,11 @@ numeric +time_t+ value, or the special string +"never"+.
+
See also *--show-last-upload-attempt-time*.
*--new-report*='PATH'::
Submit a new report located at 'PATH' to the database. The new report will be in
the “pending” state. The UUID assigned to the new report will be printed. This
option may appear multiple times.
*--utc*::
When showing times, do so in UTC as opposed to the local time zone. When setting
times, interpret ambiguous time strings in UTC as opposed to the local time

View File

@ -32,6 +32,8 @@
#include "client/crash_report_database.h"
#include "client/settings.h"
#include "tools/tool_support.h"
#include "util/file/file_io.h"
#include "util/file/file_reader.h"
#include "util/misc/uuid.h"
namespace crashpad {
@ -54,6 +56,7 @@ void Usage(const std::string& me) {
" --set-uploads-enabled=BOOL enable or disable uploads\n"
" --set-last-upload-attempt-time=TIME\n"
" set the last-upload-attempt time to TIME\n"
" --new-report=PATH submit a new report at PATH\n"
" --utc show and set UTC times instead of local\n"
" --help display this help and exit\n"
" --version output version information and exit\n",
@ -63,6 +66,7 @@ void Usage(const std::string& me) {
struct Options {
std::vector<UUID> show_reports;
std::vector<base::FilePath> new_report_paths;
const char* database;
const char* set_last_upload_attempt_time_string;
time_t set_last_upload_attempt_time;
@ -252,6 +256,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
kOptionShowReport,
kOptionSetUploadsEnabled,
kOptionSetLastUploadAttemptTime,
kOptionNewReport,
kOptionUTC,
// Standard options.
@ -282,6 +287,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
required_argument,
nullptr,
kOptionSetLastUploadAttemptTime},
{"new-report", required_argument, nullptr, kOptionNewReport},
{"utc", no_argument, nullptr, kOptionUTC},
{"help", no_argument, nullptr, kOptionHelp},
{"version", no_argument, nullptr, kOptionVersion},
@ -342,6 +348,10 @@ int DatabaseUtilMain(int argc, char* argv[]) {
options.set_last_upload_attempt_time_string = optarg;
break;
}
case kOptionNewReport: {
options.new_report_paths.push_back(base::FilePath(optarg));
break;
}
case kOptionUTC: {
options.utc = true;
break;
@ -381,12 +391,14 @@ int DatabaseUtilMain(int argc, char* argv[]) {
}
}
// --new-report is treated as a show operation because it produces output.
const size_t show_operations = options.show_client_id +
options.show_uploads_enabled +
options.show_last_upload_attempt_time +
options.show_pending_reports +
options.show_completed_reports +
options.show_reports.size();
options.show_reports.size() +
options.new_report_paths.size();
const size_t set_operations =
options.has_set_uploads_enabled +
(options.set_last_upload_attempt_time_string != nullptr);
@ -505,6 +517,45 @@ int DatabaseUtilMain(int argc, char* argv[]) {
return EXIT_FAILURE;
}
for (const base::FilePath new_report_path : options.new_report_paths) {
FileReader file_reader;
if (!file_reader.Open(new_report_path)) {
return EXIT_FAILURE;
}
CrashReportDatabase::NewReport* new_report;
CrashReportDatabase::OperationStatus status =
database->PrepareNewCrashReport(&new_report);
if (status != CrashReportDatabase::kNoError) {
return EXIT_FAILURE;
}
CrashReportDatabase::CallErrorWritingCrashReport
call_error_writing_crash_report(database.get(), new_report);
char buf[4096];
ssize_t read_result;
while ((read_result = file_reader.Read(buf, sizeof(buf))) > 0) {
if (!LoggingWriteFile(new_report->handle, buf, read_result)) {
return EXIT_FAILURE;
}
}
if (read_result < 0) {
return EXIT_FAILURE;
}
call_error_writing_crash_report.Disarm();
UUID uuid;
status = database->FinishedWritingCrashReport(new_report, &uuid);
if (status != CrashReportDatabase::kNoError) {
return EXIT_FAILURE;
}
const char* prefix = (show_operations > 1) ? "New report ID: " : "";
printf("%s%s\n", prefix, uuid.ToString().c_str());
}
return EXIT_SUCCESS;
}