Coverage for /Syzygy/pe/pe_file_parser_unittest.cc

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

Coverage information generated Thu Jan 14 17:40:38 2016.