1 : // Copyright 2012 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 "syzygy/pe/pe_file_parser.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/native_library.h"
19 : #include "base/path_service.h"
20 : #include "base/files/file_path.h"
21 : #include "base/memory/scoped_ptr.h"
22 : #include "base/strings/string_util.h"
23 : #include "base/win/pe_image.h"
24 : #include "gmock/gmock.h"
25 : #include "gtest/gtest.h"
26 : #include "syzygy/core/unittest_util.h"
27 : #include "syzygy/pe/unittest_util.h"
28 :
29 : namespace pe {
30 :
31 : using block_graph::BlockGraph;
32 : using core::RelativeAddress;
33 : using testing::ContainerEq;
34 : using testing::Contains;
35 :
36 : namespace {
37 :
38 : // Exposes the protected methods for testing.
39 : class TestPEFileParser: public PEFileParser {
40 : public:
41 E : TestPEFileParser(const PEFile& image_file,
42 : BlockGraph::AddressSpace* address_space,
43 : AddReferenceCallback add_reference)
44 : : PEFileParser(image_file, address_space, add_reference) {
45 E : }
46 :
47 : // Expose as public for testing.
48 : using PEFileParser::ParseArchitectureDir;
49 : using PEFileParser::ParseBoundImportDir;
50 : using PEFileParser::ParseComDescriptorDir;
51 : using PEFileParser::ParseDebugDir;
52 : using PEFileParser::ParseDelayImportDir;
53 : using PEFileParser::ParseExceptionDir;
54 : using PEFileParser::ParseExportDir;
55 : using PEFileParser::ParseGlobalDir;
56 : using PEFileParser::ParseIatDir;
57 : using PEFileParser::ParseImageHeader;
58 : using PEFileParser::ParseImportDir;
59 : using PEFileParser::ParseLoadConfigDir;
60 : using PEFileParser::ParseRelocDir;
61 : using PEFileParser::ParseResourceDir;
62 : using PEFileParser::ParseSecurityDir;
63 : using PEFileParser::ParseTlsDir;
64 : };
65 :
66 : class PEFileParserTest: public testing::PELibUnitTest {
67 : typedef testing::PELibUnitTest Super;
68 :
69 : public:
70 E : PEFileParserTest() : address_space_(&image_), loaded_image_(NULL) {
71 E : }
72 :
73 E : virtual void SetUp() {
74 E : Super::SetUp();
75 :
76 : add_reference_ = base::Bind(&PEFileParserTest::AddReference,
77 E : base::Unretained(this));
78 : on_import_thunk_ = base::Bind(&PEFileParserTest::OnImportThunk,
79 E : base::Unretained(this));
80 :
81 E : ASSERT_TRUE(image_file_.Init(testing::GetExeRelativePath(
82 : testing::kTestDllName)));
83 E : }
84 :
85 E : virtual void TearDown() {
86 E : if (loaded_image_ != NULL)
87 E : base::UnloadNativeLibrary(loaded_image_);
88 E : loaded_image_ = NULL;
89 :
90 E : Super::TearDown();
91 E : }
92 :
93 : bool AddReference(RelativeAddress src,
94 : BlockGraph::ReferenceType type,
95 : BlockGraph::Size size,
96 E : RelativeAddress dst) {
97 E : Reference ref = { type, size, dst };
98 E : bool inserted = references_.insert(std::make_pair(src, ref)).second;
99 E : EXPECT_TRUE(inserted);
100 E : return inserted;
101 E : }
102 :
103 : bool OnImportThunk(const char* module_name,
104 : const char* symbol_name,
105 E : BlockGraph::Block* thunk) {
106 E : EXPECT_TRUE(module_name != NULL);
107 E : EXPECT_TRUE(symbol_name != NULL);
108 E : EXPECT_TRUE(thunk != NULL);
109 E : import_map_[module_name]++;
110 E : EXPECT_TRUE(import_set_.insert(
111 : std::make_pair(std::string(module_name),
112 : std::string(symbol_name))).second);
113 E : return true;
114 E : }
115 :
116 : // Assert that an exported function in the test_dll is referenced
117 : // in the image.
118 E : bool ExportIsReferenced(const char* function_name_or_ordinal) {
119 E : if (loaded_image_ == NULL) {
120 i : base::NativeLibraryLoadError error;
121 : loaded_image_ = base::LoadNativeLibrary(
122 i : testing::GetExeRelativePath(testing::kTestDllName), &error);
123 : }
124 :
125 E : EXPECT_TRUE(loaded_image_ != NULL);
126 E : if (loaded_image_ == NULL)
127 i : return false;
128 :
129 : void* function = base::GetFunctionPointerFromNativeLibrary(
130 E : loaded_image_, function_name_or_ordinal);
131 :
132 : RelativeAddress addr(reinterpret_cast<const char*>(function) -
133 E : reinterpret_cast<const char*>(loaded_image_));
134 :
135 E : ReferenceMap::const_iterator it(references_.begin());
136 E : for (; it != references_.end(); ++it) {
137 E : if (it->second.dst == addr)
138 E : return true;
139 E : }
140 :
141 i : return false;
142 E : }
143 :
144 E : void AssertDataDirectoryEntryValid(BlockGraph::Block* block) {
145 E : ASSERT_TRUE(block != NULL);
146 E : ASSERT_NE(0u, block->size());
147 E : ASSERT_EQ(block->size(), block->data_size());
148 E : ASSERT_TRUE(block->data() != NULL);
149 E : }
150 :
151 : // Locate block pointed to by the reference at @p offset into @p block.
152 : // @returns the block in question, or NULL if no such block.
153 : BlockGraph::Block* FindReferencedBlock(BlockGraph::Block* block,
154 E : BlockGraph::Offset offset) {
155 E : ReferenceMap::const_iterator it(references_.find(block->addr() + offset));
156 E : if (it == references_.end())
157 i : return NULL;
158 :
159 E : return address_space_.GetBlockByAddress(it->second.dst);
160 E : }
161 :
162 : protected:
163 : struct Reference {
164 : BlockGraph::ReferenceType type;
165 : BlockGraph::Size size;
166 : RelativeAddress dst;
167 : };
168 :
169 : typedef std::map<RelativeAddress, Reference> ReferenceMap;
170 : ReferenceMap references_;
171 :
172 : // This is used to count the number of imported symbols per imported module,
173 : // and is populated by the OnImportThunk callback.
174 : typedef std::map<std::string, size_t> ImportMap;
175 : typedef std::set<std::pair<std::string, std::string>> ImportSet;
176 : ImportMap import_map_;
177 : ImportSet import_set_;
178 :
179 : PEFileParser::AddReferenceCallback add_reference_;
180 : PEFileParser::OnImportThunkCallback on_import_thunk_;
181 : PEFile image_file_;
182 : BlockGraph image_;
183 : BlockGraph::AddressSpace address_space_;
184 :
185 : base::NativeLibrary loaded_image_;
186 : };
187 :
188 : } // namespace
189 :
190 E : TEST_F(PEFileParserTest, ParseImageHeader) {
191 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
192 :
193 E : PEFileParser::PEHeader header;
194 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
195 :
196 : // Check that the DOS header was read successfully.
197 E : ASSERT_TRUE(header.dos_header != NULL);
198 E : ASSERT_GE(header.dos_header->size(), sizeof(IMAGE_DOS_HEADER));
199 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.dos_header->type());
200 : // Check the underlying data.
201 E : ASSERT_GE(header.dos_header->data_size(), sizeof(IMAGE_DOS_HEADER));
202 : const IMAGE_DOS_HEADER* dos_header =
203 E : reinterpret_cast<const IMAGE_DOS_HEADER*>(header.dos_header->data());
204 E : ASSERT_TRUE(dos_header != NULL);
205 E : ASSERT_EQ(IMAGE_DOS_SIGNATURE, dos_header->e_magic);
206 :
207 : // Check that the DOS header references the NT headers.
208 : ASSERT_EQ(header.nt_headers,
209 : FindReferencedBlock(header.dos_header,
210 E : offsetof(IMAGE_DOS_HEADER, e_lfanew)));
211 :
212 : // Check the NT headers.
213 E : ASSERT_TRUE(header.nt_headers != NULL);
214 E : ASSERT_GT(header.nt_headers->size(), sizeof(IMAGE_NT_HEADERS));
215 E : ASSERT_EQ(header.nt_headers->data_size(), header.nt_headers->size());
216 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.nt_headers->type());
217 : const IMAGE_NT_HEADERS* nt_headers =
218 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
219 E : ASSERT_TRUE(nt_headers != NULL);
220 E : ASSERT_EQ(IMAGE_NT_OPTIONAL_HDR32_MAGIC, nt_headers->OptionalHeader.Magic);
221 :
222 E : const IMAGE_SECTION_HEADER* section_headers = NULL;
223 : // Check that the data accounts for the image section headers.
224 : ASSERT_EQ(nt_headers->FileHeader.NumberOfSections * sizeof(*section_headers) +
225 E : sizeof(*nt_headers), header.nt_headers->data_size());
226 E : }
227 :
228 E : TEST_F(PEFileParserTest, ParseExportDir) {
229 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
230 :
231 E : PEFileParser::PEHeader header;
232 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
233 :
234 : const IMAGE_NT_HEADERS* nt_headers =
235 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
236 :
237 : const IMAGE_DATA_DIRECTORY& dir =
238 E : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
239 E : EXPECT_TRUE(parser.ParseExportDir(dir) != NULL);
240 :
241 E : base::NativeLibraryLoadError error;
242 : loaded_image_ = base::LoadNativeLibrary(
243 E : testing::GetExeRelativePath(testing::kTestDllName), &error);
244 E : ASSERT_TRUE(loaded_image_ != NULL);
245 :
246 E : ASSERT_TRUE(ExportIsReferenced("function1"));
247 : // function2 is exported by ordinal only.
248 E : ASSERT_TRUE(ExportIsReferenced(reinterpret_cast<const char*>(7)));
249 E : ASSERT_TRUE(ExportIsReferenced("function3"));
250 E : }
251 :
252 E : TEST_F(PEFileParserTest, ParseEmptyExportDir) {
253 : base::FilePath no_exports_dll_path = testing::GetOutputRelativePath(
254 E : testing::kNoExportsDllName);
255 E : pe::PEFile no_exports_dll_image;
256 E : ASSERT_TRUE(no_exports_dll_image.Init(no_exports_dll_path));
257 : TestPEFileParser parser(no_exports_dll_image,
258 E : &address_space_, add_reference_);
259 :
260 E : PEFileParser::PEHeader header;
261 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
262 :
263 : const IMAGE_NT_HEADERS* nt_headers =
264 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
265 :
266 : const IMAGE_DATA_DIRECTORY& dir =
267 E : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
268 E : EXPECT_TRUE(parser.ParseExportDir(dir) != NULL);
269 E : }
270 :
271 E : TEST_F(PEFileParserTest, ParseImportDir) {
272 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
273 E : parser.set_on_import_thunk(on_import_thunk_);
274 :
275 E : PEFileParser::PEHeader header;
276 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
277 :
278 : const IMAGE_NT_HEADERS* nt_headers =
279 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
280 :
281 : const IMAGE_DATA_DIRECTORY& dir =
282 E : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
283 E : BlockGraph::Block* block = parser.ParseImportDir(dir);
284 E : ASSERT_TRUE(block != NULL);
285 :
286 : // Test that we have the two import descriptors we expect, plus the sentinel.
287 E : size_t num_descriptors = block->size() / sizeof(IMAGE_IMPORT_DESCRIPTOR);
288 E : ASSERT_EQ(3, num_descriptors);
289 E : ASSERT_TRUE(block->data() != NULL);
290 E : ASSERT_EQ(block->size(), block->data_size());
291 :
292 E : std::set<std::string> import_names;
293 E : for (size_t i = 0; i < num_descriptors - 1; ++i) {
294 E : size_t element_offset = sizeof(IMAGE_IMPORT_DESCRIPTOR) * i;
295 : BlockGraph::Block* name_block =
296 : FindReferencedBlock(block, element_offset +
297 E : offsetof(IMAGE_IMPORT_DESCRIPTOR, Name));
298 E : ASSERT_TRUE(name_block != NULL);
299 :
300 : const char* name =
301 E : reinterpret_cast<const char*>(name_block->data());
302 E : EXPECT_TRUE(import_names.insert(name).second);
303 :
304 : // Now retrieve the IAT and INT blocks.
305 : BlockGraph::Block* iat_block =
306 : FindReferencedBlock(block, element_offset +
307 E : offsetof(IMAGE_IMPORT_DESCRIPTOR, FirstThunk));
308 : BlockGraph::Block* int_block =
309 : FindReferencedBlock(block, element_offset +
310 E : offsetof(IMAGE_IMPORT_DESCRIPTOR, OriginalFirstThunk));
311 :
312 E : ASSERT_TRUE(iat_block != NULL);
313 E : ASSERT_TRUE(int_block != NULL);
314 E : ASSERT_EQ(iat_block->size(), int_block->size());
315 E : ASSERT_EQ(iat_block->data_size(), int_block->data_size());
316 : ASSERT_EQ(0,
317 E : memcmp(iat_block->data(), int_block->data(), iat_block->data_size()));
318 :
319 : // Now check that each slot, save for the last one, in the IAT/INT
320 : // points to a name block or else is an ordinal.
321 E : size_t num_thunks = iat_block->data_size() / sizeof(IMAGE_THUNK_DATA) - 1;
322 : const IMAGE_THUNK_DATA* iat =
323 E : reinterpret_cast<const IMAGE_THUNK_DATA*>(iat_block->data());
324 E : for (size_t i = 0; i < num_thunks; ++i) {
325 E : if (!IMAGE_ORDINAL(iat[i].u1.Ordinal)) {
326 i : size_t thunk_offset = sizeof(IMAGE_THUNK_DATA) * i;
327 i : ASSERT_TRUE(FindReferencedBlock(iat_block, thunk_offset) != NULL);
328 i : ASSERT_TRUE(FindReferencedBlock(int_block, thunk_offset) != NULL);
329 : }
330 E : }
331 E : }
332 :
333 : // Check that the sentinel is all zero.
334 E : IMAGE_IMPORT_DESCRIPTOR zero = {};
335 : const IMAGE_IMPORT_DESCRIPTOR* sentinel =
336 : reinterpret_cast<const IMAGE_IMPORT_DESCRIPTOR*>(block->data()) +
337 E : num_descriptors - 1;
338 E : EXPECT_EQ(0, memcmp(sentinel, &zero, sizeof(zero)));
339 :
340 E : std::set<std::string> expected;
341 E : expected.insert("KERNEL32.dll");
342 E : expected.insert("export_dll.dll");
343 E : EXPECT_THAT(import_names, ContainerEq(expected));
344 :
345 : // The number of expected symbols imported from kernel32.dll.
346 : #if defined(NDEBUG)
347 : // VC++ 2013 Release Build.
348 : static size_t kNumKernel32Symbols = 63;
349 : #else
350 : // VC++ 2013 Debug/Coverage build.
351 : static size_t kNumKernel32Symbols = 64;
352 : #endif
353 : // The number of expected symbols imported from export_dll.dll.
354 : static const size_t kNumExportDllSymbols = 3;
355 :
356 E : ImportMap expected_import_map;
357 E : expected_import_map["KERNEL32.dll"] = kNumKernel32Symbols;
358 E : expected_import_map["export_dll.dll"] = kNumExportDllSymbols;
359 E : EXPECT_THAT(import_map_, ContainerEq(expected_import_map));
360 :
361 E : EXPECT_EQ(kNumKernel32Symbols + kNumExportDllSymbols, import_set_.size());
362 : EXPECT_THAT(import_set_, Contains(std::make_pair(
363 E : std::string("KERNEL32.dll"), std::string("ExitProcess"))));
364 : EXPECT_THAT(import_set_, Contains(std::make_pair(
365 E : std::string("export_dll.dll"), std::string("function1"))));
366 E : }
367 :
368 E : TEST_F(PEFileParserTest, ParseDelayImportDir) {
369 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
370 :
371 E : PEFileParser::PEHeader header;
372 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
373 :
374 : const IMAGE_NT_HEADERS* nt_headers =
375 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
376 :
377 : const IMAGE_DATA_DIRECTORY& dir =
378 : nt_headers->OptionalHeader.DataDirectory[
379 E : IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
380 E : BlockGraph::Block* block = parser.ParseDelayImportDir(dir);
381 E : ASSERT_TRUE(block != NULL);
382 :
383 : // Test that we have the import descriptors we expect - we expect
384 : // the one delay import, plus the sentinel import descriptor to be
385 : // chunked out.
386 E : size_t num_descriptors = block->size() / sizeof(ImgDelayDescr);
387 E : ASSERT_EQ(2, num_descriptors);
388 E : ASSERT_TRUE(block->data() != NULL);
389 E : ASSERT_EQ(block->size(), block->data_size());
390 :
391 E : std::set<std::string> import_names;
392 E : for (size_t i = 0; i < num_descriptors - 1; ++i) {
393 E : size_t element_offset = sizeof(ImgDelayDescr) * i;
394 : BlockGraph::Block* name_block =
395 : FindReferencedBlock(block, element_offset +
396 E : offsetof(ImgDelayDescr, rvaDLLName));
397 E : ASSERT_TRUE(name_block != NULL);
398 :
399 : const char* name =
400 E : reinterpret_cast<const char*>(name_block->data());
401 E : EXPECT_TRUE(import_names.insert(name).second);
402 :
403 : // Now retrieve the IAT, INT and BoundIAT blocks.
404 : BlockGraph::Block* iat_block =
405 : FindReferencedBlock(block, element_offset +
406 E : offsetof(ImgDelayDescr, rvaIAT));
407 : BlockGraph::Block* int_block =
408 : FindReferencedBlock(block, element_offset +
409 E : offsetof(ImgDelayDescr, rvaINT));
410 : BlockGraph::Block* bound_iat_block =
411 : FindReferencedBlock(block, element_offset +
412 E : offsetof(ImgDelayDescr, rvaBoundIAT));
413 :
414 E : ASSERT_TRUE(iat_block != NULL);
415 E : ASSERT_TRUE(int_block != NULL);
416 E : ASSERT_TRUE(bound_iat_block != NULL);
417 :
418 E : ASSERT_EQ(iat_block->size(), int_block->size());
419 E : ASSERT_EQ(iat_block->size(), bound_iat_block->size());
420 E : ASSERT_EQ(iat_block->data_size(), int_block->data_size());
421 E : ASSERT_EQ(iat_block->data_size(), bound_iat_block->data_size());
422 :
423 : // Now check that each slot, save for the last one, in the INT
424 : // points to a name block or else is an ordinal.
425 E : size_t num_thunks = iat_block->data_size() / sizeof(IMAGE_THUNK_DATA) - 1;
426 : const IMAGE_THUNK_DATA* iat =
427 E : reinterpret_cast<const IMAGE_THUNK_DATA*>(int_block->data());
428 E : for (size_t i = 0; i < num_thunks; ++i) {
429 E : if (!IMAGE_ORDINAL(iat[i].u1.Ordinal)) {
430 i : size_t thunk_offset = sizeof(IMAGE_THUNK_DATA) * i;
431 i : ASSERT_TRUE(FindReferencedBlock(int_block, thunk_offset) != NULL);
432 : }
433 E : }
434 E : }
435 :
436 : // Check that the sentinel is all zero.
437 E : ImgDelayDescr zero = {};
438 : const ImgDelayDescr* sentinel =
439 : reinterpret_cast<const ImgDelayDescr*>(block->data()) +
440 E : num_descriptors - 1;
441 E : EXPECT_EQ(0, memcmp(sentinel, &zero, sizeof(zero)));
442 :
443 E : std::set<std::string> expected;
444 E : expected.insert("ole32.dll");
445 E : EXPECT_THAT(import_names, ContainerEq(expected));
446 E : }
447 :
448 E : TEST_F(PEFileParserTest, ParseImage) {
449 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
450 :
451 E : PEFileParser::PEHeader header;
452 E : EXPECT_TRUE(parser.ParseImage(&header));
453 :
454 : // Check that the DOS header was read successfully.
455 E : ASSERT_TRUE(header.dos_header != NULL);
456 E : ASSERT_GE(header.dos_header->size(), sizeof(IMAGE_DOS_HEADER));
457 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.dos_header->type());
458 : // Check the underlying data.
459 E : ASSERT_GE(header.dos_header->data_size(), sizeof(IMAGE_DOS_HEADER));
460 : const IMAGE_DOS_HEADER* dos_header =
461 E : reinterpret_cast<const IMAGE_DOS_HEADER*>(header.dos_header->data());
462 E : ASSERT_TRUE(dos_header != NULL);
463 E : ASSERT_EQ(IMAGE_DOS_SIGNATURE, dos_header->e_magic);
464 :
465 : // Check the NT headers.
466 E : ASSERT_TRUE(header.nt_headers != NULL);
467 E : ASSERT_GT(header.nt_headers->size(), sizeof(IMAGE_NT_HEADERS));
468 E : ASSERT_EQ(header.nt_headers->data_size(), header.nt_headers->size());
469 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.nt_headers->type());
470 : const IMAGE_NT_HEADERS* nt_headers =
471 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
472 E : ASSERT_TRUE(nt_headers != NULL);
473 E : ASSERT_EQ(IMAGE_NT_OPTIONAL_HDR32_MAGIC, nt_headers->OptionalHeader.Magic);
474 :
475 E : const IMAGE_SECTION_HEADER* section_headers = NULL;
476 : // Check that the data accounts for the image section headers.
477 : ASSERT_EQ(nt_headers->FileHeader.NumberOfSections * sizeof(*section_headers) +
478 E : sizeof(*nt_headers), header.nt_headers->data_size());
479 :
480 : section_headers =
481 E : reinterpret_cast<const IMAGE_SECTION_HEADER*>(nt_headers + 1);
482 :
483 : // Now check the various data directory sections we expect to be non NULL.
484 : // We know the test dll has exports.
485 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
486 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_EXPORT]));
487 : // And imports.
488 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
489 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT]));
490 : // And resources.
491 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
492 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]));
493 : // And relocs.
494 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
495 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC]));
496 : // And a debug directory.
497 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
498 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_DEBUG]));
499 : // And a tls directory?
500 : // TODO(siggi): add some TLS data to the test DLL.
501 : // EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
502 : // header.data_directory[IMAGE_DIRECTORY_ENTRY_TLS]));
503 : // And a load configuration directory.
504 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
505 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]));
506 : // And a delay import directory.
507 : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
508 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]));
509 E : }
510 :
511 : } // namespace pe
|