393 lines
14 KiB
C++
393 lines
14 KiB
C++
// 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 record’s 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 object’s 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_
|