Coverage for /Syzygy/pe/pe_file_parser_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
96.7%2973070.C++test

Line-by-line coverage:

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

Coverage information generated Fri Jul 29 11:00:21 2016.