mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08:00
Add MinidumpFileWriter::InitializeFromSnapshot() and its tests.
TEST=minidump_test MinidumpFileWriter.InitializeFromSnapshot* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/703223003
This commit is contained in:
parent
e5048b3a80
commit
360e441c53
@ -32,12 +32,12 @@ MinidumpExceptionWriter::~MinidumpExceptionWriter() {
|
||||
|
||||
void MinidumpExceptionWriter::InitializeFromSnapshot(
|
||||
const ExceptionSnapshot* exception_snapshot,
|
||||
const MinidumpThreadIDMap* thread_id_map) {
|
||||
const MinidumpThreadIDMap& thread_id_map) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
DCHECK(!context_);
|
||||
|
||||
auto thread_id_it = thread_id_map->find(exception_snapshot->ThreadID());
|
||||
DCHECK(thread_id_it != thread_id_map->end());
|
||||
auto thread_id_it = thread_id_map.find(exception_snapshot->ThreadID());
|
||||
DCHECK(thread_id_it != thread_id_map.end());
|
||||
SetThreadID(thread_id_it->second);
|
||||
|
||||
SetExceptionCode(exception_snapshot->Exception());
|
||||
|
@ -49,7 +49,7 @@ class MinidumpExceptionWriter final : public internal::MinidumpStreamWriter {
|
||||
//! this method, and it is not normally necessary to call any mutator
|
||||
//! methods after this method.
|
||||
void InitializeFromSnapshot(const ExceptionSnapshot* exception_snapshot,
|
||||
const MinidumpThreadIDMap* thread_id_map);
|
||||
const MinidumpThreadIDMap& thread_id_map);
|
||||
|
||||
//! \brief Arranges for MINIDUMP_EXCEPTION_STREAM::ThreadContext to point to
|
||||
//! the CPU context to be written by \a context.
|
||||
|
@ -232,7 +232,7 @@ TEST(MinidumpExceptionWriter, InitializeFromSnapshot) {
|
||||
thread_id_map[kThreadID] = expect_exception.ThreadId;
|
||||
|
||||
auto exception_writer = make_scoped_ptr(new MinidumpExceptionWriter());
|
||||
exception_writer->InitializeFromSnapshot(&exception_snapshot, &thread_id_map);
|
||||
exception_writer->InitializeFromSnapshot(&exception_snapshot, thread_id_map);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(exception_writer.Pass());
|
||||
|
@ -15,7 +15,16 @@
|
||||
#include "minidump/minidump_file_writer.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_crashpad_info_writer.h"
|
||||
#include "minidump/minidump_exception_writer.h"
|
||||
#include "minidump/minidump_memory_writer.h"
|
||||
#include "minidump/minidump_misc_info_writer.h"
|
||||
#include "minidump/minidump_module_writer.h"
|
||||
#include "minidump/minidump_system_info_writer.h"
|
||||
#include "minidump/minidump_thread_id_map.h"
|
||||
#include "minidump/minidump_thread_writer.h"
|
||||
#include "minidump/minidump_writer_util.h"
|
||||
#include "snapshot/process_snapshot.h"
|
||||
#include "util/file/file_writer.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
|
||||
@ -36,6 +45,63 @@ MinidumpFileWriter::MinidumpFileWriter()
|
||||
MinidumpFileWriter::~MinidumpFileWriter() {
|
||||
}
|
||||
|
||||
void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
const ProcessSnapshot* process_snapshot) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
DCHECK_EQ(header_.Signature, 0u);
|
||||
DCHECK_EQ(header_.TimeDateStamp, 0u);
|
||||
DCHECK_EQ(header_.Flags, MiniDumpNormal);
|
||||
DCHECK(streams_.empty());
|
||||
|
||||
// This time is truncated to an integer number of seconds, not rounded, for
|
||||
// compatibility with the truncation of process_snapshot->ProcessStartTime()
|
||||
// done by MinidumpMiscInfoWriter::InitializeFromSnapshot(). Handling both
|
||||
// timestamps in the same way allows the highest-fidelity computation of
|
||||
// process uptime as the difference between the two values.
|
||||
timeval snapshot_time;
|
||||
process_snapshot->SnapshotTime(&snapshot_time);
|
||||
SetTimestamp(snapshot_time.tv_sec);
|
||||
|
||||
const SystemSnapshot* system_snapshot = process_snapshot->System();
|
||||
auto system_info = make_scoped_ptr(new MinidumpSystemInfoWriter());
|
||||
system_info->InitializeFromSnapshot(system_snapshot);
|
||||
AddStream(system_info.Pass());
|
||||
|
||||
auto misc_info = make_scoped_ptr(new MinidumpMiscInfoWriter());
|
||||
misc_info->InitializeFromSnapshot(process_snapshot);
|
||||
AddStream(misc_info.Pass());
|
||||
|
||||
auto memory_list = make_scoped_ptr(new MinidumpMemoryListWriter());
|
||||
auto thread_list = make_scoped_ptr(new MinidumpThreadListWriter());
|
||||
thread_list->SetMemoryListWriter(memory_list.get());
|
||||
MinidumpThreadIDMap thread_id_map;
|
||||
thread_list->InitializeFromSnapshot(process_snapshot->Threads(),
|
||||
&thread_id_map);
|
||||
AddStream(thread_list.Pass());
|
||||
|
||||
const ExceptionSnapshot* exception_snapshot = process_snapshot->Exception();
|
||||
if (exception_snapshot) {
|
||||
auto exception = make_scoped_ptr(new MinidumpExceptionWriter());
|
||||
exception->InitializeFromSnapshot(exception_snapshot, thread_id_map);
|
||||
AddStream(exception.Pass());
|
||||
}
|
||||
|
||||
auto module_list = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||
module_list->InitializeFromSnapshot(process_snapshot->Modules());
|
||||
AddStream(module_list.Pass());
|
||||
|
||||
auto crashpad_info = make_scoped_ptr(new MinidumpCrashpadInfoWriter());
|
||||
crashpad_info->InitializeFromSnapshot(process_snapshot);
|
||||
|
||||
// Since the MinidumpCrashpadInfo stream is an extension, it’s safe to not add
|
||||
// it to the minidump file if it wouldn’t carry any useful information.
|
||||
if (crashpad_info->IsUseful()) {
|
||||
AddStream(crashpad_info.Pass());
|
||||
}
|
||||
|
||||
AddStream(memory_list.Pass());
|
||||
}
|
||||
|
||||
void MinidumpFileWriter::SetTimestamp(time_t timestamp) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ProcessSnapshot;
|
||||
|
||||
//! \brief The root-level object in a minidump file.
|
||||
//!
|
||||
//! This object writes a MINIDUMP_HEADER and list of MINIDUMP_DIRECTORY entries
|
||||
@ -39,6 +41,34 @@ class MinidumpFileWriter final : public internal::MinidumpWritable {
|
||||
MinidumpFileWriter();
|
||||
~MinidumpFileWriter() override;
|
||||
|
||||
//! \brief Initializes the MinidumpFileWriter and populates it with
|
||||
//! appropriate child streams based on \a process_snapshot.
|
||||
//!
|
||||
//! This method will add additional streams to the minidump file as children
|
||||
//! of the MinidumpFileWriter object and as pointees of the top-level
|
||||
//! MINIDUMP_DIRECTORY. To do so, it will obtain other snapshot information
|
||||
//! from \a process_snapshot, such as a SystemSnapshot, lists of
|
||||
//! ThreadSnapshot and ModuleSnapshot objects, and, if available, an
|
||||
//! ExceptionSnapshot.
|
||||
//!
|
||||
//! The streams are added in the order that they are expected to be most
|
||||
//! useful to minidump readers, to improve data locality and minimize seeking.
|
||||
//! The streams are added in this order:
|
||||
//! - kMinidumpStreamTypeSystemInfo
|
||||
//! - kMinidumpStreamTypeMiscInfo
|
||||
//! - kMinidumpStreamTypeThreadList
|
||||
//! - kMinidumpStreamTypeException (if present)
|
||||
//! - kMinidumpStreamTypeModuleList
|
||||
//! - kMinidumpStreamTypeCrashpadInfo (if present)
|
||||
//! - kMinidumpStreamTypeMemoryList
|
||||
//!
|
||||
//! \param[in] process_snapshot The process snapshot to use as source data.
|
||||
//!
|
||||
//! \note Valid in #kStateMutable. No mutator methods may be called before
|
||||
//! this method, and it is not normally necessary to call any mutator
|
||||
//! methods after this method.
|
||||
void InitializeFromSnapshot(const ProcessSnapshot* process_snapshot);
|
||||
|
||||
//! \brief Sets MINIDUMP_HEADER::Timestamp.
|
||||
//!
|
||||
//! \note Valid in #kStateMutable.
|
||||
|
@ -24,6 +24,12 @@
|
||||
#include "minidump/minidump_writable.h"
|
||||
#include "minidump/test/minidump_file_writer_test_util.h"
|
||||
#include "minidump/test/minidump_writable_test_util.h"
|
||||
#include "snapshot/test/test_cpu_context.h"
|
||||
#include "snapshot/test/test_exception_snapshot.h"
|
||||
#include "snapshot/test/test_module_snapshot.h"
|
||||
#include "snapshot/test/test_process_snapshot.h"
|
||||
#include "snapshot/test/test_system_snapshot.h"
|
||||
#include "snapshot/test/test_thread_snapshot.h"
|
||||
#include "util/file/file_writer.h"
|
||||
#include "util/file/string_file_writer.h"
|
||||
|
||||
@ -232,6 +238,185 @@ TEST(MinidumpFileWriter, ZeroLengthStream) {
|
||||
EXPECT_EQ(kStreamOffset, directory[0].Location.Rva);
|
||||
}
|
||||
|
||||
TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
|
||||
const uint32_t kSnapshotTime = 0x4976043c;
|
||||
const timeval kSnapshotTimeval = { implicit_cast<time_t>(kSnapshotTime), 0 };
|
||||
|
||||
TestProcessSnapshot process_snapshot;
|
||||
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
|
||||
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
|
||||
StringFileWriter file_writer;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
|
||||
|
||||
const MINIDUMP_DIRECTORY* directory;
|
||||
const MINIDUMP_HEADER* header =
|
||||
MinidumpHeaderAtStart(file_writer.string(), &directory);
|
||||
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 5, kSnapshotTime));
|
||||
ASSERT_TRUE(directory);
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_SYSTEM_INFO>(
|
||||
file_writer.string(), directory[0].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMiscInfo, directory[1].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MISC_INFO_4>(
|
||||
file_writer.string(), directory[1].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeThreadList, directory[2].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
|
||||
file_writer.string(), directory[2].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeModuleList, directory[3].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
|
||||
file_writer.string(), directory[3].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMemoryList, directory[4].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
file_writer.string(), directory[4].Location));
|
||||
}
|
||||
|
||||
TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) {
|
||||
// In a 32-bit environment, this will give a “timestamp out of range” warning,
|
||||
// but the test should complete without failure.
|
||||
const uint32_t kSnapshotTime = 0xfd469ab8;
|
||||
const timeval kSnapshotTimeval = { implicit_cast<time_t>(kSnapshotTime), 0 };
|
||||
|
||||
TestProcessSnapshot process_snapshot;
|
||||
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
|
||||
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
|
||||
auto thread_snapshot = make_scoped_ptr(new TestThreadSnapshot());
|
||||
InitializeCPUContextX86_64(thread_snapshot->MutableContext(), 5);
|
||||
process_snapshot.AddThread(thread_snapshot.Pass());
|
||||
|
||||
auto exception_snapshot = make_scoped_ptr(new TestExceptionSnapshot());
|
||||
InitializeCPUContextX86_64(exception_snapshot->MutableContext(), 11);
|
||||
process_snapshot.SetException(exception_snapshot.Pass());
|
||||
|
||||
// The module does not have anything that needs to be represented in a
|
||||
// MinidumpModuleCrashpadInfo structure, so no such structure is expected to
|
||||
// be present, which will in turn suppress the addition of a
|
||||
// MinidumpCrashpadInfo stream.
|
||||
auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot());
|
||||
process_snapshot.AddModule(module_snapshot.Pass());
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
|
||||
StringFileWriter file_writer;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
|
||||
|
||||
const MINIDUMP_DIRECTORY* directory;
|
||||
const MINIDUMP_HEADER* header =
|
||||
MinidumpHeaderAtStart(file_writer.string(), &directory);
|
||||
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 6, kSnapshotTime));
|
||||
ASSERT_TRUE(directory);
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_SYSTEM_INFO>(
|
||||
file_writer.string(), directory[0].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMiscInfo, directory[1].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MISC_INFO_4>(
|
||||
file_writer.string(), directory[1].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeThreadList, directory[2].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
|
||||
file_writer.string(), directory[2].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeException, directory[3].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_EXCEPTION_STREAM>(
|
||||
file_writer.string(), directory[3].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeModuleList, directory[4].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
|
||||
file_writer.string(), directory[4].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMemoryList, directory[5].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
file_writer.string(), directory[5].Location));
|
||||
}
|
||||
|
||||
TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) {
|
||||
const uint32_t kSnapshotTime = 0x15393bd3;
|
||||
const timeval kSnapshotTimeval = { implicit_cast<time_t>(kSnapshotTime), 0 };
|
||||
|
||||
TestProcessSnapshot process_snapshot;
|
||||
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
|
||||
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
|
||||
auto thread_snapshot = make_scoped_ptr(new TestThreadSnapshot());
|
||||
InitializeCPUContextX86_64(thread_snapshot->MutableContext(), 5);
|
||||
process_snapshot.AddThread(thread_snapshot.Pass());
|
||||
|
||||
auto exception_snapshot = make_scoped_ptr(new TestExceptionSnapshot());
|
||||
InitializeCPUContextX86_64(exception_snapshot->MutableContext(), 11);
|
||||
process_snapshot.SetException(exception_snapshot.Pass());
|
||||
|
||||
// The module needs an annotation for the MinidumpCrashpadInfo stream to be
|
||||
// considered useful and be included.
|
||||
auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot());
|
||||
std::vector<std::string> annotations_list(1, std::string("annotation"));
|
||||
module_snapshot->SetAnnotationsVector(annotations_list);
|
||||
process_snapshot.AddModule(module_snapshot.Pass());
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
|
||||
StringFileWriter file_writer;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
|
||||
|
||||
const MINIDUMP_DIRECTORY* directory;
|
||||
const MINIDUMP_HEADER* header =
|
||||
MinidumpHeaderAtStart(file_writer.string(), &directory);
|
||||
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 7, kSnapshotTime));
|
||||
ASSERT_TRUE(directory);
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_SYSTEM_INFO>(
|
||||
file_writer.string(), directory[0].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMiscInfo, directory[1].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MISC_INFO_4>(
|
||||
file_writer.string(), directory[1].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeThreadList, directory[2].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
|
||||
file_writer.string(), directory[2].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeException, directory[3].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_EXCEPTION_STREAM>(
|
||||
file_writer.string(), directory[3].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeModuleList, directory[4].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
|
||||
file_writer.string(), directory[4].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeCrashpadInfo, directory[5].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MinidumpCrashpadInfo>(
|
||||
file_writer.string(), directory[5].Location));
|
||||
|
||||
EXPECT_EQ(kMinidumpStreamTypeMemoryList, directory[6].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
file_writer.string(), directory[6].Location));
|
||||
}
|
||||
|
||||
TEST(MinidumpFileWriterDeathTest, SameStreamType) {
|
||||
MinidumpFileWriter minidump_file;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user