Coverage for /Syzygy/pdb/pdb_writer_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
96.9%62640.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/pdb/pdb_writer.h"
  16    :  
  17    :  #include <algorithm>
  18    :  #include <cstdio>
  19    :  #include <cstring>
  20    :  #include <string>
  21    :  #include <vector>
  22    :  
  23    :  #include "base/command_line.h"
  24    :  #include "base/files/scoped_temp_dir.h"
  25    :  #include "base/process/launch.h"
  26    :  #include "base/strings/utf_string_conversions.h"
  27    :  #include "gtest/gtest.h"
  28    :  #include "syzygy/msf/unittest_util.h"
  29    :  #include "syzygy/pdb/pdb_file.h"
  30    :  #include "syzygy/pdb/pdb_reader.h"
  31    :  #include "syzygy/pdb/pdb_stream.h"
  32    :  #include "syzygy/pdb/unittest_util.h"
  33    :  #include "syzygy/pe/unittest_util.h"
  34    :  
  35    :  namespace pdb {
  36    :  
  37    :  namespace {
  38    :  
  39    :  class TestPdbWriter : public PdbWriter {
  40    :   public:
  41    :    TestPdbWriter() {
  42    :    }
  43    :  
  44    :    ~TestPdbWriter() {
  45    :    }
  46    :  
  47    :    using PdbWriter::AppendStream;
  48    :  };
  49    :  
  50    :  class TestPdbStream : public PdbStream {
  51    :   public:
  52  E :    TestPdbStream(uint32 length, uint32 mask) : PdbStream(length), data_(length) {
  53  E :      uint32* data = reinterpret_cast<uint32*>(data_.data());
  54    :  
  55    :      // Just to make sure the data is non-repeating (so we can distinguish if it
  56    :      // has been correctly written or not) fill it with integers encoding their
  57    :      // own position in the stream.
  58  E :      for (size_t i = 0; i < data_.size() / sizeof(data[0]); ++i)
  59  E :        data[i] = i | mask;
  60  E :    }
  61    :  
  62  E :    bool ReadBytes(void* dest, size_t count, size_t* bytes_read) {
  63  E :      DCHECK(bytes_read != NULL);
  64    :  
  65  E :      if (pos() == length()) {
  66  i :        *bytes_read = 0;
  67  i :        return true;
  68    :      }
  69    :  
  70  E :      count = std::min(count, length() - pos());
  71  E :      ::memcpy(dest, data_.data() + pos(), count);
  72  E :      Seek(pos() + count);
  73  E :      *bytes_read = count;
  74    :  
  75  E :      return true;
  76  E :    }
  77    :  
  78  E :    const std::vector<uint8> data() const { return data_; }
  79    :  
  80    :   private:
  81    :    std::vector<uint8> data_;
  82    :  };
  83    :  
  84    :  }  // namespace
  85    :  
  86  E :  TEST(PdbWriterTest, PdbStrCompatible) {
  87    :    base::FilePath test_dll_msf =
  88  E :        testing::GetSrcRelativePath(testing::kTestPdbFilePath);
  89    :  
  90  E :    PdbFile file;
  91  E :    PdbReader reader;
  92  E :    ASSERT_TRUE(reader.Read(test_dll_msf, &file));
  93    :  
  94    :    // We need at least 8 MB of data in the DLL to ensure that the free page map
  95    :    // requires a second page. We manually add data to it until we get to that
  96    :    // point.
  97  E :    int64 test_dll_msf_length = 0;
  98  E :    ASSERT_TRUE(base::GetFileSize(test_dll_msf, &test_dll_msf_length));
  99  E :    while (test_dll_msf_length < 9 * 1024 * 1024) {
 100  E :      file.AppendStream(new TestPdbStream(1024 * 1024, file.StreamCount()));
 101  E :      test_dll_msf_length += 1024 * 1024;
 102  E :    }
 103    :  
 104    :    // Write the Syzygy modified PDB to disk.
 105  E :    base::ScopedTempDir temp_dir;
 106  E :    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 107  E :    base::FilePath msf_path = temp_dir.path().Append(testing::kTestPdbFilePath);
 108  E :    ASSERT_TRUE(base::CreateDirectory(msf_path.DirName()));
 109  E :    PdbWriter writer;
 110  E :    ASSERT_TRUE(writer.Write(msf_path, file));
 111    :  
 112    :    // Write a new stream to disk.
 113  E :    base::FilePath stream_path = temp_dir.path().AppendASCII("new_stream.dat");
 114  E :    scoped_refptr<TestPdbStream> new_stream(new TestPdbStream(1024 * 1024, 0xff));
 115    :    {
 116  E :      base::ScopedFILE stream_file(base::OpenFile(stream_path, "wb"));
 117  E :      ASSERT_TRUE(stream_file.get() != NULL);
 118    :      ASSERT_EQ(new_stream->data().size(),
 119    :                ::fwrite(new_stream->data().data(), sizeof(new_stream->data()[0]),
 120  E :                         new_stream->data().size(), stream_file.get()));
 121  E :    }
 122    :  
 123    :    // Get the path to pdbstr.exe, which we redistribute in third_party.
 124    :    base::FilePath msfstr_path =
 125  E :        testing::GetSrcRelativePath(testing::kPdbStrPath);
 126    :  
 127    :    // Create the arguments to pdbstr.
 128  E :    std::string msf_arg = base::WideToUTF8(msf_path.value());
 129  E :    msf_arg.insert(0, "-p:");
 130  E :    std::string stream_arg = base::WideToUTF8(stream_path.value());
 131  E :    stream_arg.insert(0, "-i:");
 132    :  
 133    :    // Add a new stream to the PDB in place. This should produce no output.
 134    :    {
 135  E :      base::CommandLine cmd(msfstr_path);
 136  E :      cmd.AppendArg(msf_arg);
 137  E :      cmd.AppendArg(stream_arg);
 138  E :      cmd.AppendArg("-w");
 139  E :      cmd.AppendArg("-s:nonexistent-stream-name");
 140    :  
 141  E :      std::string output;
 142  E :      ASSERT_TRUE(base::GetAppOutput(cmd, &output));
 143  E :      ASSERT_TRUE(output.empty());
 144  E :    }
 145    :  
 146    :    // Read the pdbstr modified PDB.
 147  E :    PdbFile file_read;
 148  E :    ASSERT_TRUE(reader.Read(msf_path, &file_read));
 149    :  
 150    :    // Add the new stream to the original PDB.
 151  E :    file.AppendStream(new_stream.get());
 152    :  
 153    :    // Clear stream 0 (the previous directory) and stream 1 (the PDB header
 154    :    // stream). These can vary but be functionally equivalent. We only care about
 155    :    // the actual content streams, which are the rest of them.
 156  E :    scoped_refptr<PdbStream> empty_stream(new TestPdbStream(0, 0));
 157  E :    file.ReplaceStream(0, empty_stream.get());
 158  E :    file.ReplaceStream(1, empty_stream.get());
 159  E :    file_read.ReplaceStream(0, empty_stream.get());
 160  E :    file_read.ReplaceStream(1, empty_stream.get());
 161    :  
 162    :    // Ensure that the two PDBs are identical.
 163    :    ASSERT_NO_FATAL_FAILURE(
 164  E :        testing::EnsureMsfContentsAreIdentical(file, file_read));
 165  E :  }
 166    :  
 167    :  }  // namespace pdb

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