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
|
||||
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_
|
||||
|
||||
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
|
||||
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**
|
||||
|
||||
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-rate-limit don't rate limit crash uploads\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)
|
||||
" --pipe-name=PIPE communicate with the client over PIPE\n"
|
||||
#endif // OS_WIN
|
||||
@ -173,6 +177,9 @@ void Usage(const base::FilePath& me) {
|
||||
" crash_reporter, thus skipping metrics consent\n"
|
||||
" checks\n"
|
||||
#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"
|
||||
" --version output version information and exit\n",
|
||||
me.value().c_str());
|
||||
@ -195,6 +202,10 @@ struct Options {
|
||||
VMAddress sanitization_information_address;
|
||||
int initial_client_fd;
|
||||
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)
|
||||
std::string pipe_name;
|
||||
InitialClientData initial_client_data;
|
||||
@ -551,6 +562,9 @@ int HandlerMain(int argc,
|
||||
kOptionNoPeriodicTasks,
|
||||
kOptionNoRateLimit,
|
||||
kOptionNoUploadGzip,
|
||||
#if defined(OS_ANDROID)
|
||||
kOptionNoWriteMinidumpToDatabase,
|
||||
#endif // OS_ANDROID
|
||||
#if defined(OS_WIN)
|
||||
kOptionPipeName,
|
||||
#endif // OS_WIN
|
||||
@ -568,6 +582,9 @@ int HandlerMain(int argc,
|
||||
kOptionMinidumpDirForTests,
|
||||
kOptionAlwaysAllowFeedback,
|
||||
#endif // OS_CHROMEOS
|
||||
#if defined(OS_ANDROID)
|
||||
kOptionWriteMinidumpToLog,
|
||||
#endif // OS_ANDROID
|
||||
|
||||
// Standard options.
|
||||
kOptionHelp = -2,
|
||||
@ -609,6 +626,12 @@ int HandlerMain(int argc,
|
||||
{"no-periodic-tasks", no_argument, nullptr, kOptionNoPeriodicTasks},
|
||||
{"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit},
|
||||
{"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)
|
||||
{"pipe-name", required_argument, nullptr, kOptionPipeName},
|
||||
#endif // OS_WIN
|
||||
@ -647,6 +670,9 @@ int HandlerMain(int argc,
|
||||
nullptr,
|
||||
kOptionAlwaysAllowFeedback},
|
||||
#endif // OS_CHROMEOS
|
||||
#if defined(OS_ANDROID)
|
||||
{"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog},
|
||||
#endif // OS_ANDROID
|
||||
{"help", no_argument, nullptr, kOptionHelp},
|
||||
{"version", no_argument, nullptr, kOptionVersion},
|
||||
{nullptr, 0, nullptr, 0},
|
||||
@ -663,6 +689,9 @@ int HandlerMain(int argc,
|
||||
options.periodic_tasks = true;
|
||||
options.rate_limit = true;
|
||||
options.upload_gzip = true;
|
||||
#if defined(OS_ANDROID)
|
||||
options.write_minidump_to_database = true;
|
||||
#endif
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
||||
@ -749,6 +778,12 @@ int HandlerMain(int argc,
|
||||
options.upload_gzip = false;
|
||||
break;
|
||||
}
|
||||
#if defined(OS_ANDROID)
|
||||
case kOptionNoWriteMinidumpToDatabase: {
|
||||
options.write_minidump_to_database = false;
|
||||
break;
|
||||
}
|
||||
#endif // OS_ANDROID
|
||||
#if defined(OS_WIN)
|
||||
case kOptionPipeName: {
|
||||
options.pipe_name = optarg;
|
||||
@ -803,6 +838,12 @@ int HandlerMain(int argc,
|
||||
break;
|
||||
}
|
||||
#endif // OS_CHROMEOS
|
||||
#if defined(OS_ANDROID)
|
||||
case kOptionWriteMinidumpToLog: {
|
||||
options.write_minidump_to_log = true;
|
||||
break;
|
||||
}
|
||||
#endif // OS_ANDROID
|
||||
case kOptionHelp: {
|
||||
Usage(me);
|
||||
MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly);
|
||||
@ -863,6 +904,14 @@ int HandlerMain(int argc,
|
||||
me, "--shared-client-connection requires --initial-client-fd");
|
||||
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
|
||||
|
||||
if (options.database.empty()) {
|
||||
@ -966,8 +1015,17 @@ int HandlerMain(int argc,
|
||||
// TODO(scottmg): Process level file attachments, and for all platforms.
|
||||
nullptr,
|
||||
#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
|
||||
user_stream_sources);
|
||||
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
if (options.exception_information_address) {
|
||||
|
@ -23,23 +23,56 @@
|
||||
#include "minidump/minidump_file_writer.h"
|
||||
#include "snapshot/linux/process_snapshot_linux.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/ptrace_client.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
#include "util/misc/metrics.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 {
|
||||
|
||||
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(
|
||||
CrashReportDatabase* database,
|
||||
CrashReportUploadThread* upload_thread,
|
||||
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)
|
||||
: database_(database),
|
||||
upload_thread_(upload_thread),
|
||||
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;
|
||||
|
||||
@ -116,6 +149,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
||||
}
|
||||
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;
|
||||
CrashReportDatabase::OperationStatus database_status =
|
||||
database_->PrepareNewCrashReport(&new_report);
|
||||
@ -129,9 +176,8 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
||||
process_snapshot->SetReportID(new_report->ReportID());
|
||||
|
||||
ProcessSnapshot* snapshot =
|
||||
sanitized_snapshot
|
||||
? implicit_cast<ProcessSnapshot*>(sanitized_snapshot.get())
|
||||
: implicit_cast<ProcessSnapshot*>(process_snapshot.get());
|
||||
sanitized_snapshot ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot)
|
||||
: implicit_cast<ProcessSnapshot*>(process_snapshot);
|
||||
|
||||
MinidumpFileWriter minidump;
|
||||
minidump.InitializeFromSnapshot(snapshot);
|
||||
@ -144,6 +190,16 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
||||
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;
|
||||
database_status =
|
||||
database_->FinishedWritingCrashReport(std::move(new_report), &uuid);
|
||||
@ -163,7 +219,30 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -30,6 +30,9 @@
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ProcessSnapshotLinux;
|
||||
class ProcessSnapshotSanitized;
|
||||
|
||||
//! \brief An exception handler that writes crash reports for exceptions
|
||||
//! to a CrashReportDatabase.
|
||||
class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||
@ -50,6 +53,10 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||
//! To interoperate with Breakpad servers, the recommended practice is to
|
||||
//! specify values for the `"prod"` and `"ver"` keys as process
|
||||
//! 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
|
||||
//! crash reports. For each crash report that is written, the data sources
|
||||
//! are called in turn. These data sources may contribute additional
|
||||
@ -58,6 +65,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||
CrashReportDatabase* database,
|
||||
CrashReportUploadThread* upload_thread,
|
||||
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);
|
||||
|
||||
~CrashReportExceptionHandler() override;
|
||||
@ -87,9 +96,18 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
||||
pid_t* requesting_thread_id,
|
||||
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
|
||||
CrashReportUploadThread* upload_thread_; // 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
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler);
|
||||
|
@ -211,17 +211,30 @@ bool MinidumpFileWriter::AddUserExtensionStream(
|
||||
}
|
||||
|
||||
bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) {
|
||||
return WriteMinidump(file_writer, true);
|
||||
}
|
||||
|
||||
bool MinidumpFileWriter::WriteMinidump(FileWriterInterface* file_writer,
|
||||
bool allow_seek) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
FileOffset start_offset = file_writer->Seek(0, SEEK_CUR);
|
||||
FileOffset start_offset = -1;
|
||||
if (allow_seek) {
|
||||
start_offset = file_writer->Seek(0, SEEK_CUR);
|
||||
if (start_offset < 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
header_.Signature = MINIDUMP_SIGNATURE;
|
||||
}
|
||||
|
||||
if (!MinidumpWritable::WriteEverything(file_writer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!allow_seek)
|
||||
return true;
|
||||
|
||||
FileOffset end_offset = file_writer->Seek(0, SEEK_CUR);
|
||||
if (end_offset < 0) {
|
||||
return false;
|
||||
|
@ -134,6 +134,21 @@ class MinidumpFileWriter final : public internal::MinidumpWritable {
|
||||
//! mistaken for valid ones.
|
||||
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:
|
||||
// MinidumpWritable:
|
||||
bool Freeze() override;
|
||||
|
@ -36,7 +36,9 @@
|
||||
#include "snapshot/test/test_system_snapshot.h"
|
||||
#include "snapshot/test/test_thread_snapshot.h"
|
||||
#include "test/gtest_death.h"
|
||||
#include "util/file/output_stream_file_writer.h"
|
||||
#include "util/file/string_file.h"
|
||||
#include "util/stream/output_stream_interface.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
@ -88,6 +90,22 @@ class TestStream final : public internal::MinidumpStreamWriter {
|
||||
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) {
|
||||
MinidumpFileWriter minidump_file;
|
||||
constexpr time_t kTimestamp = 0x155d2fb8;
|
||||
@ -578,6 +596,51 @@ TEST(MinidumpFileWriter, SameStreamType) {
|
||||
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 test
|
||||
} // namespace crashpad
|
||||
|
@ -56,7 +56,6 @@ crashpad_executable("base94_encoder") {
|
||||
":tool_support",
|
||||
"../build:default_exe_manifest_win",
|
||||
"../third_party/mini_chromium:base",
|
||||
"../third_party/zlib",
|
||||
"../util",
|
||||
]
|
||||
}
|
||||
|
@ -91,6 +91,8 @@ static_library("util") {
|
||||
"file/file_writer.cc",
|
||||
"file/file_writer.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.h",
|
||||
"file/string_file.cc",
|
||||
@ -466,13 +468,13 @@ static_library("util") {
|
||||
include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ]
|
||||
}
|
||||
|
||||
public_deps = [ "../compat" ]
|
||||
|
||||
deps += [
|
||||
"../third_party/mini_chromium:base",
|
||||
public_deps = [
|
||||
"../compat",
|
||||
"../third_party/zlib",
|
||||
]
|
||||
|
||||
deps += [ "../third_party/mini_chromium:base" ]
|
||||
|
||||
if (crashpad_is_mac) {
|
||||
libs = [
|
||||
"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