diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h
index 64d599d4..8537687a 100644
--- a/compat/non_win/dbghelp.h
+++ b/compat/non_win/dbghelp.h
@@ -535,16 +535,14 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MODULE {
VS_FIXEDFILEINFO VersionInfo;
//! \brief A pointer to the module’s CodeView record, typically a link to its
- //! debugging information in crashpad::MinidumpModuleCodeViewRecordPDB70
- //! format.
+ //! debugging information in crashpad::CodeViewRecordPDB70 format.
//!
//! The specific format of the CodeView record is indicated by its signature,
//! the first 32-bit value in the structure. For links to debugging
//! information in contemporary usage, this is normally a
- //! crashpad::MinidumpModuleCodeViewRecordPDB70 structure, but may be a
- //! crashpad::MinidumpModuleCodeViewRecordPDB20 structure instead. These
- //! structures identify a link to debugging data within a `.pdb` (Program
- //! Database) file. See Matching
//! Debug Information, PDB Files.
//!
@@ -565,8 +563,8 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MODULE {
//! On Windows, the CodeView record is taken from a module’s
//! IMAGE_DEBUG_DIRECTORY entry whose Type field has the value
//! IMAGE_DEBUG_TYPE_CODEVIEW (`2`), if any. Records in
- //! crashpad::MinidumpModuleCodeViewRecordPDB70 format are generated by Visual
- //! Studio .NET (2002) (version 7.0) and later.
+ //! crashpad::CodeViewRecordPDB70 format are generated by Visual Studio .NET
+ //! (2002) (version 7.0) and later.
//!
//! When the CodeView record is not present, the fields of this
//! MINIDUMP_LOCATION_DESCRIPTOR will be `0`.
diff --git a/minidump/minidump_extensions.cc b/minidump/minidump_extensions.cc
index da67d0c5..a956817e 100644
--- a/minidump/minidump_extensions.cc
+++ b/minidump/minidump_extensions.cc
@@ -16,8 +16,6 @@
namespace crashpad {
-const uint32_t MinidumpModuleCodeViewRecordPDB20::kSignature;
-const uint32_t MinidumpModuleCodeViewRecordPDB70::kSignature;
const uint32_t MinidumpModuleCrashpadInfo::kVersion;
const uint32_t MinidumpCrashpadInfo::kVersion;
diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h
index b8bf77a1..95fdbddf 100644
--- a/minidump/minidump_extensions.h
+++ b/minidump/minidump_extensions.h
@@ -22,6 +22,7 @@
#include "base/compiler_specific.h"
#include "build/build_config.h"
+#include "util/misc/pdb_structures.h"
#include "util/misc/uuid.h"
// C4200 is "nonstandard extension used : zero-sized array in struct/union".
@@ -216,112 +217,6 @@ enum MinidumpOS : uint32_t {
kMinidumpOSUnknown = 0xffffffff,
};
-//! \brief A CodeView record linking to a `.pdb` 2.0 file.
-//!
-//! This format provides an indirect link to debugging data by referencing an
-//! external `.pdb` file by its name, timestamp, and age. This structure may be
-//! pointed to by MINIDUMP_MODULE::CvRecord. It has been superseded by
-//! MinidumpModuleCodeViewRecordPDB70.
-//!
-//! For more information about this structure and format, see Matching
-//! Debug Information, PDB Files, and Undocumented
-//! Windows 2000 Secrets, Windows 2000 Debugging Support/Microsoft Symbol
-//! File Internals/CodeView Subsections.
-//!
-//! \sa IMAGE_DEBUG_MISC
-struct MinidumpModuleCodeViewRecordPDB20 {
- //! \brief The magic number identifying this structure version, stored in
- //! #signature.
- //!
- //! In a hex dump, this will appear as “NB10” when produced by a little-endian
- //! machine.
- static const uint32_t kSignature = '01BN';
-
- //! \brief The magic number identifying this structure version, the value of
- //! #kSignature.
- uint32_t signature;
-
- //! \brief The offset to CodeView data.
- //!
- //! In this structure, this field always has the value `0` because no CodeView
- //! data is present, there is only a link to CodeView data stored in an
- //! external file.
- uint32_t offset;
-
- //! \brief The time that the `.pdb` file was created, in `time_t` format, the
- //! number of seconds since the POSIX epoch.
- uint32_t timestamp;
-
- //! \brief The revision of the `.pdb` file.
- //!
- //! A `.pdb` file’s age indicates incremental changes to it. When a `.pdb`
- //! file is created, it has age `1`, and subsequent updates increase this
- //! value.
- uint32_t age;
-
- //! \brief The path or file name of the `.pdb` file associated with the
- //! module.
- //!
- //! This is a NUL-terminated string. On Windows, it will be encoded in the
- //! code page of the system that linked the module. On other operating
- //! systems, UTF-8 may be used.
- uint8_t pdb_name[1];
-};
-
-//! \brief A CodeView record linking to a `.pdb` 7.0 file.
-//!
-//! This format provides an indirect link to debugging data by referencing an
-//! external `.pdb` file by its name, %UUID, and age. This structure may be
-//! pointed to by MINIDUMP_MODULE::CvRecord.
-//!
-//! For more information about this structure and format, see Matching
-//! Debug Information, PDB Files.
-//!
-//! \sa MinidumpModuleCodeViewRecordPDB20
-//! \sa IMAGE_DEBUG_MISC
-struct MinidumpModuleCodeViewRecordPDB70 {
- // UUID has a constructor, which makes it non-POD, which makes this structure
- // non-POD. In order for the default constructor to zero-initialize other
- // members, an explicit constructor must be provided.
- MinidumpModuleCodeViewRecordPDB70()
- : signature(),
- uuid(),
- age(),
- pdb_name() {
- }
-
- //! \brief The magic number identifying this structure version, stored in
- //! #signature.
- //!
- //! In a hex dump, this will appear as “RSDS” when produced by a little-endian
- //! machine.
- static const uint32_t kSignature = 'SDSR';
-
- //! \brief The magic number identifying this structure version, the value of
- //! #kSignature.
- uint32_t signature;
-
- //! \brief The `.pdb` file’s unique identifier.
- UUID uuid;
-
- //! \brief The revision of the `.pdb` file.
- //!
- //! A `.pdb` file’s age indicates incremental changes to it. When a `.pdb`
- //! file is created, it has age `1`, and subsequent updates increase this
- //! value.
- uint32_t age;
-
- //! \brief The path or file name of the `.pdb` file associated with the
- //! module.
- //!
- //! This is a NUL-terminated string. On Windows, it will be encoded in the
- //! code page of the system that linked the module. On other operating
- //! systems, UTF-8 may be used.
- uint8_t pdb_name[1];
-};
//! \brief A list of ::RVA pointers.
struct ALIGNAS(4) PACKED MinidumpRVAList {
diff --git a/minidump/minidump_module_writer.cc b/minidump/minidump_module_writer.cc
index dc5eddfa..33c83a75 100644
--- a/minidump/minidump_module_writer.cc
+++ b/minidump/minidump_module_writer.cc
@@ -77,7 +77,7 @@ bool MinidumpModuleCodeViewRecordPDBLinkWriter::WriteObject(
} // namespace internal
template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB20>;
+ CodeViewRecordPDB20>;
MinidumpModuleCodeViewRecordPDB20Writer::
~MinidumpModuleCodeViewRecordPDB20Writer() {
@@ -95,7 +95,7 @@ void MinidumpModuleCodeViewRecordPDB20Writer::SetTimestampAndAge(
}
template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB70>;
+ CodeViewRecordPDB70>;
MinidumpModuleCodeViewRecordPDB70Writer::
~MinidumpModuleCodeViewRecordPDB70Writer() {
diff --git a/minidump/minidump_module_writer.h b/minidump/minidump_module_writer.h
index 2bec5968..ecf3cb85 100644
--- a/minidump/minidump_module_writer.h
+++ b/minidump/minidump_module_writer.h
@@ -86,42 +86,38 @@ class MinidumpModuleCodeViewRecordPDBLinkWriter
} // namespace internal
-//! \brief The writer for a MinidumpModuleCodeViewRecordPDB20 object in a
-//! minidump file.
+//! \brief The writer for a CodeViewRecordPDB20 object in a minidump file.
//!
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead.
class MinidumpModuleCodeViewRecordPDB20Writer final
: public internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB20> {
+ CodeViewRecordPDB20> {
public:
MinidumpModuleCodeViewRecordPDB20Writer()
: internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB20>() {}
+ CodeViewRecordPDB20>() {}
~MinidumpModuleCodeViewRecordPDB20Writer() override;
- //! \brief Sets MinidumpModuleCodeViewRecordPDB20::timestamp and
- //! MinidumpModuleCodeViewRecordPDB20::age.
+ //! \brief Sets CodeViewRecordPDB20::timestamp and CodeViewRecordPDB20::age.
void SetTimestampAndAge(time_t timestamp, uint32_t age);
private:
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCodeViewRecordPDB20Writer);
};
-//! \brief The writer for a MinidumpModuleCodeViewRecordPDB70 object in a
-//! minidump file.
+//! \brief The writer for a CodeViewRecordPDB70 object in a minidump file.
class MinidumpModuleCodeViewRecordPDB70Writer final
: public internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB70> {
+ CodeViewRecordPDB70> {
public:
MinidumpModuleCodeViewRecordPDB70Writer()
: internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
- MinidumpModuleCodeViewRecordPDB70>() {}
+ CodeViewRecordPDB70>() {}
~MinidumpModuleCodeViewRecordPDB70Writer() override;
- //! \brief Initializes the MinidumpModuleCodeViewRecordPDB70 based on \a
- //! module_snapshot.
+ //! \brief Initializes the CodeViewRecordPDB70 based on \a module_snapshot.
//!
//! \param[in] module_snapshot The module snapshot to use as source data.
//!
@@ -130,8 +126,7 @@ class MinidumpModuleCodeViewRecordPDB70Writer final
//! methods after this method.
void InitializeFromSnapshot(const ModuleSnapshot* module_snapshot);
- //! \brief Sets MinidumpModuleCodeViewRecordPDB70::uuid and
- //! MinidumpModuleCodeViewRecordPDB70::age.
+ //! \brief Sets CodeViewRecordPDB70::uuid and CodeViewRecordPDB70::age.
void SetUUIDAndAge(const UUID& uuid, uint32_t age) {
codeview_record()->uuid = uuid;
codeview_record()->age = age;
diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc
index ab2ff20d..0605474f 100644
--- a/minidump/minidump_module_writer_test.cc
+++ b/minidump/minidump_module_writer_test.cc
@@ -100,10 +100,9 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
std::string observed_pdb_name;
if (expected_pdb_uuid) {
// The CodeView record should be a PDB 7.0 link.
- const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record =
- MinidumpWritableAtLocationDescriptor<
- MinidumpModuleCodeViewRecordPDB70>(file_contents,
- *codeview_record);
+ const CodeViewRecordPDB70* codeview_pdb70_record =
+ MinidumpWritableAtLocationDescriptor(
+ file_contents, *codeview_record);
ASSERT_TRUE(codeview_pdb70_record);
EXPECT_EQ(0,
memcmp(expected_pdb_uuid,
@@ -113,14 +112,12 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
observed_pdb_name.assign(
reinterpret_cast(&codeview_pdb70_record->pdb_name[0]),
- codeview_record->DataSize -
- offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name));
+ codeview_record->DataSize - offsetof(CodeViewRecordPDB70, pdb_name));
} else {
// The CodeView record should be a PDB 2.0 link.
- const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record =
- MinidumpWritableAtLocationDescriptor<
- MinidumpModuleCodeViewRecordPDB20>(file_contents,
- *codeview_record);
+ const CodeViewRecordPDB20* codeview_pdb20_record =
+ MinidumpWritableAtLocationDescriptor(
+ file_contents, *codeview_record);
ASSERT_TRUE(codeview_pdb20_record);
EXPECT_EQ(static_cast(expected_pdb_timestamp),
codeview_pdb20_record->timestamp);
@@ -128,8 +125,7 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
observed_pdb_name.assign(
reinterpret_cast(&codeview_pdb20_record->pdb_name[0]),
- codeview_record->DataSize -
- offsetof(MinidumpModuleCodeViewRecordPDB20, pdb_name));
+ codeview_record->DataSize - offsetof(CodeViewRecordPDB20, pdb_name));
}
// Check for, and then remove, the NUL terminator.
diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc
index f1ab4abd..71e8b913 100644
--- a/minidump/test/minidump_writable_test_util.cc
+++ b/minidump/test/minidump_writable_test_util.cc
@@ -291,21 +291,19 @@ const T* MinidumpCVPDBAtLocationDescriptor(
} // namespace
template <>
-const MinidumpModuleCodeViewRecordPDB20*
-MinidumpWritableAtLocationDescriptor(
- const std::string& file_contents,
- const MINIDUMP_LOCATION_DESCRIPTOR& location) {
- return MinidumpCVPDBAtLocationDescriptor(
- file_contents, location);
+const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor<
+ CodeViewRecordPDB20>(const std::string& file_contents,
+ const MINIDUMP_LOCATION_DESCRIPTOR& location) {
+ return MinidumpCVPDBAtLocationDescriptor(file_contents,
+ location);
}
template <>
-const MinidumpModuleCodeViewRecordPDB70*
-MinidumpWritableAtLocationDescriptor(
- const std::string& file_contents,
- const MINIDUMP_LOCATION_DESCRIPTOR& location) {
- return MinidumpCVPDBAtLocationDescriptor(
- file_contents, location);
+const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor<
+ CodeViewRecordPDB70>(const std::string& file_contents,
+ const MINIDUMP_LOCATION_DESCRIPTOR& location) {
+ return MinidumpCVPDBAtLocationDescriptor(file_contents,
+ location);
}
TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value)
diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h
index ac7ac038..ce489686 100644
--- a/minidump/test/minidump_writable_test_util.h
+++ b/minidump/test/minidump_writable_test_util.h
@@ -98,8 +98,8 @@ MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpSimpleStringDictionary);
// data).
MINIDUMP_ALLOW_OVERSIZED_DATA(IMAGE_DEBUG_MISC);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_STRING);
-MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpModuleCodeViewRecordPDB20);
-MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpModuleCodeViewRecordPDB70);
+MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB20);
+MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB70);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpUTF8String);
// minidump_file_writer_test accesses its variable-sized test streams via a
@@ -142,10 +142,10 @@ const T* TMinidumpWritableAtLocationDescriptor(
//! specializations ensure that the size given by \a location matches the
//! size expected of a stream containing the number of elements it claims to
//! have.
-//! - With an IMAGE_DEBUG_MISC, MinidumpModuleCodeViewRecordPDB20, or
-//! MinidumpModuleCodeViewRecordPDB70 template parameter, template
-//! specializations ensure that the structure has the expected format
-//! including any magic number and the `NUL`-terminated string.
+//! - With an IMAGE_DEBUG_MISC, CodeViewRecordPDB20, or CodeViewRecordPDB70
+//! template parameter, template specializations ensure that the structure
+//! has the expected format including any magic number and the `NUL`-
+//! terminated string.
//!
//! \param[in] file_contents The contents of the minidump file.
//! \param[in] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within
@@ -190,16 +190,14 @@ const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor<
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
-const MinidumpModuleCodeViewRecordPDB20*
-MinidumpWritableAtLocationDescriptor(
- const std::string& file_contents,
- const MINIDUMP_LOCATION_DESCRIPTOR& location);
+const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor<
+ CodeViewRecordPDB20>(const std::string& file_contents,
+ const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
-const MinidumpModuleCodeViewRecordPDB70*
-MinidumpWritableAtLocationDescriptor(
- const std::string& file_contents,
- const MINIDUMP_LOCATION_DESCRIPTOR& location);
+const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor<
+ CodeViewRecordPDB70>(const std::string& file_contents,
+ const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MinidumpModuleCrashpadInfoList*
diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp
index a49ee96e..b71b80d6 100644
--- a/snapshot/snapshot_test.gyp
+++ b/snapshot/snapshot_test.gyp
@@ -78,6 +78,7 @@
'win/cpu_context_win_test.cc',
'win/exception_snapshot_win_test.cc',
'win/pe_image_annotations_reader_test.cc',
+ 'win/pe_image_reader_test.cc',
'win/process_reader_win_test.cc',
'win/system_snapshot_win_test.cc',
],
diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc
index 1819a45b..d375b514 100644
--- a/snapshot/win/module_snapshot_win.cc
+++ b/snapshot/win/module_snapshot_win.cc
@@ -148,7 +148,11 @@ ModuleSnapshot::ModuleType ModuleSnapshotWin::GetModuleType() const {
void ModuleSnapshotWin::UUID(crashpad::UUID* uuid) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- CHECK(false) << "TODO(scottmg)";
+ // TODO(scottmg): Also pass the age and pdbname through to snapshot?
+ DWORD age;
+ std::string pdbname;
+ if (!pe_image_reader_->DebugDirectoryInformation(uuid, &age, &pdbname))
+ *uuid = crashpad::UUID();
}
std::vector ModuleSnapshotWin::AnnotationsVector() const {
diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc
index 01755612..61219bfa 100644
--- a/snapshot/win/pe_image_reader.cc
+++ b/snapshot/win/pe_image_reader.cc
@@ -17,9 +17,11 @@
#include
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "client/crashpad_info.h"
#include "snapshot/win/process_reader_win.h"
+#include "util/misc/pdb_structures.h"
namespace crashpad {
@@ -110,13 +112,70 @@ bool PEImageReader::GetCrashpadInfo(
return true;
}
-bool PEImageReader::GetSectionByName(const std::string& name,
- IMAGE_SECTION_HEADER* section) const {
- if (name.size() > sizeof(section->Name)) {
- LOG(WARNING) << "supplied section name too long " << name;
+bool PEImageReader::DebugDirectoryInformation(UUID* uuid,
+ DWORD* age,
+ std::string* pdbname) {
+ WinVMAddress nt_headers_address;
+ IMAGE_NT_HEADERS nt_headers;
+ if (!ReadNtHeaders(&nt_headers_address, &nt_headers))
return false;
+
+ const IMAGE_DATA_DIRECTORY& data_directory =
+ nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
+ if (data_directory.VirtualAddress == 0 || data_directory.Size == 0)
+ return false;
+ IMAGE_DEBUG_DIRECTORY debug_directory;
+ if (data_directory.Size % sizeof(debug_directory) != 0)
+ return false;
+ for (size_t offset = 0; offset < data_directory.Size;
+ offset += sizeof(debug_directory)) {
+ if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset,
+ sizeof(debug_directory),
+ &debug_directory)) {
+ LOG(WARNING) << "could not read data directory";
+ return false;
+ }
+
+ if (debug_directory.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
+ continue;
+
+ if (debug_directory.SizeOfData < sizeof(CodeViewRecordPDB70)) {
+ LOG(WARNING) << "CodeView debug entry of unexpected size";
+ continue;
+ }
+ scoped_ptr data(new char[debug_directory.SizeOfData]);
+ if (!CheckedReadMemory(Address() + debug_directory.AddressOfRawData,
+ debug_directory.SizeOfData,
+ data.get())) {
+ LOG(WARNING) << "could not read debug directory";
+ return false;
+ }
+
+ if (*reinterpret_cast(data.get()) !=
+ CodeViewRecordPDB70::kSignature) {
+ // TODO(scottmg): Consider supporting other record types, see
+ // https://code.google.com/p/crashpad/issues/detail?id=47.
+ LOG(WARNING) << "encountered non-7.0 CodeView debug record";
+ continue;
+ }
+
+ CodeViewRecordPDB70* codeview =
+ reinterpret_cast(data.get());
+ *uuid = codeview->uuid;
+ *age = codeview->age;
+ // This is a NUL-terminated string encoded in the codepage of the system
+ // where the binary was linked. We have no idea what that was, so we just
+ // assume ASCII.
+ *pdbname = std::string(reinterpret_cast(&codeview->pdb_name[0]));
+ return true;
}
+ return false;
+}
+
+// TODO(scottmg): This needs to be made cross-bitness supporting.
+bool PEImageReader::ReadNtHeaders(WinVMAddress* nt_headers_address,
+ IMAGE_NT_HEADERS* nt_headers) const {
IMAGE_DOS_HEADER dos_header;
if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) {
LOG(WARNING) << "could not read dos header of " << module_name_;
@@ -128,20 +187,33 @@ bool PEImageReader::GetSectionByName(const std::string& name,
return false;
}
- // TODO(scottmg): This is reading a same-bitness sized structure.
- IMAGE_NT_HEADERS nt_headers;
- WinVMAddress nt_headers_address = Address() + dos_header.e_lfanew;
+ *nt_headers_address = Address() + dos_header.e_lfanew;
if (!CheckedReadMemory(
- nt_headers_address, sizeof(IMAGE_NT_HEADERS), &nt_headers)) {
+ *nt_headers_address, sizeof(IMAGE_NT_HEADERS), nt_headers)) {
LOG(WARNING) << "could not read nt headers of " << module_name_;
return false;
}
- if (nt_headers.Signature != IMAGE_NT_SIGNATURE) {
+ if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {
LOG(WARNING) << "invalid signature in nt headers of " << module_name_;
return false;
}
+ return true;
+}
+
+bool PEImageReader::GetSectionByName(const std::string& name,
+ IMAGE_SECTION_HEADER* section) const {
+ if (name.size() > sizeof(section->Name)) {
+ LOG(WARNING) << "supplied section name too long " << name;
+ return false;
+ }
+
+ WinVMAddress nt_headers_address;
+ IMAGE_NT_HEADERS nt_headers;
+ if (!ReadNtHeaders(&nt_headers_address, &nt_headers))
+ return false;
+
WinVMAddress first_section_address =
nt_headers_address + offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
nt_headers.FileHeader.SizeOfOptionalHeader;
diff --git a/snapshot/win/pe_image_reader.h b/snapshot/win/pe_image_reader.h
index 71b4863e..2273a8e6 100644
--- a/snapshot/win/pe_image_reader.h
+++ b/snapshot/win/pe_image_reader.h
@@ -21,6 +21,7 @@
#include "base/basictypes.h"
#include "util/misc/initialization_state_dcheck.h"
+#include "util/misc/uuid.h"
#include "util/win/address_types.h"
#include "util/win/checked_win_address_range.h"
@@ -93,7 +94,21 @@ class PEImageReader {
//! messages. Other failures will result in messages being logged.
bool GetCrashpadInfo(process_types::CrashpadInfo* crashpad_info) const;
+ //! \brief Obtains information from the module's debug directory, if any.
+ //!
+ //! \param[out] uuid The unique identifier of the executable/PDB.
+ //! \param[out] age The age field for the pdb (the number of times it's been
+ //! relinked).
+ //! \param[out] pdbname Name of the pdb file.
+ //! \return `true` on success, or `false` if the module has no debug directory
+ //! entry.
+ bool DebugDirectoryInformation(UUID* uuid, DWORD* age, std::string* pdbname);
+
private:
+ //! \brief Reads the `IMAGE_NT_HEADERS` from the beginning of the image.
+ bool ReadNtHeaders(WinVMAddress* nt_header_address,
+ IMAGE_NT_HEADERS* nt_headers) const;
+
//! \brief Finds a given section by name in the image.
bool GetSectionByName(const std::string& name,
IMAGE_SECTION_HEADER* section) const;
diff --git a/snapshot/win/pe_image_reader_test.cc b/snapshot/win/pe_image_reader_test.cc
new file mode 100644
index 00000000..4376f2b8
--- /dev/null
+++ b/snapshot/win/pe_image_reader_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// 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.
+
+#include "snapshot/win/pe_image_reader.h"
+
+#include
+
+#include "gtest/gtest.h"
+#include "snapshot/win/process_reader_win.h"
+
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+namespace crashpad {
+namespace test {
+namespace {
+
+TEST(PEImageReader, DebugDirectory) {
+ PEImageReader pe_image_reader;
+ ProcessReaderWin process_reader;
+ ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess()));
+ HMODULE self = reinterpret_cast(&__ImageBase);
+ MODULEINFO module_info;
+ ASSERT_TRUE(GetModuleInformation(
+ GetCurrentProcess(), self, &module_info, sizeof(module_info)));
+ EXPECT_EQ(self, module_info.lpBaseOfDll);
+ EXPECT_TRUE(pe_image_reader.Initialize(&process_reader,
+ reinterpret_cast(self),
+ module_info.SizeOfImage,
+ "self"));
+ UUID uuid;
+ DWORD age;
+ std::string pdbname;
+ EXPECT_TRUE(pe_image_reader.DebugDirectoryInformation(&uuid, &age, &pdbname));
+ EXPECT_NE(-1, pdbname.find("crashpad_snapshot_test"));
+ const std::string suffix(".pdb");
+ EXPECT_EQ(
+ 0,
+ pdbname.compare(pdbname.size() - suffix.size(), suffix.size(), suffix));
+}
+
+} // namespace
+} // namespace test
+} // namespace crashpad
diff --git a/util/misc/pdb_structures.cc b/util/misc/pdb_structures.cc
new file mode 100644
index 00000000..c62f11c0
--- /dev/null
+++ b/util/misc/pdb_structures.cc
@@ -0,0 +1,22 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// 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.
+
+#include "util/misc/pdb_structures.h"
+
+namespace crashpad {
+
+const uint32_t CodeViewRecordPDB20::kSignature;
+const uint32_t CodeViewRecordPDB70::kSignature;
+
+} // namespace crashpad
diff --git a/util/misc/pdb_structures.h b/util/misc/pdb_structures.h
new file mode 100644
index 00000000..04d76eec
--- /dev/null
+++ b/util/misc/pdb_structures.h
@@ -0,0 +1,131 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// 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_UTIL_MISC_PDB_STRUCTURES_H_
+#define CRASHPAD_UTIL_MISC_PDB_STRUCTURES_H_
+
+#include "util/misc/uuid.h"
+
+namespace crashpad {
+
+//! \brief A CodeView record linking to a `.pdb` 2.0 file.
+//!
+//! This format provides an indirect link to debugging data by referencing an
+//! external `.pdb` file by its name, timestamp, and age. This structure may be
+//! pointed to by MINIDUMP_MODULE::CvRecord. It has been superseded by
+//! CodeViewRecordPDB70.
+//!
+//! For more information about this structure and format, see Matching
+//! Debug Information, PDB Files, and Undocumented
+//! Windows 2000 Secrets, Windows 2000 Debugging Support/Microsoft Symbol
+//! File Internals/CodeView Subsections.
+//!
+//! \sa IMAGE_DEBUG_MISC
+struct CodeViewRecordPDB20 {
+ //! \brief The magic number identifying this structure version, stored in
+ //! #signature.
+ //!
+ //! In a hex dump, this will appear as “NB10” when produced by a little-endian
+ //! machine.
+ static const uint32_t kSignature = '01BN';
+
+ //! \brief The magic number identifying this structure version, the value of
+ //! #kSignature.
+ uint32_t signature;
+
+ //! \brief The offset to CodeView data.
+ //!
+ //! In this structure, this field always has the value `0` because no CodeView
+ //! data is present, there is only a link to CodeView data stored in an
+ //! external file.
+ uint32_t offset;
+
+ //! \brief The time that the `.pdb` file was created, in `time_t` format, the
+ //! number of seconds since the POSIX epoch.
+ uint32_t timestamp;
+
+ //! \brief The revision of the `.pdb` file.
+ //!
+ //! A `.pdb` file’s age indicates incremental changes to it. When a `.pdb`
+ //! file is created, it has age `1`, and subsequent updates increase this
+ //! value.
+ uint32_t age;
+
+ //! \brief The path or file name of the `.pdb` file associated with the
+ //! module.
+ //!
+ //! This is a NUL-terminated string. On Windows, it will be encoded in the
+ //! code page of the system that linked the module. On other operating
+ //! systems, UTF-8 may be used.
+ uint8_t pdb_name[1];
+};
+
+//! \brief A CodeView record linking to a `.pdb` 7.0 file.
+//!
+//! This format provides an indirect link to debugging data by referencing an
+//! external `.pdb` file by its name, %UUID, and age. This structure may be
+//! pointed to by MINIDUMP_MODULE::CvRecord.
+//!
+//! For more information about this structure and format, see Matching
+//! Debug Information, PDB Files.
+//!
+//! \sa CodeViewRecordPDB20
+//! \sa IMAGE_DEBUG_MISC
+struct CodeViewRecordPDB70 {
+ // UUID has a constructor, which makes it non-POD, which makes this structure
+ // non-POD. In order for the default constructor to zero-initialize other
+ // members, an explicit constructor must be provided.
+ CodeViewRecordPDB70()
+ : signature(),
+ uuid(),
+ age(),
+ pdb_name() {
+ }
+
+ //! \brief The magic number identifying this structure version, stored in
+ //! #signature.
+ //!
+ //! In a hex dump, this will appear as “RSDS” when produced by a little-endian
+ //! machine.
+ static const uint32_t kSignature = 'SDSR';
+
+ //! \brief The magic number identifying this structure version, the value of
+ //! #kSignature.
+ uint32_t signature;
+
+ //! \brief The `.pdb` file’s unique identifier.
+ UUID uuid;
+
+ //! \brief The revision of the `.pdb` file.
+ //!
+ //! A `.pdb` file’s age indicates incremental changes to it. When a `.pdb`
+ //! file is created, it has age `1`, and subsequent updates increase this
+ //! value.
+ uint32_t age;
+
+ //! \brief The path or file name of the `.pdb` file associated with the
+ //! module.
+ //!
+ //! This is a NUL-terminated string. On Windows, it will be encoded in the
+ //! code page of the system that linked the module. On other operating
+ //! systems, UTF-8 may be used.
+ uint8_t pdb_name[1];
+};
+
+} // namespace crashpad
+
+#endif // CRASHPAD_UTIL_MISC_PDB_STRUCTURES_H_
diff --git a/util/util.gyp b/util/util.gyp
index df377592..69dab9fa 100644
--- a/util/util.gyp
+++ b/util/util.gyp
@@ -91,6 +91,8 @@
'misc/initialization_state.h',
'misc/initialization_state_dcheck.cc',
'misc/initialization_state_dcheck.h',
+ 'misc/pdb_structures.cc',
+ 'misc/pdb_structures.h',
'misc/scoped_forbid_return.cc',
'misc/scoped_forbid_return.h',
'misc/symbolic_constants_common.h',