crashpad/minidump/minidump_module_writer.h

393 lines
14 KiB
C
Raw Normal View History

// Copyright 2014 The Crashpad Authors
//
// 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_MINIDUMP_MINIDUMP_MODULE_WRITER_H_
#define CRASHPAD_MINIDUMP_MINIDUMP_MODULE_WRITER_H_
#include <windows.h>
#include <dbghelp.h>
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
#include <memory>
#include <string>
#include <vector>
#include "minidump/minidump_extensions.h"
#include "minidump/minidump_stream_writer.h"
#include "minidump/minidump_writable.h"
namespace crashpad {
class ModuleSnapshot;
namespace internal {
class MinidumpUTF16StringWriter;
} // namespace internal
//! \brief The base class for writers of CodeView records referenced by
//! MINIDUMP_MODULE::CvRecord in minidump files.
class MinidumpModuleCodeViewRecordWriter : public internal::MinidumpWritable {
public:
MinidumpModuleCodeViewRecordWriter(
const MinidumpModuleCodeViewRecordWriter&) = delete;
MinidumpModuleCodeViewRecordWriter& operator=(
const MinidumpModuleCodeViewRecordWriter&) = delete;
~MinidumpModuleCodeViewRecordWriter() override;
protected:
MinidumpModuleCodeViewRecordWriter() : MinidumpWritable() {}
};
namespace internal {
//! \brief The base class for writers of CodeView records that serve as links to
//! `.pdb` (program database) files.
template <typename CodeViewRecordType>
class MinidumpModuleCodeViewRecordPDBLinkWriter
: public MinidumpModuleCodeViewRecordWriter {
public:
MinidumpModuleCodeViewRecordPDBLinkWriter(
const MinidumpModuleCodeViewRecordPDBLinkWriter&) = delete;
MinidumpModuleCodeViewRecordPDBLinkWriter& operator=(
const MinidumpModuleCodeViewRecordPDBLinkWriter&) = delete;
//! \brief Sets the name of the `.pdb` file being linked to.
void SetPDBName(const std::string& pdb_name) { pdb_name_ = pdb_name; }
protected:
MinidumpModuleCodeViewRecordPDBLinkWriter();
~MinidumpModuleCodeViewRecordPDBLinkWriter() override;
// MinidumpWritable:
size_t SizeOfObject() override;
bool WriteObject(FileWriterInterface* file_writer) override;
//! \brief Returns a pointer to the raw CodeView records data.
//!
//! Subclasses can use this to set fields in their codeview records other than
//! the `pdb_name` field.
CodeViewRecordType* codeview_record() { return &codeview_record_; }
private:
CodeViewRecordType codeview_record_;
std::string pdb_name_;
};
} // namespace internal
//! \brief The writer for a CodeViewRecordPDB20 object in a minidump file.
//!
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer or
//! MinidumpModuleCodeViewRecordBuildIDWriter instead.
class MinidumpModuleCodeViewRecordPDB20Writer final
: public internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
CodeViewRecordPDB20> {
public:
MinidumpModuleCodeViewRecordPDB20Writer()
: internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
CodeViewRecordPDB20>() {}
MinidumpModuleCodeViewRecordPDB20Writer(
const MinidumpModuleCodeViewRecordPDB20Writer&) = delete;
MinidumpModuleCodeViewRecordPDB20Writer& operator=(
const MinidumpModuleCodeViewRecordPDB20Writer&) = delete;
~MinidumpModuleCodeViewRecordPDB20Writer() override;
//! \brief Sets CodeViewRecordPDB20::timestamp and CodeViewRecordPDB20::age.
void SetTimestampAndAge(time_t timestamp, uint32_t age);
};
//! \brief The writer for a CodeViewRecordPDB70 object in a minidump file.
class MinidumpModuleCodeViewRecordPDB70Writer final
: public internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
CodeViewRecordPDB70> {
public:
MinidumpModuleCodeViewRecordPDB70Writer()
: internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
CodeViewRecordPDB70>() {}
MinidumpModuleCodeViewRecordPDB70Writer(
const MinidumpModuleCodeViewRecordPDB70Writer&) = delete;
MinidumpModuleCodeViewRecordPDB70Writer& operator=(
const MinidumpModuleCodeViewRecordPDB70Writer&) = delete;
~MinidumpModuleCodeViewRecordPDB70Writer() override;
//! \brief Initializes the CodeViewRecordPDB70 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 CodeViewRecordPDB70::uuid and CodeViewRecordPDB70::age.
void SetUUIDAndAge(const UUID& uuid, uint32_t age) {
codeview_record()->uuid = uuid;
codeview_record()->age = age;
}
};
//! \brief The writer for a CodeViewRecordBuildID object in a minidump file.
class MinidumpModuleCodeViewRecordBuildIDWriter final
: public MinidumpModuleCodeViewRecordWriter {
public:
MinidumpModuleCodeViewRecordBuildIDWriter();
MinidumpModuleCodeViewRecordBuildIDWriter(
const MinidumpModuleCodeViewRecordBuildIDWriter&) = delete;
MinidumpModuleCodeViewRecordBuildIDWriter& operator=(
const MinidumpModuleCodeViewRecordBuildIDWriter&) = delete;
~MinidumpModuleCodeViewRecordBuildIDWriter() override;
//! \brief Sets the build ID used for symbol lookup.
void SetBuildID(const std::vector<uint8_t>& build_id);
private:
// MinidumpWritable:
size_t SizeOfObject() override;
bool WriteObject(FileWriterInterface* file_writer) override;
std::vector<uint8_t> build_id_;
};
//! \brief The writer for an IMAGE_DEBUG_MISC object in a minidump file.
//!
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead.
class MinidumpModuleMiscDebugRecordWriter final
: public internal::MinidumpWritable {
public:
MinidumpModuleMiscDebugRecordWriter();
MinidumpModuleMiscDebugRecordWriter(
const MinidumpModuleMiscDebugRecordWriter&) = delete;
MinidumpModuleMiscDebugRecordWriter& operator=(
const MinidumpModuleMiscDebugRecordWriter&) = delete;
~MinidumpModuleMiscDebugRecordWriter() override;
//! \brief Sets IMAGE_DEBUG_MISC::DataType.
void SetDataType(uint32_t data_type) {
image_debug_misc_.DataType = data_type;
}
//! \brief Sets IMAGE_DEBUG_MISC::Data, IMAGE_DEBUG_MISC::Length, and
//! IMAGE_DEBUG_MISC::Unicode.
//!
//! If \a utf16 is `true`, \a data will be treated as UTF-8 data and will be
//! converted to UTF-16, and IMAGE_DEBUG_MISC::Unicode will be set to `1`.
//! Otherwise, \a data will be used as-is and IMAGE_DEBUG_MISC::Unicode will
//! be set to `0`.
void SetData(const std::string& data, bool utf16);
protected:
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
bool WriteObject(FileWriterInterface* file_writer) override;
private:
IMAGE_DEBUG_MISC image_debug_misc_;
std::string data_;
std::u16string data_utf16_;
};
//! \brief The writer for a MINIDUMP_MODULE object in a minidump file.
//!
//! Because MINIDUMP_MODULE objects only appear as elements of
//! MINIDUMP_MODULE_LIST objects, this class does not write any data on its own.
//! It makes its MINIDUMP_MODULE data available to its MinidumpModuleListWriter
//! parent, which writes it as part of a MINIDUMP_MODULE_LIST.
class MinidumpModuleWriter final : public internal::MinidumpWritable {
public:
MinidumpModuleWriter();
MinidumpModuleWriter(const MinidumpModuleWriter&) = delete;
MinidumpModuleWriter& operator=(const MinidumpModuleWriter&) = delete;
~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.
//!
//! This method is expected to be called by a MinidumpModuleListWriter in
//! order to obtain a MINIDUMP_MODULE to include in its list.
//!
//! \note Valid in #kStateWritable.
const MINIDUMP_MODULE* MinidumpModule() const;
//! \brief Arranges for MINIDUMP_MODULE::ModuleNameRva to point to a
//! MINIDUMP_STRING containing \a name.
//!
//! A name is required in all MINIDUMP_MODULE objects.
//!
//! \note Valid in #kStateMutable.
void SetName(const std::string& name);
//! \brief Arranges for MINIDUMP_MODULE::CvRecord to point to a CodeView
//! record to be written by \a codeview_record.
//!
//! This object takes ownership of \a codeview_record and becomes its parent
//! in the overall tree of internal::MinidumpWritable objects.
//!
//! \note Valid in #kStateMutable.
void SetCodeViewRecord(
std::unique_ptr<MinidumpModuleCodeViewRecordWriter> codeview_record);
//! \brief Arranges for MINIDUMP_MODULE::MiscRecord to point to an
//! IMAGE_DEBUG_MISC object to be written by \a misc_debug_record.
//!
//! This object takes ownership of \a misc_debug_record and becomes its parent
//! in the overall tree of internal::MinidumpWritable objects.
//!
//! \note Valid in #kStateMutable.
void SetMiscDebugRecord(
std::unique_ptr<MinidumpModuleMiscDebugRecordWriter> misc_debug_record);
//! \brief Sets IMAGE_DEBUG_MISC::BaseOfImage.
void SetImageBaseAddress(uint64_t image_base_address) {
module_.BaseOfImage = image_base_address;
}
//! \brief Sets IMAGE_DEBUG_MISC::SizeOfImage.
void SetImageSize(uint32_t image_size) { module_.SizeOfImage = image_size; }
//! \brief Sets IMAGE_DEBUG_MISC::CheckSum.
void SetChecksum(uint32_t checksum) { module_.CheckSum = checksum; }
//! \brief Sets IMAGE_DEBUG_MISC::TimeDateStamp.
//!
//! \note Valid in #kStateMutable.
void SetTimestamp(time_t timestamp);
//! \brief Sets \ref VS_FIXEDFILEINFO::dwFileVersionMS
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileVersionMS" and \ref
//! VS_FIXEDFILEINFO::dwFileVersionLS
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileVersionLS".
//!
//! \note Valid in #kStateMutable.
void SetFileVersion(uint16_t version_0,
uint16_t version_1,
uint16_t version_2,
uint16_t version_3);
//! \brief Sets \ref VS_FIXEDFILEINFO::dwProductVersionMS
//! "IMAGE_DEBUG_MISC::VersionInfo::dwProductVersionMS" and \ref
//! VS_FIXEDFILEINFO::dwProductVersionLS
//! "IMAGE_DEBUG_MISC::VersionInfo::dwProductVersionLS".
//!
//! \note Valid in #kStateMutable.
void SetProductVersion(uint16_t version_0,
uint16_t version_1,
uint16_t version_2,
uint16_t version_3);
//! \brief Sets \ref VS_FIXEDFILEINFO::dwFileFlags
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileFlags" and \ref
//! VS_FIXEDFILEINFO::dwFileFlagsMask
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileFlagsMask".
//!
//! \note Valid in #kStateMutable.
void SetFileFlagsAndMask(uint32_t file_flags, uint32_t file_flags_mask);
//! \brief Sets \ref VS_FIXEDFILEINFO::dwFileOS
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileOS".
void SetFileOS(uint32_t file_os) { module_.VersionInfo.dwFileOS = file_os; }
//! \brief Sets \ref VS_FIXEDFILEINFO::dwFileType
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileType" and \ref
//! VS_FIXEDFILEINFO::dwFileSubtype
//! "IMAGE_DEBUG_MISC::VersionInfo::dwFileSubtype".
void SetFileTypeAndSubtype(uint32_t file_type, uint32_t file_subtype) {
module_.VersionInfo.dwFileType = file_type;
module_.VersionInfo.dwFileSubtype = file_subtype;
}
protected:
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
std::vector<MinidumpWritable*> Children() override;
bool WriteObject(FileWriterInterface* file_writer) override;
private:
MINIDUMP_MODULE module_;
std::unique_ptr<internal::MinidumpUTF16StringWriter> name_;
std::unique_ptr<MinidumpModuleCodeViewRecordWriter> codeview_record_;
std::unique_ptr<MinidumpModuleMiscDebugRecordWriter> misc_debug_record_;
};
//! \brief The writer for a MINIDUMP_MODULE_LIST stream in a minidump file,
//! containing a list of MINIDUMP_MODULE objects.
class MinidumpModuleListWriter final : public internal::MinidumpStreamWriter {
public:
MinidumpModuleListWriter();
MinidumpModuleListWriter(const MinidumpModuleListWriter&) = delete;
MinidumpModuleListWriter& operator=(const MinidumpModuleListWriter&) = delete;
~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. AddModule() may not be called before this
//! method, and it is not normally necessary to call AddModule() after
//! this method.
void InitializeFromSnapshot(
const std::vector<const ModuleSnapshot*>& module_snapshots);
//! \brief Adds a MinidumpModuleWriter to the MINIDUMP_MODULE_LIST.
//!
//! This object takes ownership of \a module and becomes its parent in the
//! overall tree of internal::MinidumpWritable objects.
//!
//! \note Valid in #kStateMutable.
void AddModule(std::unique_ptr<MinidumpModuleWriter> module);
protected:
// MinidumpWritable:
bool Freeze() override;
size_t SizeOfObject() override;
std::vector<MinidumpWritable*> Children() override;
bool WriteObject(FileWriterInterface* file_writer) override;
// MinidumpStreamWriter:
MinidumpStreamType StreamType() const override;
private:
std::vector<std::unique_ptr<MinidumpModuleWriter>> modules_;
MINIDUMP_MODULE_LIST module_list_base_;
};
} // namespace crashpad
#endif // CRASHPAD_MINIDUMP_MINIDUMP_MODULE_WRITER_H_