Coverage for /Syzygy/pe/pe_relinker_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1651650.C++test

Line-by-line coverage:

   1    :  // Copyright 2013 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_relinker_util.h"
  16    :  
  17    :  #include "base/files/file_util.h"
  18    :  #include "base/strings/utf_string_conversions.h"
  19    :  #include "gtest/gtest.h"
  20    :  #include "syzygy/block_graph/typed_block.h"
  21    :  #include "syzygy/common/defs.h"
  22    :  #include "syzygy/core/unittest_util.h"
  23    :  #include "syzygy/pdb/pdb_reader.h"
  24    :  #include "syzygy/pdb/pdb_util.h"
  25    :  #include "syzygy/pe/decomposer.h"
  26    :  #include "syzygy/pe/pe_data.h"
  27    :  #include "syzygy/pe/unittest_util.h"
  28    :  
  29    :  namespace pe {
  30    :  
  31    :  namespace {
  32    :  
  33    :  using block_graph::BlockGraph;
  34    :  using block_graph::ConstTypedBlock;
  35    :  using block_graph::OrderedBlockGraph;
  36    :  
  37    :  typedef ConstTypedBlock<IMAGE_DATA_DIRECTORY> ImageDataDirectory;
  38    :  typedef ConstTypedBlock<IMAGE_DEBUG_DIRECTORY> ImageDebugDirectory;
  39    :  typedef ConstTypedBlock<IMAGE_DOS_HEADER> DosHeader;
  40    :  typedef ConstTypedBlock<IMAGE_NT_HEADERS> NtHeaders;
  41    :  
  42    :  class PERelinkerUtilTest : public testing::PELibUnitTest {
  43    :    typedef testing::PELibUnitTest Super;
  44    :  
  45    :   public:
  46  E :    PERelinkerUtilTest() : image_layout_(&block_graph_) {
  47  E :    }
  48    :  
  49  E :    void SetUp() {
  50  E :      Super::SetUp();
  51    :  
  52  E :      input_dll_ = testing::GetExeRelativePath(testing::kTestDllName);
  53  E :      input_pdb_ = testing::GetExeRelativePath(testing::kTestDllPdbName);
  54    :  
  55  E :      ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_));
  56  E :      temp_dll_ = temp_dir_.Append(testing::kTestDllName);
  57  E :      temp_pdb_ = temp_dir_.Append(testing::kTestDllPdbName);
  58  E :    }
  59    :  
  60  E :    void CreateFile(const base::FilePath& file) {
  61  E :      base::ScopedFILE f(base::OpenFile(file, "wb"));
  62  E :    }
  63    :  
  64  E :    void DecomposeTestDll() {
  65  E :      ASSERT_TRUE(pe_file_.Init(input_dll_));
  66  E :      pe::Decomposer decomposer(pe_file_);
  67  E :      ASSERT_TRUE(decomposer.Decompose(&image_layout_));
  68    :      dos_header_block_ = image_layout_.blocks.GetBlockByAddress(
  69  E :          core::RelativeAddress(0));
  70  E :      ASSERT_TRUE(dos_header_block_ != NULL);
  71  E :    }
  72    :  
  73  E :    bool BlockGraphHasSyzygyMetadataSection() const {
  74    :      BlockGraph::SectionMap::const_iterator it =
  75  E :          block_graph_.sections().begin();
  76  E :      for (; it != block_graph_.sections().end(); ++it) {
  77  E :        if (it->second.name() == common::kSyzygyMetadataSectionName)
  78  E :          return true;
  79  E :      }
  80  E :      return false;
  81  E :    }
  82    :  
  83    :    void CheckPdbInfo(const base::FilePath& pdb_path,
  84  E :                      const GUID& pdb_guid) {
  85  E :      DosHeader dos_header;
  86  E :      ASSERT_TRUE(dos_header.Init(0, dos_header_block_));
  87    :  
  88  E :      NtHeaders nt_headers;
  89  E :      ASSERT_TRUE(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
  90    :  
  91    :      const IMAGE_DATA_DIRECTORY* data_dir =
  92  E :          nt_headers->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
  93  E :      ImageDebugDirectory debug_dir;
  94  E :      ASSERT_TRUE(nt_headers.Dereference(data_dir->VirtualAddress, &debug_dir));
  95    :  
  96  E :      bool seen_cv_record = false;
  97  E :      for (size_t i = 0; i < debug_dir.ElementCount(); ++i) {
  98  E :        if (debug_dir[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW)
  99  E :          continue;
 100    :  
 101  E :        ASSERT_FALSE(seen_cv_record);
 102  E :        seen_cv_record = true;
 103    :  
 104  E :        ASSERT_LE(sizeof(CvInfoPdb70), debug_dir[i].SizeOfData);
 105  E :        ConstTypedBlock<CvInfoPdb70> pdb_info;
 106  E :        ASSERT_TRUE(debug_dir.Dereference(debug_dir[i].AddressOfRawData,
 107    :                                          &pdb_info));
 108    :  
 109  E :        ASSERT_EQ(pdb_guid, pdb_info->signature);
 110    :  
 111  E :        std::wstring pdb_file_name = base::UTF8ToWide(pdb_info->pdb_file_name);
 112  E :        ASSERT_EQ(pdb_path.value(), pdb_file_name);
 113  E :      }
 114  E :    }
 115    :  
 116    :    PETransformPolicy policy_;
 117    :    base::FilePath input_dll_;
 118    :    base::FilePath input_pdb_;
 119    :    base::FilePath temp_dir_;
 120    :    base::FilePath temp_dll_;
 121    :    base::FilePath temp_pdb_;
 122    :  
 123    :    pe::PEFile pe_file_;
 124    :    ImageLayout image_layout_;
 125    :    BlockGraph block_graph_;
 126    :    BlockGraph::Block* dos_header_block_;
 127    :  };
 128    :  
 129    :  }  // namespace
 130    :  
 131  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsInferPdbPaths) {
 132  E :    base::FilePath input_pdb, output_pdb;
 133    :  
 134    :    EXPECT_TRUE(ValidateAndInferPaths(
 135  E :        input_dll_, temp_dll_, false, &input_pdb, &output_pdb));
 136  E :    EXPECT_FALSE(input_pdb.empty());
 137  E :    EXPECT_FALSE(output_pdb.empty());
 138    :  
 139  E :    input_pdb.clear();
 140  E :    output_pdb.clear();
 141    :    EXPECT_TRUE(ValidateAndInferPaths(
 142  E :        input_dll_, temp_dll_, true, &input_pdb, &output_pdb));
 143  E :    EXPECT_FALSE(input_pdb.empty());
 144  E :    EXPECT_FALSE(output_pdb.empty());
 145  E :  }
 146    :  
 147  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsAllSpecified) {
 148    :    EXPECT_TRUE(ValidateAndInferPaths(
 149  E :        input_dll_, temp_dll_, false, &input_pdb_, &temp_pdb_));
 150  E :  }
 151    :  
 152  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsMissingInputPdb) {
 153  E :    base::FilePath output_pdb;
 154    :    EXPECT_FALSE(ValidateAndInferPaths(
 155  E :        input_dll_, temp_dll_, false, &temp_pdb_, &output_pdb));
 156  E :  }
 157    :  
 158  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsMismatchedInputPdb) {
 159  E :    base::FilePath output_pdb;
 160  E :    CreateFile(temp_pdb_);
 161    :    EXPECT_FALSE(ValidateAndInferPaths(
 162  E :        input_dll_, temp_pdb_, false, &input_pdb_, &output_pdb));
 163  E :  }
 164    :  
 165  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsExistingModule) {
 166  E :    CreateFile(temp_dll_);
 167    :  
 168    :    EXPECT_FALSE(ValidateAndInferPaths(
 169  E :        input_dll_, temp_dll_, false, &input_pdb_, &temp_pdb_));
 170    :  
 171    :    EXPECT_TRUE(ValidateAndInferPaths(
 172  E :        input_dll_, temp_dll_, true, &input_pdb_, &temp_pdb_));
 173  E :  }
 174    :  
 175  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsExistingPdb) {
 176  E :    CreateFile(temp_pdb_);
 177    :  
 178    :    EXPECT_FALSE(ValidateAndInferPaths(
 179  E :        input_dll_, temp_dll_, false, &input_pdb_, &temp_pdb_));
 180    :  
 181    :    EXPECT_TRUE(ValidateAndInferPaths(
 182  E :        input_dll_, temp_dll_, true, &input_pdb_, &temp_pdb_));
 183  E :  }
 184    :  
 185  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsInPlaceModule) {
 186  E :    base::FilePath output_dll = input_dll_;
 187    :    EXPECT_FALSE(ValidateAndInferPaths(
 188  E :        input_dll_, output_dll, false, &input_pdb_, &temp_pdb_));
 189  E :  }
 190    :  
 191  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsInPlacePdb) {
 192  E :    base::FilePath output_pdb = input_pdb_;
 193    :    EXPECT_FALSE(ValidateAndInferPaths(
 194  E :        input_dll_, temp_dll_, false, &input_pdb_, &output_pdb));
 195  E :  }
 196    :  
 197  E :  TEST_F(PERelinkerUtilTest, ValidateAndInferPathsBothOutputsSame) {
 198  E :    base::FilePath output_dll = temp_dll_;
 199  E :    base::FilePath output_pdb = temp_dll_;
 200    :    EXPECT_FALSE(ValidateAndInferPaths(
 201  E :        input_dll_, temp_dll_, false, &output_dll, &output_pdb));
 202  E :  }
 203    :  
 204  E :  TEST_F(PERelinkerUtilTest, FinalizeBlockGraphNoMetadata) {
 205  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 206    :  
 207  E :    DosHeader dos_header;
 208  E :    NtHeaders nt_headers;
 209  E :    ASSERT_TRUE(dos_header.Init(0, dos_header_block_));
 210  E :    ASSERT_TRUE(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
 211  E :    size_t header_section_count = nt_headers->FileHeader.NumberOfSections;
 212    :  
 213  E :    GUID guid = {};
 214    :    EXPECT_TRUE(FinalizeBlockGraph(input_dll_, temp_pdb_, guid, false,
 215  E :                                   &policy_, &block_graph_, dos_header_block_));
 216  E :    EXPECT_EQ(header_section_count, nt_headers->FileHeader.NumberOfSections);
 217    :  
 218  E :    EXPECT_FALSE(BlockGraphHasSyzygyMetadataSection());
 219  E :    ASSERT_NO_FATAL_FAILURE(CheckPdbInfo(temp_pdb_, guid));
 220  E :  }
 221    :  
 222  E :  TEST_F(PERelinkerUtilTest, FinalizeBlockGraphMetadata) {
 223  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 224    :  
 225  E :    DosHeader dos_header;
 226  E :    NtHeaders nt_headers;
 227  E :    ASSERT_TRUE(dos_header.Init(0, dos_header_block_));
 228  E :    ASSERT_TRUE(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
 229  E :    size_t header_section_count = nt_headers->FileHeader.NumberOfSections;
 230    :  
 231  E :    GUID guid = {};
 232    :    EXPECT_TRUE(FinalizeBlockGraph(input_dll_, temp_pdb_, guid, true,
 233  E :                                   &policy_, &block_graph_, dos_header_block_));
 234  E :    EXPECT_EQ(header_section_count + 1, nt_headers->FileHeader.NumberOfSections);
 235    :  
 236  E :    EXPECT_TRUE(BlockGraphHasSyzygyMetadataSection());
 237  E :    ASSERT_NO_FATAL_FAILURE(CheckPdbInfo(temp_pdb_, guid));
 238  E :  }
 239    :  
 240    :  // This is more of an integration test, but the individual transforms and
 241    :  // orderers are very thoroughly tested elsewhere.
 242  E :  TEST_F(PERelinkerUtilTest, FinalizeOrderedBlockGraphAndBuildImageLayout) {
 243  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 244  E :    OrderedBlockGraph obg(&block_graph_);
 245    :  
 246    :    // Move the DOS header block out of place.
 247  E :    BlockGraph::Section* section = block_graph_.FindSection(".text");
 248  E :    obg.PlaceAtHead(section);
 249  E :    obg.PlaceAtHead(section, dos_header_block_);
 250    :    ASSERT_EQ(dos_header_block_,
 251  E :              obg.ordered_section(section).ordered_blocks().front());
 252    :  
 253  E :    EXPECT_TRUE(FinalizeOrderedBlockGraph(&obg, dos_header_block_));
 254    :  
 255    :    // Ensure the DOS header block is no longer first. The section itself should
 256    :    // still be first.
 257    :    EXPECT_NE(dos_header_block_,
 258  E :              obg.ordered_section(section).ordered_blocks().front());
 259    :  
 260    :    // Build the layout and ensure it is as expected.
 261  E :    size_t kPadding = 8;
 262  E :    size_t kCodeAlign = 16;
 263  E :    ImageLayout image_layout(&block_graph_);
 264    :    EXPECT_TRUE(BuildImageLayout(kPadding, kCodeAlign, obg, dos_header_block_,
 265  E :                                 &image_layout));
 266    :  
 267    :    // Skip over header blocks.
 268  E :    BlockGraph::AddressSpace::RangeMapConstIter it = image_layout.blocks.begin();
 269    :    while (it != image_layout.blocks.end() &&
 270  E :           it->second->section() == BlockGraph::kInvalidSectionId) {
 271  E :      ++it;
 272  E :    }
 273    :  
 274    :    // We expect there to be blocks left.
 275  E :    ASSERT_TRUE(it != image_layout.blocks.end());
 276    :  
 277    :    // Make sure the rest of all blocks respect the padding and alignment.
 278  E :    BlockGraph::AddressSpace::RangeMapConstIter prev_it = it;
 279  E :    ++it;
 280  E :    while (it != image_layout.blocks.end()) {
 281  E :      ASSERT_LE(prev_it->first.end() + kPadding, it->first.start());
 282  E :      if (it->second->type() == BlockGraph::CODE_BLOCK)
 283  E :        ASSERT_EQ(0u, it->first.start().value() % kCodeAlign);
 284    :  
 285  E :      prev_it = it;
 286  E :      ++it;
 287  E :    }
 288  E :  }
 289    :  
 290    :  // Again, this is more of an integration test as the individual PDB mutators
 291    :  // are thoroughly tested elsewhere.
 292  E :  TEST_F(PERelinkerUtilTest, GetOmapRangeAndFinalizePdb) {
 293  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll());
 294    :  
 295  E :    RelativeAddressRange omap_range;
 296  E :    GetOmapRange(image_layout_.sections, &omap_range);
 297  E :    EXPECT_FALSE(omap_range.IsEmpty());
 298    :  
 299  E :    ASSERT_TRUE(base::CopyFile(input_dll_, temp_dll_));
 300    :  
 301  E :    pdb::PdbFile pdb_file;
 302  E :    pdb::PdbReader pdb_reader;
 303  E :    ASSERT_TRUE(pdb_reader.Read(input_pdb_, &pdb_file));
 304    :  
 305  E :    GUID guid = {};
 306    :    EXPECT_TRUE(FinalizePdbFile(input_dll_,
 307    :                                temp_dll_,
 308    :                                omap_range,
 309    :                                image_layout_,
 310    :                                guid,
 311    :                                true,   // augment_pdb.
 312    :                                false,  // strip_strings.
 313    :                                true,   // compress_pdb.
 314  E :                                &pdb_file));
 315    :  
 316    :    pdb::PdbInfoHeader70 pdb_header;
 317  E :    pdb::NameStreamMap pdb_name_stream_map;
 318    :    ASSERT_TRUE(pdb::ReadHeaderInfoStream(
 319  E :        pdb_file, &pdb_header, &pdb_name_stream_map));
 320    :  
 321  E :    EXPECT_EQ(guid, pdb_header.signature);
 322  E :  }
 323    :  
 324    :  }  // namespace pe

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