mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08:00
minidump: Add InitializeFromSnapshot() for MinidumpModuleWriter and
MinidumpModuleListWriter. TEST=minidump_test R=rsesek@chromium.org Review URL: https://codereview.chromium.org/682263002
This commit is contained in:
parent
7f30a9ebef
commit
84b44610cf
@ -16,10 +16,14 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "minidump/minidump_string_writer.h"
|
#include "minidump/minidump_string_writer.h"
|
||||||
#include "minidump/minidump_writer_util.h"
|
#include "minidump/minidump_writer_util.h"
|
||||||
|
#include "snapshot/module_snapshot.h"
|
||||||
#include "util/file/file_writer.h"
|
#include "util/file/file_writer.h"
|
||||||
|
#include "util/numeric/in_range_cast.h"
|
||||||
#include "util/numeric/safe_assignment.h"
|
#include "util/numeric/safe_assignment.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
@ -96,6 +100,25 @@ MinidumpModuleCodeViewRecordPDB70Writer::
|
|||||||
~MinidumpModuleCodeViewRecordPDB70Writer() {
|
~MinidumpModuleCodeViewRecordPDB70Writer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinidumpModuleCodeViewRecordPDB70Writer::InitializeFromSnapshot(
|
||||||
|
const ModuleSnapshot* module_snapshot) {
|
||||||
|
DCHECK_EQ(state(), kStateMutable);
|
||||||
|
|
||||||
|
std::string name = module_snapshot->Name();
|
||||||
|
std::string leaf_name;
|
||||||
|
size_t last_slash = name.find_last_of('/');
|
||||||
|
if (last_slash != std::string::npos) {
|
||||||
|
leaf_name = name.substr(last_slash + 1);
|
||||||
|
} else {
|
||||||
|
leaf_name = name;
|
||||||
|
}
|
||||||
|
SetPDBName(leaf_name);
|
||||||
|
|
||||||
|
UUID uuid;
|
||||||
|
module_snapshot->UUID(&uuid);
|
||||||
|
SetUUIDAndAge(uuid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
MinidumpModuleMiscDebugRecordWriter::MinidumpModuleMiscDebugRecordWriter()
|
MinidumpModuleMiscDebugRecordWriter::MinidumpModuleMiscDebugRecordWriter()
|
||||||
: internal::MinidumpWritable(),
|
: internal::MinidumpWritable(),
|
||||||
image_debug_misc_(),
|
image_debug_misc_(),
|
||||||
@ -186,6 +209,48 @@ MinidumpModuleWriter::MinidumpModuleWriter()
|
|||||||
MinidumpModuleWriter::~MinidumpModuleWriter() {
|
MinidumpModuleWriter::~MinidumpModuleWriter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinidumpModuleWriter::InitializeFromSnapshot(
|
||||||
|
const ModuleSnapshot* module_snapshot) {
|
||||||
|
DCHECK_EQ(state(), kStateMutable);
|
||||||
|
DCHECK(!name_);
|
||||||
|
DCHECK(!codeview_record_);
|
||||||
|
DCHECK(!misc_debug_record_);
|
||||||
|
|
||||||
|
SetName(module_snapshot->Name());
|
||||||
|
|
||||||
|
SetImageBaseAddress(module_snapshot->Address());
|
||||||
|
SetImageSize(InRangeCast<uint32_t>(module_snapshot->Size(),
|
||||||
|
std::numeric_limits<uint32_t>::max()));
|
||||||
|
SetTimestamp(module_snapshot->Timestamp());
|
||||||
|
|
||||||
|
uint16_t v[4];
|
||||||
|
module_snapshot->FileVersion(&v[0], &v[1], &v[2], &v[3]);
|
||||||
|
SetFileVersion(v[0], v[1], v[2], v[3]);
|
||||||
|
|
||||||
|
module_snapshot->SourceVersion(&v[0], &v[1], &v[2], &v[3]);
|
||||||
|
SetProductVersion(v[0], v[1], v[2], v[3]);
|
||||||
|
|
||||||
|
uint32_t file_type;
|
||||||
|
switch (module_snapshot->GetModuleType()) {
|
||||||
|
case ModuleSnapshot::kModuleTypeExecutable:
|
||||||
|
file_type = VFT_APP;
|
||||||
|
break;
|
||||||
|
case ModuleSnapshot::kModuleTypeSharedLibrary:
|
||||||
|
case ModuleSnapshot::kModuleTypeLoadableModule:
|
||||||
|
file_type = VFT_DLL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
file_type = VFT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SetFileTypeAndSubtype(file_type, VFT2_UNKNOWN);
|
||||||
|
|
||||||
|
auto codeview_record =
|
||||||
|
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB70Writer());
|
||||||
|
codeview_record->InitializeFromSnapshot(module_snapshot);
|
||||||
|
SetCodeViewRecord(codeview_record.Pass());
|
||||||
|
}
|
||||||
|
|
||||||
const MINIDUMP_MODULE* MinidumpModuleWriter::MinidumpModule() const {
|
const MINIDUMP_MODULE* MinidumpModuleWriter::MinidumpModule() const {
|
||||||
DCHECK_EQ(state(), kStateWritable);
|
DCHECK_EQ(state(), kStateWritable);
|
||||||
|
|
||||||
@ -316,6 +381,18 @@ MinidumpModuleListWriter::MinidumpModuleListWriter()
|
|||||||
MinidumpModuleListWriter::~MinidumpModuleListWriter() {
|
MinidumpModuleListWriter::~MinidumpModuleListWriter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinidumpModuleListWriter::InitializeFromSnapshot(
|
||||||
|
const std::vector<const ModuleSnapshot*>& module_snapshots) {
|
||||||
|
DCHECK_EQ(state(), kStateMutable);
|
||||||
|
DCHECK(modules_.empty());
|
||||||
|
|
||||||
|
for (const ModuleSnapshot* module_snapshot : module_snapshots) {
|
||||||
|
auto module = make_scoped_ptr(new MinidumpModuleWriter());
|
||||||
|
module->InitializeFromSnapshot(module_snapshot);
|
||||||
|
AddModule(module.Pass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MinidumpModuleListWriter::AddModule(
|
void MinidumpModuleListWriter::AddModule(
|
||||||
scoped_ptr<MinidumpModuleWriter> module) {
|
scoped_ptr<MinidumpModuleWriter> module) {
|
||||||
DCHECK_EQ(state(), kStateMutable);
|
DCHECK_EQ(state(), kStateMutable);
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
|
class ModuleSnapshot;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
class MinidumpUTF16StringWriter;
|
class MinidumpUTF16StringWriter;
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
@ -117,6 +119,16 @@ class MinidumpModuleCodeViewRecordPDB70Writer final
|
|||||||
|
|
||||||
~MinidumpModuleCodeViewRecordPDB70Writer() override;
|
~MinidumpModuleCodeViewRecordPDB70Writer() override;
|
||||||
|
|
||||||
|
//! \brief Initializes the MinidumpModuleCodeViewRecordPDB70 based on \a
|
||||||
|
//! module_snapshot.
|
||||||
|
//!
|
||||||
|
//! \param[in] module_snapshot The module 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 ModuleSnapshot* module_snapshot);
|
||||||
|
|
||||||
//! \brief Sets MinidumpModuleCodeViewRecordPDB70::uuid and
|
//! \brief Sets MinidumpModuleCodeViewRecordPDB70::uuid and
|
||||||
//! MinidumpModuleCodeViewRecordPDB70::age.
|
//! MinidumpModuleCodeViewRecordPDB70::age.
|
||||||
void SetUUIDAndAge(const UUID& uuid, uint32_t age) {
|
void SetUUIDAndAge(const UUID& uuid, uint32_t age) {
|
||||||
@ -176,6 +188,15 @@ class MinidumpModuleWriter final : public internal::MinidumpWritable {
|
|||||||
MinidumpModuleWriter();
|
MinidumpModuleWriter();
|
||||||
~MinidumpModuleWriter() override;
|
~MinidumpModuleWriter() override;
|
||||||
|
|
||||||
|
//! \brief Initializes the MINIDUMP_MODULE based on \a module_snapshot.
|
||||||
|
//!
|
||||||
|
//! \param[in] module_snapshot The module 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 ModuleSnapshot* module_snapshot);
|
||||||
|
|
||||||
//! \brief Returns a MINIDUMP_MODULE referencing this object’s data.
|
//! \brief Returns a MINIDUMP_MODULE referencing this object’s data.
|
||||||
//!
|
//!
|
||||||
//! This method is expected to be called by a MinidumpModuleListWriter in
|
//! This method is expected to be called by a MinidumpModuleListWriter in
|
||||||
@ -294,6 +315,17 @@ class MinidumpModuleListWriter final : public internal::MinidumpStreamWriter {
|
|||||||
MinidumpModuleListWriter();
|
MinidumpModuleListWriter();
|
||||||
~MinidumpModuleListWriter() override;
|
~MinidumpModuleListWriter() override;
|
||||||
|
|
||||||
|
//! \brief Adds an initialized MINIDUMP_MODULE for each module in \a
|
||||||
|
//! module_snapshots to the MINIDUMP_MODULE_LIST.
|
||||||
|
//!
|
||||||
|
//! \param[in] module_snapshots The module snapshots 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 std::vector<const ModuleSnapshot*>& module_snapshots);
|
||||||
|
|
||||||
//! \brief Adds a MinidumpModuleWriter to the MINIDUMP_MODULE_LIST.
|
//! \brief Adds a MinidumpModuleWriter to the MINIDUMP_MODULE_LIST.
|
||||||
//!
|
//!
|
||||||
//! This object takes ownership of \a module and becomes its parent in the
|
//! This object takes ownership of \a module and becomes its parent in the
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "minidump/minidump_extensions.h"
|
#include "minidump/minidump_extensions.h"
|
||||||
@ -26,8 +27,10 @@
|
|||||||
#include "minidump/test/minidump_file_writer_test_util.h"
|
#include "minidump/test/minidump_file_writer_test_util.h"
|
||||||
#include "minidump/test/minidump_string_writer_test_util.h"
|
#include "minidump/test/minidump_string_writer_test_util.h"
|
||||||
#include "minidump/test/minidump_writable_test_util.h"
|
#include "minidump/test/minidump_writable_test_util.h"
|
||||||
|
#include "snapshot/test/test_module_snapshot.h"
|
||||||
#include "util/file/string_file_writer.h"
|
#include "util/file/string_file_writer.h"
|
||||||
#include "util/misc/uuid.h"
|
#include "util/misc/uuid.h"
|
||||||
|
#include "util/stdlib/pointer_container.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
namespace test {
|
||||||
@ -606,7 +609,146 @@ TEST(MinidumpModuleWriter, ThreeModules) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MinidumpSystemInfoWriterDeathTest, NoModuleName) {
|
void InitializeTestModuleSnapshotFromMinidumpModule(
|
||||||
|
TestModuleSnapshot* module_snapshot,
|
||||||
|
const MINIDUMP_MODULE& minidump_module,
|
||||||
|
const std::string& name,
|
||||||
|
const crashpad::UUID& uuid) {
|
||||||
|
module_snapshot->SetName(name);
|
||||||
|
|
||||||
|
module_snapshot->SetAddressAndSize(minidump_module.BaseOfImage,
|
||||||
|
minidump_module.SizeOfImage);
|
||||||
|
module_snapshot->SetTimestamp(minidump_module.TimeDateStamp);
|
||||||
|
module_snapshot->SetFileVersion(
|
||||||
|
minidump_module.VersionInfo.dwFileVersionMS >> 16,
|
||||||
|
minidump_module.VersionInfo.dwFileVersionMS & 0xffff,
|
||||||
|
minidump_module.VersionInfo.dwFileVersionLS >> 16,
|
||||||
|
minidump_module.VersionInfo.dwFileVersionLS & 0xffff);
|
||||||
|
module_snapshot->SetSourceVersion(
|
||||||
|
minidump_module.VersionInfo.dwProductVersionMS >> 16,
|
||||||
|
minidump_module.VersionInfo.dwProductVersionMS & 0xffff,
|
||||||
|
minidump_module.VersionInfo.dwProductVersionLS >> 16,
|
||||||
|
minidump_module.VersionInfo.dwProductVersionLS & 0xffff);
|
||||||
|
|
||||||
|
ModuleSnapshot::ModuleType module_type;
|
||||||
|
switch (minidump_module.VersionInfo.dwFileType) {
|
||||||
|
case VFT_APP:
|
||||||
|
module_type = ModuleSnapshot::kModuleTypeExecutable;
|
||||||
|
break;
|
||||||
|
case VFT_DLL:
|
||||||
|
module_type = ModuleSnapshot::kModuleTypeSharedLibrary;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
module_type = ModuleSnapshot::kModuleTypeUnknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
module_snapshot->SetModuleType(module_type);
|
||||||
|
|
||||||
|
module_snapshot->SetUUID(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
|
||||||
|
MINIDUMP_MODULE expect_modules[3] = {};
|
||||||
|
const char* module_paths[3] = {};
|
||||||
|
const char* module_names[3] = {};
|
||||||
|
UUID uuids[3] = {};
|
||||||
|
|
||||||
|
static_assert(arraysize(expect_modules) == arraysize(module_paths),
|
||||||
|
"array sizes must be equal");
|
||||||
|
static_assert(arraysize(expect_modules) == arraysize(module_names),
|
||||||
|
"array sizes must be equal");
|
||||||
|
static_assert(arraysize(expect_modules) == arraysize(uuids),
|
||||||
|
"array sizes must be equal");
|
||||||
|
|
||||||
|
expect_modules[0].BaseOfImage = 0x100101000;
|
||||||
|
expect_modules[0].SizeOfImage = 0xf000;
|
||||||
|
expect_modules[0].TimeDateStamp = 0x01234567;
|
||||||
|
expect_modules[0].VersionInfo.dwFileVersionMS = 0x00010002;
|
||||||
|
expect_modules[0].VersionInfo.dwFileVersionLS = 0x00030004;
|
||||||
|
expect_modules[0].VersionInfo.dwProductVersionMS = 0x00050006;
|
||||||
|
expect_modules[0].VersionInfo.dwProductVersionLS = 0x00070008;
|
||||||
|
expect_modules[0].VersionInfo.dwFileType = VFT_APP;
|
||||||
|
module_paths[0] = "/usr/bin/true";
|
||||||
|
module_names[0] = "true";
|
||||||
|
const uint8_t kUUIDBytes0[16] =
|
||||||
|
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||||
|
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
|
||||||
|
uuids[0].InitializeFromBytes(kUUIDBytes0);
|
||||||
|
|
||||||
|
expect_modules[1].BaseOfImage = 0x200202000;
|
||||||
|
expect_modules[1].SizeOfImage = 0x1e1000;
|
||||||
|
expect_modules[1].TimeDateStamp = 0x89abcdef;
|
||||||
|
expect_modules[1].VersionInfo.dwFileVersionMS = 0x0009000a;
|
||||||
|
expect_modules[1].VersionInfo.dwFileVersionLS = 0x000b000c;
|
||||||
|
expect_modules[1].VersionInfo.dwProductVersionMS = 0x000d000e;
|
||||||
|
expect_modules[1].VersionInfo.dwProductVersionLS = 0x000f0000;
|
||||||
|
expect_modules[1].VersionInfo.dwFileType = VFT_DLL;
|
||||||
|
module_paths[1] = "/usr/lib/libSystem.B.dylib";
|
||||||
|
module_names[1] = "libSystem.B.dylib";
|
||||||
|
const uint8_t kUUIDBytes1[16] =
|
||||||
|
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||||
|
uuids[1].InitializeFromBytes(kUUIDBytes1);
|
||||||
|
|
||||||
|
expect_modules[2].BaseOfImage = 0x300303000;
|
||||||
|
expect_modules[2].SizeOfImage = 0x2d000;
|
||||||
|
expect_modules[2].TimeDateStamp = 0x76543210;
|
||||||
|
expect_modules[2].VersionInfo.dwFileVersionMS = 0x11112222;
|
||||||
|
expect_modules[2].VersionInfo.dwFileVersionLS = 0x33334444;
|
||||||
|
expect_modules[2].VersionInfo.dwProductVersionMS = 0x9999aaaa;
|
||||||
|
expect_modules[2].VersionInfo.dwProductVersionLS = 0xbbbbcccc;
|
||||||
|
expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN;
|
||||||
|
module_paths[2] = "/usr/lib/dyld";
|
||||||
|
module_names[2] = "dyld";
|
||||||
|
const uint8_t kUUIDBytes2[16] =
|
||||||
|
{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||||
|
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0};
|
||||||
|
uuids[2].InitializeFromBytes(kUUIDBytes2);
|
||||||
|
|
||||||
|
PointerVector<TestModuleSnapshot> module_snapshots_owner;
|
||||||
|
std::vector<const ModuleSnapshot*> module_snapshots;
|
||||||
|
for (size_t index = 0; index < arraysize(expect_modules); ++index) {
|
||||||
|
TestModuleSnapshot* module_snapshot = new TestModuleSnapshot();
|
||||||
|
module_snapshots_owner.push_back(module_snapshot);
|
||||||
|
InitializeTestModuleSnapshotFromMinidumpModule(module_snapshot,
|
||||||
|
expect_modules[index],
|
||||||
|
module_paths[index],
|
||||||
|
uuids[index]);
|
||||||
|
module_snapshots.push_back(module_snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto module_list_writer = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||||
|
module_list_writer->InitializeFromSnapshot(module_snapshots);
|
||||||
|
|
||||||
|
MinidumpFileWriter minidump_file_writer;
|
||||||
|
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||||
|
|
||||||
|
StringFileWriter file_writer;
|
||||||
|
ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
|
||||||
|
|
||||||
|
const MINIDUMP_MODULE_LIST* module_list;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
GetModuleListStream(file_writer.string(), &module_list));
|
||||||
|
|
||||||
|
ASSERT_EQ(3u, module_list->NumberOfModules);
|
||||||
|
|
||||||
|
for (size_t index = 0; index < module_list->NumberOfModules; ++index) {
|
||||||
|
SCOPED_TRACE(base::StringPrintf("index %zu", index));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(ExpectModule(&expect_modules[index],
|
||||||
|
&module_list->Modules[index],
|
||||||
|
file_writer.string(),
|
||||||
|
module_paths[index],
|
||||||
|
module_names[index],
|
||||||
|
&uuids[index],
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MinidumpModuleWriterDeathTest, NoModuleName) {
|
||||||
MinidumpFileWriter minidump_file_writer;
|
MinidumpFileWriter minidump_file_writer;
|
||||||
auto module_list_writer = make_scoped_ptr(new MinidumpModuleListWriter());
|
auto module_list_writer = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||||
auto module_writer = make_scoped_ptr(new MinidumpModuleWriter());
|
auto module_writer = make_scoped_ptr(new MinidumpModuleWriter());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user