Support PE modules in core files when running core2md

Core files generated from `wine` contain both ELF and PE modules. Module
format can be guessed by checking the file contents. If the module
corresponds to PE-file conditions (has specific fields set up as
described in https://code.google.com/archive/p/corkami/wikis/PE.wiki)
we'll create a MDCVInfoPDB70 record in the minidump for it, but if
the file cannot be opened, is too short or is not a PE file, we'll
fall back to ELF procedure.

Added /src/client/linux/minidump_writer/pe_file.{cc,h} to
src_client_linux_libbreakpad_client_a_SOURCES and
src_client_linux_linux_client_unittest_shlib_SOURCES.
Makefile.in and aclocal.m4 were generated by running 'aclocal && automake'.

Test: build core2md and use it to convert a core file into dmp, validate
that the generated dmp file can be opened. Ran './configure & make'.

Change-Id: I225ffeea3f582deed40ecdfe7ab77f5754e90cbe
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3629189
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Iryna Shakhova 2022-05-12 09:32:52 +00:00 committed by Joshua Peraza
parent c85eb4a59b
commit 0808030bee
7 changed files with 622 additions and 65 deletions

View file

@ -71,6 +71,8 @@
#include "client/linux/minidump_writer/line_reader.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "client/linux/minidump_writer/pe_file.h"
#include "client/linux/minidump_writer/pe_structs.h"
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
#include "client/minidump_file_writer.h"
#include "common/linux/file_id.h"
@ -95,8 +97,11 @@ using google_breakpad::MappingInfo;
using google_breakpad::MappingList;
using google_breakpad::MinidumpFileWriter;
using google_breakpad::PageAllocator;
using google_breakpad::PEFile;
using google_breakpad::PEFileFormat;
using google_breakpad::ProcCpuInfoReader;
using google_breakpad::RawContextCPU;
using google_breakpad::RSDS_DEBUG_FORMAT;
using google_breakpad::ThreadInfo;
using google_breakpad::TypedMDRVA;
using google_breakpad::UContextReader;
@ -632,40 +637,88 @@ class MinidumpWriter {
mod->base_of_image = mapping.start_addr;
mod->size_of_image = mapping.size;
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
dumper_->allocator());
char file_name[NAME_MAX];
char file_path[NAME_MAX];
if (identifier) {
// GUID was provided by caller.
identifier_bytes.insert(identifier_bytes.end(),
identifier,
identifier + sizeof(MDGUID));
dumper_->GetMappingEffectiveNameAndPath(mapping, file_path,
sizeof(file_path), file_name,
sizeof(file_name));
RSDS_DEBUG_FORMAT rsds;
PEFileFormat file_format = PEFile::TryGetDebugInfo(file_path, &rsds);
if (file_format == PEFileFormat::notPeCoff) {
// The module is not a PE/COFF file, process as an ELF.
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
dumper_->allocator());
if (identifier) {
// GUID was provided by caller.
identifier_bytes.insert(identifier_bytes.end(), identifier,
identifier + sizeof(MDGUID));
} else {
// Note: ElfFileIdentifierForMapping() can manipulate the
// |mapping.name|, that is why we need to call the method
// GetMappingEffectiveNameAndPath again.
dumper_->ElfFileIdentifierForMapping(mapping, member, mapping_id,
identifier_bytes);
dumper_->GetMappingEffectiveNameAndPath(mapping, file_path,
sizeof(file_path), file_name,
sizeof(file_name));
}
if (!identifier_bytes.empty()) {
UntypedMDRVA cv(&minidump_writer_);
if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
return false;
const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
cv.Copy(&cv_signature, sizeof(cv_signature));
cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
identifier_bytes.size());
mod->cv_record = cv.location();
}
} else {
// Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
dumper_->ElfFileIdentifierForMapping(mapping,
member,
mapping_id,
identifier_bytes);
}
if (!identifier_bytes.empty()) {
UntypedMDRVA cv(&minidump_writer_);
if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
// The module is a PE/COFF file. Create MDCVInfoPDB70 struct for it.
size_t file_name_length = strlen(file_name);
TypedMDRVA<MDCVInfoPDB70> cv(&minidump_writer_);
if (!cv.AllocateObjectAndArray(file_name_length + 1, sizeof(uint8_t)))
return false;
const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
cv.Copy(&cv_signature, sizeof(cv_signature));
cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
identifier_bytes.size());
if (!cv.CopyIndexAfterObject(0, file_name, file_name_length))
return false;
MDCVInfoPDB70* cv_ptr = cv.get();
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
if (file_format == PEFileFormat::peWithBuildId) {
// Populate BuildId and age using RSDS instance.
cv_ptr->signature.data1 = static_cast<uint32_t>(rsds.guid[0]) << 24 |
static_cast<uint32_t>(rsds.guid[1]) << 16 |
static_cast<uint32_t>(rsds.guid[2]) << 8 |
static_cast<uint32_t>(rsds.guid[3]);
cv_ptr->signature.data2 =
static_cast<uint16_t>(rsds.guid[4]) << 8 | rsds.guid[5];
cv_ptr->signature.data3 =
static_cast<uint16_t>(rsds.guid[6]) << 8 | rsds.guid[7];
cv_ptr->signature.data4[0] = rsds.guid[8];
cv_ptr->signature.data4[1] = rsds.guid[9];
cv_ptr->signature.data4[2] = rsds.guid[10];
cv_ptr->signature.data4[3] = rsds.guid[11];
cv_ptr->signature.data4[4] = rsds.guid[12];
cv_ptr->signature.data4[5] = rsds.guid[13];
cv_ptr->signature.data4[6] = rsds.guid[14];
cv_ptr->signature.data4[7] = rsds.guid[15];
// The Age field should be reverted as well.
cv_ptr->age = static_cast<uint32_t>(rsds.age[0]) << 24 |
static_cast<uint32_t>(rsds.age[1]) << 16 |
static_cast<uint32_t>(rsds.age[2]) << 8 |
static_cast<uint32_t>(rsds.age[3]);
} else {
cv_ptr->age = 0;
}
mod->cv_record = cv.location();
}
char file_name[NAME_MAX];
char file_path[NAME_MAX];
dumper_->GetMappingEffectiveNameAndPath(
mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
MDLocationDescriptor ld;
if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
return false;

View file

@ -0,0 +1,148 @@
// Copyright (c) 2022, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string.h>
#include "client/linux/minidump_writer/pe_file.h"
#include "client/linux/minidump_writer/pe_structs.h"
#include "common/linux/memory_mapped_file.h"
namespace google_breakpad {
PEFileFormat PEFile::TryGetDebugInfo(const char* filename,
PRSDS_DEBUG_FORMAT debug_info) {
MemoryMappedFile mapped_file(filename, 0);
if (!mapped_file.data())
return PEFileFormat::notPeCoff;
const void* base = mapped_file.data();
const size_t file_size = mapped_file.size();
const IMAGE_DOS_HEADER* header =
TryReadStruct<IMAGE_DOS_HEADER>(base, 0, file_size);
if (!header || (header->e_magic != IMAGE_DOS_SIGNATURE)) {
return PEFileFormat::notPeCoff;
}
// NTHeader is at position 'e_lfanew'.
DWORD nt_header_offset = header->e_lfanew;
// First, read a common IMAGE_NT_HEADERS structure. It should contain a
// special flag marking whether PE module is x64 (OptionalHeader.Magic)
// and so-called NT_SIGNATURE in Signature field.
const IMAGE_NT_HEADERS* nt_header =
TryReadStruct<IMAGE_NT_HEADERS>(base, nt_header_offset, file_size);
if (!nt_header || (nt_header->Signature != IMAGE_NT_SIGNATURE)
|| ((nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
&& (nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)))
return PEFileFormat::notPeCoff;
bool x64 = nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
WORD sections_number = nt_header->FileHeader.NumberOfSections;
DWORD debug_offset;
DWORD debug_size;
DWORD section_offset;
if (x64) {
const IMAGE_NT_HEADERS64* header_64 =
TryReadStruct<IMAGE_NT_HEADERS64>(base, nt_header_offset, file_size);
if (!header_64)
return PEFileFormat::peWithoutBuildId;
debug_offset =
header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
.VirtualAddress;
debug_size =
header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
.Size;
section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS64);
} else {
const IMAGE_NT_HEADERS32* header_32 =
TryReadStruct<IMAGE_NT_HEADERS32>(base, nt_header_offset, file_size);
if (!header_32)
return PEFileFormat::peWithoutBuildId;
debug_offset =
header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
.VirtualAddress;
debug_size =
header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
.Size;
section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS32);
}
DWORD debug_end_pos = debug_offset + debug_size;
while (debug_offset < debug_end_pos) {
for (WORD i = 0; i < sections_number; ++i) {
// Section headers are placed sequentially after the NT_HEADER (32/64).
const IMAGE_SECTION_HEADER* section =
TryReadStruct<IMAGE_SECTION_HEADER>(base, section_offset, file_size);
if (!section)
return PEFileFormat::peWithoutBuildId;
section_offset += sizeof(IMAGE_SECTION_HEADER);
// Current `debug_offset` should be inside a section, stop if we find
// a suitable one (we don't consider any malformed sections here).
if ((section->VirtualAddress <= debug_offset) &&
(debug_offset < section->VirtualAddress + section->SizeOfRawData)) {
DWORD offset =
section->PointerToRawData + debug_offset - section->VirtualAddress;
// Go to the position of current ImageDebugDirectory (offset).
const IMAGE_DEBUG_DIRECTORY* debug_directory =
TryReadStruct<IMAGE_DEBUG_DIRECTORY>(base, offset, file_size);
if (!debug_directory)
return PEFileFormat::peWithoutBuildId;
// Process ImageDebugDirectory with CodeViewRecord type and skip
// all others.
if (debug_directory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
DWORD debug_directory_size = debug_directory->SizeOfData;
if (debug_directory_size < sizeof(RSDS_DEBUG_FORMAT))
// RSDS section is malformed.
return PEFileFormat::peWithoutBuildId;
// Go to the position of current ImageDebugDirectory Raw Data
// (debug_directory->PointerToRawData) and read the RSDS section.
const RSDS_DEBUG_FORMAT* rsds =
TryReadStruct<RSDS_DEBUG_FORMAT>(
base, debug_directory->PointerToRawData, file_size);
if (!rsds)
return PEFileFormat::peWithoutBuildId;
memcpy(debug_info->guid, rsds->guid, sizeof(rsds->guid));
memcpy(debug_info->age, rsds->age, sizeof(rsds->age));
return PEFileFormat::peWithBuildId;
}
break;
}
}
debug_offset += sizeof(IMAGE_DEBUG_DIRECTORY);
}
return PEFileFormat::peWithoutBuildId;
}
} // namespace google_breakpad

