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:
Mark Mentovai 2014-10-29 11:38:49 -04:00
parent 7f30a9ebef
commit 84b44610cf
3 changed files with 252 additions and 1 deletions

View File

@ -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);

View File

@ -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 objects data. //! \brief Returns a MINIDUMP_MODULE referencing this objects 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

View File

@ -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());