pe.cc
Go to the documentation of this file.
1 // Copyright 2021 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/substitute.h"
16 #include "bloaty.h"
17 #include "util.h"
18 
19 using absl::string_view;
20 using std::string;
21 
22 namespace bloaty {
23 namespace pe {
24 constexpr uint16_t dos_magic = 0x5A4D; // MZ
25 
26 // From LIEF/include/LIEF/PE/Structures.hpp.in
28 constexpr size_t kHeader16Size = 20;
29 constexpr size_t kHeader32Size = 56;
30 constexpr size_t kNameSize = 8;
31 constexpr size_t kSymbol16Size = 18;
32 constexpr size_t kSymbol32Size = 20;
33 constexpr size_t kSectionSize = 40;
34 constexpr size_t kRelocationSize = 10;
35 constexpr size_t kBaseRelocationBlockSize = 8;
36 constexpr size_t kImportDirectoryTableEntrySize = 20;
37 constexpr size_t kResourceDirectoryTableSize = 16;
38 constexpr size_t kResourceDirectoryEntriesSize = 8;
39 constexpr size_t kResourceDataEntrySize = 16;
40 
43 
44 static_assert(kSectionSize == sizeof(pe_section),
45  "Compiler options broke LIEF struct layout");
46 static_assert(kRelocationSize == sizeof(pe_relocation),
47  "Compiler options broke LIEF struct layout");
48 static_assert(kBaseRelocationBlockSize == sizeof(pe_base_relocation_block),
49  "Compiler options broke LIEF struct layout");
50 static_assert(kImportDirectoryTableEntrySize == sizeof(pe_import),
51  "Compiler options broke LIEF struct layout");
52 static_assert(kResourceDirectoryTableSize ==
54  "Compiler options broke LIEF struct layout");
55 static_assert(kResourceDirectoryEntriesSize ==
57  "Compiler options broke LIEF struct layout");
58 static_assert(kResourceDataEntrySize == sizeof(pe_resource_data_entry),
59  "Compiler options broke LIEF struct layout");
60 static_assert(kSymbol16Size == sizeof(pe_symbol),
61  "Compiler options broke LIEF struct layout");
62 
63 static_assert(sizeof(PE_TYPE) == sizeof(uint16_t),
64  "Compiler options broke PE_TYPE size");
65 
66 class PeFile {
67  public:
69 
70  bool IsOpen() const { return ok_; }
71 
72  string_view entire_file() const { return data_; }
73  string_view pe_headers() const { return pe_headers_; }
75 
77  string_view section_header(size_t n) const {
78  return StrictSubstr(section_headers_, n * sizeof(pe_section),
79  sizeof(pe_section));
80  }
81 
82  private:
83  bool Initialize();
84 
86  return StrictSubstr(data_, start, n);
87  }
88 
89  bool ok_;
90  bool is_64bit_;
92 
95 
99 };
100 
102  if (data_.size() < sizeof(dos_header_)) {
103  return false;
104  }
105 
106  memcpy(&dos_header_, data_.data(), sizeof(dos_header_));
107 
108  if (dos_header_.Magic != dos_magic) {
109  // Not a PE file.
110  return false;
111  }
112 
113  PE_TYPE Magic;
114  auto pe_end =
116  if (CheckedAdd(pe_end, sizeof(Magic)) > data_.size()) {
117  // Cannot fit the headers / magic from optional header
118  return false;
119  }
120 
122  sizeof(pe_header_));
123 
124  if (!std::equal(pe_header_.signature, pe_header_.signature + sizeof(PE_Magic),
125  std::begin(PE_Magic))) {
126  // Not a PE file.
127  return false;
128  }
129 
130  memcpy(&Magic, data_.data() + pe_end, sizeof(Magic));
131 
133  // Unknown PE magic
134  return false;
135  }
136 
138 
140 
141  // TODO(mj): Figure out if we should trust SizeOfOptionalHeader here
142  const uint32_t sections_offset = dos_header_.AddressOfNewExeHeader +
143  sizeof(pe_header_) +
145 
146  auto sections_size = CheckedMul(section_count_, sizeof(pe_section));
147  if ((sections_offset + sections_size) > data_.size()) {
148  // Cannot fit the headers
149  return false;
150  }
151 
152  pe_headers_ = GetRegion(0, sections_offset);
153  section_headers_ = GetRegion(sections_offset, sections_size);
154 
155  return true;
156 }
157 
158 class Section {
159  public:
160  string name;
161 
164 
167 
169  assert(header_data.size() == sizeof(header_));
170  memcpy(&header_, header_data.data(), sizeof(header_));
171 
172  // TODO(mj): Handle long section names:
173  // For longer names, this member contains a forward slash (/) followed by an
174  // ASCII representation of a decimal number that is an offset into the
175  // string table.
177  }
178 
179  private:
181 };
182 
183 template <class Func>
184 void ForEachSection(const PeFile& pe, Func&& section_func) {
185  for (auto n = 0; n < pe.section_count(); ++n) {
187  section_func(section);
188  }
189 }
190 
191 void ParseSections(const PeFile& pe, RangeSink* sink) {
192  assert(pe.IsOpen());
193  ForEachSection(pe, [sink, &pe](const Section& section) {
194  uint64_t vmaddr = section.virtual_addr();
195  uint64_t vmsize = section.virtual_size();
196  absl::string_view section_data = StrictSubstr(
197  pe.entire_file(), section.raw_offset(), section.raw_size());
198 
199  sink->AddRange("pe_sections", section.name, vmaddr, vmsize, section_data);
200  });
201 }
202 
203 void AddCatchAll(const PeFile& pe, RangeSink* sink) {
204  assert(pe.IsOpen());
205 
206  auto begin = pe.pe_headers().data() - sink->input_file().data().data();
207  sink->AddRange("pe_catchall", "[PE Headers]", begin, pe.pe_headers().size(),
208  pe.pe_headers());
209 
210  begin = pe.section_headers().data() - sink->input_file().data().data();
211  sink->AddRange("pe_catchall", "[PE Section Headers]", begin,
212  pe.section_headers().size(), pe.section_headers());
213 
214  // The last-line fallback to make sure we cover the entire file.
215  sink->AddFileRange("pe_catchall", "[Unmapped]", sink->input_file().data());
216 }
217 
218 class PEObjectFile : public ObjectFile {
219  public:
220  PEObjectFile(std::unique_ptr<InputFile> file_data,
221  std::unique_ptr<pe::PeFile> pe)
222  : ObjectFile(std::move(file_data)), pe_file(std::move(pe)) {}
223 
224  std::string GetBuildId() const override {
225  // TODO(mj): Read from pe_pdb_??
226  return std::string();
227  }
228 
229  void ProcessFile(const std::vector<RangeSink*>& sinks) const override {
230  for (auto sink : sinks) {
231  switch (sink->data_source()) {
233  // TODO(mj): sections: list out imports and other stuff!
236  break;
241  // TODO(mj): Generate symbols from debug info, exports, imports, tls
242  // data, relocations, resources ...
246  default:
247  THROW("PE doesn't support this data source");
248  }
250  }
251  }
252 
253  bool GetDisassemblyInfo(string_view /*symbol*/, DataSource /*symbol_source*/,
254  DisassemblyInfo* /*info*/) const override {
255  WARN("PE files do not support disassembly yet");
256  return false;
257  }
258 
259  protected:
260  std::unique_ptr<pe::PeFile> pe_file;
261 };
262 
263 bool ReadMagic(const string_view& data) {
264  // If the size is smaller than a dos header, it cannot be a PE file, right?
265  if (data.size() < sizeof(pe_dos_header)) {
266  return false;
267  }
268 
269  uint16_t magic;
270  memcpy(&magic, data.data(), sizeof(magic));
271 
272  return magic == dos_magic;
273 }
274 } // namespace pe
275 
276 std::unique_ptr<ObjectFile> TryOpenPEFile(std::unique_ptr<InputFile>& file) {
277  // Do not bother creating an object if the first magic is not even there
278  if (pe::ReadMagic(file->data())) {
279  std::unique_ptr<pe::PeFile> pe(new pe::PeFile(file->data()));
280 
281  if (pe->IsOpen()) {
282  return std::unique_ptr<ObjectFile>(
284  }
285  }
286 
287  return nullptr;
288 }
289 
290 } // namespace bloaty
bloaty::pe::PeFile::Initialize
bool Initialize()
Definition: pe.cc:101
bloaty::pe::Section
Definition: pe.cc:158
bloaty::pe::PeFile::section_headers
string_view section_headers() const
Definition: pe.cc:74
bloaty::pe::PeFile::pe_headers_
string_view pe_headers_
Definition: pe.cc:96
bloaty::pe::Section::raw_size
uint32_t raw_size() const
Definition: pe.cc:163
pe_resource_data_entry
Definition: pe_structures.h:328
bloaty
Definition: bloaty.cc:69
PE_TYPE::PE32
@ PE32
32bits
pe_dos_header::Magic
uint16_t Magic
Definition: pe_structures.h:182
bloaty::pe::PeFile::section_count
uint32_t section_count() const
Definition: pe.cc:76
section
OPENSSL_EXPORT const char * section
Definition: conf.h:114
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
pe_section::VirtualSize
uint32_t VirtualSize
Definition: pe_structures.h:80
magic
uintptr_t magic
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:83
uint16_t
unsigned short uint16_t
Definition: stdint-msvc2008.h:79
bloaty::ObjectFile
Definition: bloaty.h:257
PE_TYPE::PE32_PLUS
@ PE32_PLUS
64 bits
absl::base_internal::Magic
static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:322
bloaty::DataSource::kShortSymbols
@ kShortSymbols
bloaty::pe::dos_magic
constexpr uint16_t dos_magic
Definition: pe.cc:24
bloaty::pe::PEObjectFile::ProcessFile
void ProcessFile(const std::vector< RangeSink * > &sinks) const override
Definition: pe.cc:229
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
bloaty.h
bloaty::pe::PEObjectFile::GetDisassemblyInfo
bool GetDisassemblyInfo(string_view, DataSource, DisassemblyInfo *) const override
Definition: pe.cc:253
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
bloaty::DataSource::kArchiveMembers
@ kArchiveMembers
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
pe_dos_header::AddressOfNewExeHeader
uint32_t AddressOfNewExeHeader
Definition: pe_structures.h:200
pe_header::SizeOfOptionalHeader
uint16_t SizeOfOptionalHeader
Definition: pe_structures.h:44
bloaty::pe::kImportDirectoryTableEntrySize
constexpr size_t kImportDirectoryTableEntrySize
Definition: pe.cc:36
bloaty::pe::Section::name
string name
Definition: pe.cc:160
bloaty::pe::Section::raw_offset
uint32_t raw_offset() const
Definition: pe.cc:162
PE_TYPE
PE_TYPE
Definition: pe_enums.h:32
bloaty::DataSource::kSegments
@ kSegments
bloaty::pe::kBaseRelocationBlockSize
constexpr size_t kBaseRelocationBlockSize
Definition: pe.cc:35
pe_relocation
Definition: pe_structures.h:49
bloaty::pe::Section::virtual_addr
uint32_t virtual_addr() const
Definition: pe.cc:165
bloaty::pe::Section::Section
Section(string_view header_data)
Definition: pe.cc:168
pe_section
Definition: pe_structures.h:78
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
bloaty::pe::kSymbol32Size
constexpr size_t kSymbol32Size
Definition: pe.cc:32
pe_structures.h
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
start
static uint64_t start
Definition: benchmark-pound.c:74
bloaty::pe::kResourceDataEntrySize
constexpr size_t kResourceDataEntrySize
Definition: pe.cc:39
bloaty::pe::Section::header_
pe_section header_
Definition: pe.cc:180
bloaty::ObjectFile::file_data
const InputFile & file_data() const
Definition: bloaty.h:274
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
bloaty::pe::ForEachSection
void ForEachSection(const PeFile &pe, Func &&section_func)
Definition: pe.cc:184
absl::string_view::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:277
bloaty::TryOpenPEFile
std::unique_ptr< ObjectFile > TryOpenPEFile(std::unique_ptr< InputFile > &file)
Definition: pe.cc:276
pe_header::signature
char signature[sizeof(PE_Magic)]
Definition: pe_structures.h:38
pe_symbol
Definition: pe_structures.h:61
THROW
#define THROW(msg)
Definition: bloaty/src/util.h:45
bloaty::pe::PeFile::pe_headers
string_view pe_headers() const
Definition: pe.cc:73
absl::random_internal_nanobenchmark::Func
FuncOutput(*)(const void *, FuncInput) Func
Definition: abseil-cpp/absl/random/internal/nanobenchmark.h:68
bloaty::pe::kRelocationSize
constexpr size_t kRelocationSize
Definition: pe.cc:34
PE_Magic
static const char PE_Magic[]
The PE signature bytes that follows the DOS stub header.
Definition: pe_structures.h:22
bloaty::pe::PEObjectFile::GetBuildId
std::string GetBuildId() const override
Definition: pe.cc:224
bloaty::CheckedAdd
void CheckedAdd(int64_t *accum, int64_t val)
Definition: bloaty.cc:124
bloaty::pe::kSectionSize
constexpr size_t kSectionSize
Definition: pe.cc:33
pe_dos_header
The DOS compatible header at the front of all PEs.
Definition: pe_structures.h:181
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
bloaty::CheckedMul
uint64_t CheckedMul(uint64_t a, uint64_t b)
Definition: bloaty/src/util.h:80
bloaty::RangeSink
Definition: bloaty.h:110
bloaty::DataSource::kCompileUnits
@ kCompileUnits
bloaty::pe::PeFile::PeFile
PeFile(string_view data)
Definition: pe.cc:68
bloaty::pe::kNameSize
constexpr size_t kNameSize
Definition: pe.cc:30
bloaty::DataSource::kInlines
@ kInlines
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
bloaty::DataSource
DataSource
Definition: bloaty.h:52
bloaty::pe::PeFile::section_header
string_view section_header(size_t n) const
Definition: pe.cc:77
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
section
Definition: loader.h:337
pe_section::Name
char Name[8]
Definition: pe_structures.h:79
bloaty::pe::ParseSections
void ParseSections(const PeFile &pe, RangeSink *sink)
Definition: pe.cc:191
bloaty::pe::PeFile
Definition: pe.cc:66
bloaty::pe::PeFile::is_64bit_
bool is_64bit_
Definition: pe.cc:90
bloaty::DataSource::kSymbols
@ kSymbols
bloaty::pe::PeFile::dos_header_
pe_dos_header dos_header_
Definition: pe.cc:93
pe_resource_directory_entries
Definition: pe_structures.h:320
bloaty::pe::PeFile::IsOpen
bool IsOpen() const
Definition: pe.cc:70
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
pe_header
Definition: pe_structures.h:37
pe_resource_directory_table
Definition: pe_structures.h:311
bloaty::pe::kHeader32Size
constexpr size_t kHeader32Size
Definition: pe.cc:29
bloaty::pe::PEObjectFile::PEObjectFile
PEObjectFile(std::unique_ptr< InputFile > file_data, std::unique_ptr< pe::PeFile > pe)
Definition: pe.cc:220
bloaty::pe::ReadMagic
bool ReadMagic(const string_view &data)
Definition: pe.cc:263
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
string_view
absl::string_view string_view
Definition: attr.cc:22
pe_section::SizeOfRawData
uint32_t SizeOfRawData
Definition: pe_structures.h:82
bloaty::DisassemblyInfo
Definition: bloaty.h:317
bloaty::pe::PEObjectFile
Definition: pe.cc:218
bloaty::pe::PeFile::entire_file
string_view entire_file() const
Definition: pe.cc:72
pe_header::NumberOfSections
uint16_t NumberOfSections
Definition: pe_structures.h:40
bloaty::pe::AddCatchAll
void AddCatchAll(const PeFile &pe, RangeSink *sink)
Definition: pe.cc:203
pe_section::VirtualAddress
uint32_t VirtualAddress
Definition: pe_structures.h:81
bloaty::DataSource::kFullSymbols
@ kFullSymbols
util.h
bloaty::pe::PEObjectFile::pe_file
std::unique_ptr< pe::PeFile > pe_file
Definition: pe.cc:260
bloaty::pe::PeFile::section_count_
uint32_t section_count_
Definition: pe.cc:98
bloaty::DataSource::kRawSymbols
@ kRawSymbols
strnlen
size_t strnlen(const char *str, size_t maxlen)
Definition: os390-syscalls.c:554
WARN
#define WARN(...)
Definition: bloaty/src/util.h:47
bloaty::pe::PeFile::section_headers_
string_view section_headers_
Definition: pe.cc:97
header_data
std::string header_data
Definition: rls.cc:253
bloaty::pe::PeFile::ok_
bool ok_
Definition: pe.cc:89
bloaty::pe::kHeader16Size
constexpr size_t kHeader16Size
Sizes in bytes of various things in the COFF format.
Definition: pe.cc:28
pe_base_relocation_block
Definition: pe_structures.h:55
bloaty::pe::PeFile::GetRegion
string_view GetRegion(uint64_t start, uint64_t n) const
Definition: pe.cc:85
bloaty::pe::kResourceDirectoryTableSize
constexpr size_t kResourceDirectoryTableSize
Definition: pe.cc:37
absl::string_view::data
constexpr const_pointer data() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:336
bloaty::pe::kSymbol16Size
constexpr size_t kSymbol16Size
Definition: pe.cc:31
pe_section::PointerToRawData
uint32_t PointerToRawData
Definition: pe_structures.h:83
bloaty::StrictSubstr
absl::string_view StrictSubstr(absl::string_view data, size_t off, size_t n)
Definition: bloaty/src/util.h:89
bloaty::pe::PeFile::data_
const string_view data_
Definition: pe.cc:91
bloaty::pe::Section::virtual_size
uint32_t virtual_size() const
Definition: pe.cc:166
pe_enums.h
bloaty::DataSource::kSections
@ kSections
bloaty::pe::kResourceDirectoryEntriesSize
constexpr size_t kResourceDirectoryEntriesSize
Definition: pe.cc:38
bloaty::pe::PeFile::pe_header_
pe_header pe_header_
Definition: pe.cc:94
pe_import
Definition: pe_structures.h:142


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:41