View file

@ -0,0 +1,77 @@
// Copyright (c) 2022, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_
#include "client/linux/minidump_writer/pe_structs.h"
namespace google_breakpad {
typedef enum {
notPeCoff = 0,
peWithoutBuildId = 1,
peWithBuildId = 2
} PEFileFormat;
class PEFile {
public:
/**
* Attempts to parse RSDS_DEBUG_FORMAT record from a PE (Portable
* Executable) file. To do this we check whether the loaded file is a PE
* file, and if it is - try to find IMAGE_DEBUG_DIRECTORY structure with
* its type set to IMAGE_DEBUG_TYPE_CODEVIEW.
*
* @param filename Filename for the module to parse.
* @param debug_info RSDS_DEBUG_FORMAT struct to be populated with PE debug
* info (GUID and age).
* @return
* notPeCoff: not PE/COFF file;
* peWithoutBuildId: a PE/COFF file but build-id is not set;
* peWithBuildId: a PE/COFF file and build-id is set.
*/
static PEFileFormat TryGetDebugInfo(const char* filename,
PRSDS_DEBUG_FORMAT debug_info);
private:
template <class TStruct>
static const TStruct* TryReadStruct(const void* base,
const DWORD position,
const size_t file_size) {
if (position + sizeof(TStruct) >= file_size){
return nullptr;
}
const void* ptr = static_cast<const char*>(base) + position;
return reinterpret_cast<const TStruct*>(ptr);
}
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_

View file

@ -0,0 +1,226 @@
// Copyright (c) 2022, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_
#include <cstdint>
namespace google_breakpad {
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t ULONGLONG;
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
DWORD e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_DEBUG_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Type;
DWORD SizeOfData;
DWORD AddressOfRawData;
DWORD PointerToRawData;
} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
//
// Standard fields - Magic.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
//
// NT additional fields.
//
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef struct _IMAGE_NT_HEADERS32 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _RSDS_DEBUG_FORMAT {
DWORD signature;
BYTE guid[16];
BYTE age[4];
char pdbpath[1];
} RSDS_DEBUG_FORMAT, *PRSDS_DEBUG_FORMAT;
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_