Coverage for /Syzygy/pdb/pdb_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.8%4724730.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_util.h"
  16    :  
  17    :  #include <objbase.h>
  18    :  
  19    :  #include "base/command_line.h"
  20    :  #include "base/path_service.h"
  21    :  #include "base/process_util.h"
  22    :  #include "base/scoped_native_library.h"
  23    :  #include "base/scoped_temp_dir.h"
  24    :  #include "base/utf_string_conversions.h"
  25    :  #include "base/win/pe_image.h"
  26    :  #include "gmock/gmock.h"
  27    :  #include "gtest/gtest.h"
  28    :  #include "syzygy/core/unittest_util.h"
  29    :  #include "syzygy/pdb/pdb_byte_stream.h"
  30    :  #include "syzygy/pdb/pdb_reader.h"
  31    :  #include "syzygy/pdb/pdb_writer.h"
  32    :  #include "syzygy/pdb/unittest_util.h"
  33    :  #include "syzygy/pe/pe_data.h"
  34    :  
  35    :  namespace pdb {
  36    :  
  37    :  namespace {
  38    :  
  39    :  const wchar_t* kTempPdbFileName = L"temp.pdb";
  40    :  const wchar_t* kTempPdbFileName2 = L"temp2.pdb";
  41    :  
  42    :  const GUID kSampleGuid = {0xACDC900D, 0x9009, 0xFEED, {7, 6, 5, 4, 3, 2, 1, 0}};
  43    :  
  44    :  const PdbInfoHeader70 kSamplePdbHeader = {
  45    :    kPdbCurrentVersion,
  46    :    1336402486,  // 7 May 2012, 14:54:00 GMT.
  47    :    999,
  48    :    {0xDEADBEEF, 0x900D, 0xF00D, {0, 1, 2, 3, 4, 5, 6, 7}}
  49    :  };
  50    :  
  51    :  const DbiHeader kSampleDbiHeader = {
  52    :    -1,   // signature.
  53    :    19990903,  // version.
  54    :    999,  // age.
  55    :  };
  56    :  
  57    :  const OMAP kOmapToData[] = {
  58    :    {4096, 4096},
  59    :    {5012, 5012},
  60    :    {6064, 6064},
  61    :    {7048, 240504}
  62    :  };
  63    :  
  64    :  const OMAP kOmapFromData[] = {
  65    :    {4096, 4096},
  66    :    {5012, 5012},
  67    :    {240504, 7048}
  68    :  };
  69    :  
  70    :  class PdbUtilTest : public testing::Test {
  71    :   public:
  72  E :    PdbUtilTest() : ALLOW_THIS_IN_INITIALIZER_LIST(process_(this)) {
  73  E :    }
  74    :  
  75  E :    void SetUp() {
  76  E :      ASSERT_TRUE(::SymInitialize(process_, NULL, FALSE));
  77    :  
  78  E :      ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&new_guid_));
  79  E :      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  80    :  
  81  E :      temp_pdb_file_path_ = temp_dir_.path().Append(kTempPdbFileName);
  82  E :      temp_pdb_file_path2_ = temp_dir_.path().Append(kTempPdbFileName2);
  83  E :    }
  84    :  
  85  E :    void TearDown() {
  86  E :      ASSERT_TRUE(::SymCleanup(process_));
  87  E :    }
  88    :  
  89    :    void VerifyGuidData(const FilePath& pdb_path,
  90    :                        const GUID& guid) {
  91    :      DWORD64 base_address =
  92    :          ::SymLoadModuleExW(process_,
  93    :                             NULL,
  94    :                             pdb_path.value().c_str(),
  95    :                             NULL,
  96    :                             1,
  97    :                             1,
  98    :                             NULL,
  99    :                             0);
 100    :      EXPECT_NE(0, base_address);
 101    :  
 102    :      // Get the module info to verify that the new PDB has the GUID we specified.
 103    :      IMAGEHLP_MODULEW64 module_info = { sizeof(module_info) };
 104    :      EXPECT_TRUE(::SymGetModuleInfoW64(process_, base_address, &module_info));
 105    :      EXPECT_EQ(new_guid_, module_info.PdbSig70);
 106    :  
 107    :      EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
 108    :    }
 109    :  
 110    :    void VerifyOmapData(const FilePath& pdb_path,
 111    :                        const std::vector<OMAP>& omap_to_list,
 112  E :                        const std::vector<OMAP>& omap_from_list) {
 113    :      DWORD64 base_address =
 114    :          ::SymLoadModuleExW(process_,
 115    :                             NULL,
 116    :                             pdb_path.value().c_str(),
 117    :                             NULL,
 118    :                             1,
 119    :                             1,
 120    :                             NULL,
 121  E :                             0);
 122  E :      ASSERT_NE(0, base_address);
 123    :  
 124  E :      OMAP* omap_to = NULL;
 125  E :      DWORD64 omap_to_length = 0;
 126  E :      OMAP* omap_from = NULL;
 127  E :      DWORD64 omap_from_length = 0;
 128  E :      ASSERT_TRUE(::SymGetOmaps(process_,
 129    :                                base_address,
 130    :                                &omap_to,
 131    :                                &omap_to_length,
 132    :                                &omap_from,
 133    :                                &omap_from_length));
 134    :  
 135  E :      ASSERT_EQ(omap_to_list.size(), omap_to_length);
 136  E :      EXPECT_EQ(0, memcmp(&omap_to_list[0], omap_to,
 137    :                          omap_to_list.size() * sizeof(OMAP)));
 138  E :      ASSERT_EQ(omap_from_list.size(), omap_from_length);
 139  E :      EXPECT_EQ(0, memcmp(&omap_from_list[0], omap_from,
 140    :                          omap_from_list.size() * sizeof(OMAP)));
 141    :  
 142  E :      EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
 143  E :    }
 144    :  
 145    :   protected:
 146    :    HANDLE process_;
 147    :    GUID new_guid_;
 148    :    ScopedTempDir temp_dir_;
 149    :    FilePath temp_pdb_file_path_;
 150    :    FilePath temp_pdb_file_path2_;
 151    :  };
 152    :  
 153    :  class TestPdbStream : public PdbStream {
 154    :   public:
 155  E :    TestPdbStream() : PdbStream(0), bytes_(NULL) {
 156  E :    }
 157    :  
 158    :    template<typename T> TestPdbStream(const T& t)
 159    :        : PdbStream(sizeof(T)),
 160  E :          bytes_(reinterpret_cast<const uint8*>(&t)) {
 161  E :    }
 162    :  
 163    :    virtual bool ReadBytes(void* dest,
 164    :                           size_t count,
 165  E :                           size_t* bytes_read) OVERRIDE {
 166  E :      if (pos() >= length())
 167  i :        return false;
 168  E :      size_t max_count = length() - pos();
 169  E :      *bytes_read = max_count < count ? max_count : count;
 170  E :      ::memcpy(dest, bytes_ + pos(), *bytes_read);
 171  E :      Seek(pos() + *bytes_read);
 172  E :      return *bytes_read == count;
 173  E :    }
 174    :  
 175    :   private:
 176    :    const uint8* const bytes_;
 177    :  };
 178    :  
 179    :  // Comparison operator for PdbInfoHeader70 objects.
 180    :  bool AreEqual(const PdbInfoHeader70& header1,
 181  E :                const PdbInfoHeader70& header2) {
 182  E :    return ::memcmp(&header1, &header2, sizeof(header1)) == 0;
 183  E :  }
 184    :  
 185    :  }  // namespace
 186    :  
 187  E :  TEST(PdbBitSetTest, ReadEmptyStream) {
 188  E :    scoped_refptr<PdbStream> stream(new TestPdbStream());
 189  E :    PdbBitSet bs;
 190  E :    EXPECT_FALSE(bs.Read(stream.get()));
 191  E :  }
 192    :  
 193  E :  TEST(PdbBitSetTest, SimpleMutators) {
 194  E :    PdbBitSet bs;
 195  E :    EXPECT_TRUE(bs.IsEmpty());
 196  E :    EXPECT_EQ(bs.size(), 0u);
 197  E :    bs.Resize(43);
 198  E :    EXPECT_EQ(bs.size(), 64u);
 199    :  
 200  E :    for (size_t i = 0; i < 64; ++i)
 201  E :      EXPECT_FALSE(bs.IsSet(i));
 202    :  
 203  E :    bs.Toggle(15);
 204  E :    EXPECT_TRUE(bs.IsSet(15));
 205  E :    bs.Toggle(15);
 206  E :    EXPECT_FALSE(bs.IsSet(15));
 207    :  
 208  E :    bs.Set(25);
 209  E :    EXPECT_TRUE(bs.IsSet(25));
 210  E :    bs.Clear(25);
 211  E :    EXPECT_FALSE(bs.IsSet(25));
 212    :  
 213  E :    for (size_t i = 0; i < 64; i += 10)
 214  E :      bs.Set(i);
 215    :  
 216  E :    for (size_t i = 0; i < 64; ++i)
 217  E :      EXPECT_EQ((i % 10) == 0, bs.IsSet(i));
 218  E :  }
 219    :  
 220  E :  TEST(PdbBitSetTest, ReadEmptyBitSet) {
 221  E :    const uint32 kSize = 0;
 222  E :    scoped_refptr<PdbStream> stream(new TestPdbStream(kSize));
 223  E :    PdbBitSet bs;
 224  E :    EXPECT_TRUE(bs.Read(stream.get()));
 225  E :    EXPECT_TRUE(bs.IsEmpty());
 226  E :    EXPECT_EQ(bs.size(), 0u);
 227  E :  }
 228    :  
 229  E :  TEST(PdbBitSetTest, ReadSingleDwordBitSet) {
 230  E :    const uint32 kData[] = { 1, (1<<0) | (1<<5) | (1<<13) };
 231  E :    scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
 232  E :    PdbBitSet bs;
 233  E :    EXPECT_TRUE(bs.Read(stream.get()));
 234  E :    EXPECT_FALSE(bs.IsEmpty());
 235  E :    EXPECT_EQ(bs.size(), 32u);
 236  E :    for (size_t i = 0; i < bs.size(); ++i)
 237  E :      EXPECT_EQ(i == 0 || i == 5 || i == 13, bs.IsSet(i));
 238  E :  }
 239    :  
 240  E :  TEST(PdbBitSetTest, ReadMultiDwordBitSet) {
 241  E :    const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
 242  E :    scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
 243  E :    PdbBitSet bs;
 244  E :    EXPECT_TRUE(bs.Read(stream.get()));
 245  E :    EXPECT_FALSE(bs.IsEmpty());
 246  E :    EXPECT_EQ(bs.size(), 64u);
 247  E :    for (size_t i = 0; i < bs.size(); ++i)
 248  E :      EXPECT_EQ(i == 0 || i == 5 || i == 13 || i == (32 + 5), bs.IsSet(i));
 249  E :  }
 250    :  
 251  E :  TEST(PdbBitSetTest, WriteEmptyBitSet) {
 252  E :    const uint32 kData[] = { 0 };
 253  E :    scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
 254  E :    PdbBitSet bs;
 255  E :    EXPECT_TRUE(bs.Read(stream.get()));
 256    :  
 257  E :    scoped_refptr<PdbByteStream> reader(new PdbByteStream());
 258  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 259  E :    EXPECT_TRUE(bs.Write(writer.get()));
 260    :  
 261  E :    std::vector<uint32> data;
 262  E :    EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
 263  E :    EXPECT_THAT(data, testing::ElementsAreArray(kData));
 264  E :  }
 265    :  
 266  E :  TEST(PdbBitSetTest, WriteBitSet) {
 267  E :    const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
 268  E :    scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
 269  E :    PdbBitSet bs;
 270  E :    EXPECT_TRUE(bs.Read(stream.get()));
 271    :  
 272  E :    scoped_refptr<PdbByteStream> reader(new PdbByteStream());
 273  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 274  E :    EXPECT_TRUE(bs.Write(writer.get()));
 275  E :    EXPECT_EQ(sizeof(kData), reader->length());
 276    :  
 277  E :    std::vector<uint32> data;
 278  E :    EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
 279  E :    EXPECT_THAT(data, testing::ElementsAreArray(kData));
 280  E :  }
 281    :  
 282  E :  TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetTestDll) {
 283    :    // Test the test_dll.pdb doesn't have Omap information.
 284  E :    PdbReader reader;
 285  E :    PdbFile pdb_file;
 286    :    EXPECT_TRUE(reader.Read(
 287    :        testing::GetSrcRelativePath(testing::kTestPdbFilePath),
 288  E :        &pdb_file));
 289    :  
 290  E :    PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
 291    :    DbiHeader dbi_header;
 292  E :    EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
 293    :  
 294  E :    uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
 295  E :    EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
 296    :  
 297  E :    EXPECT_TRUE(dbi_stream->Seek(offset));
 298    :    DbiDbgHeader dbi_dbg_header;
 299  E :    EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
 300    :  
 301  E :    EXPECT_EQ(-1, dbi_dbg_header.omap_to_src);
 302  E :    EXPECT_EQ(-1, dbi_dbg_header.omap_from_src);
 303  E :  }
 304    :  
 305  E :  TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetOmappedTestDll) {
 306    :    // Test that omapped_test_dll.pdb does have Omap information.
 307  E :    PdbReader reader;
 308  E :    PdbFile pdb_file;
 309    :    EXPECT_TRUE(reader.Read(
 310    :        testing::GetSrcRelativePath(testing::kOmappedTestPdbFilePath),
 311  E :        &pdb_file));
 312    :  
 313  E :    PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
 314    :    DbiHeader dbi_header;
 315  E :    EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
 316    :  
 317  E :    uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
 318  E :    EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
 319    :  
 320  E :    EXPECT_TRUE(dbi_stream->Seek(offset));
 321    :    DbiDbgHeader dbi_dbg_header;
 322  E :    EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
 323    :  
 324  E :    EXPECT_NE(-1, dbi_dbg_header.omap_to_src);
 325  E :    EXPECT_NE(-1, dbi_dbg_header.omap_from_src);
 326  E :  }
 327    :  
 328  E :  TEST_F(PdbUtilTest, TestDllHasNoOmap) {
 329    :    // Test that test_dll.pdb has no Omap information.
 330    :    FilePath test_pdb_file_path = testing::GetSrcRelativePath(
 331  E :        testing::kTestPdbFilePath);
 332    :    DWORD64 base_address =
 333    :        ::SymLoadModuleExW(process_,
 334    :                           NULL,
 335    :                           test_pdb_file_path.value().c_str(),
 336    :                           NULL,
 337    :                           1,
 338    :                           1,
 339    :                           NULL,
 340  E :                           0);
 341  E :    EXPECT_NE(0, base_address);
 342    :  
 343  E :    OMAP* omap_to = NULL;
 344  E :    DWORD64 omap_to_length = 0;
 345  E :    OMAP* omap_from = NULL;
 346  E :    DWORD64 omap_from_length = 0;
 347    :    EXPECT_FALSE(::SymGetOmaps(process_,
 348    :                               base_address,
 349    :                               &omap_to,
 350    :                               &omap_to_length,
 351    :                               &omap_from,
 352  E :                               &omap_from_length));
 353    :  
 354  E :    EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
 355  E :  }
 356    :  
 357  E :  TEST_F(PdbUtilTest, SetOmapToAndFromStream) {
 358    :    // Add Omap information to test_dll.pdb and test that the output file
 359    :    // has Omap information.
 360    :    std::vector<OMAP> omap_to_list(kOmapToData,
 361  E :                                   kOmapToData + arraysize(kOmapToData));
 362    :    std::vector<OMAP> omap_from_list(kOmapFromData,
 363  E :                                     kOmapFromData + arraysize(kOmapFromData));
 364    :  
 365    :    FilePath test_pdb_file_path = testing::GetSrcRelativePath(
 366  E :        testing::kTestPdbFilePath);
 367  E :    PdbReader pdb_reader;
 368  E :    PdbFile pdb_file;
 369  E :    ASSERT_TRUE(pdb_reader.Read(test_pdb_file_path, &pdb_file));
 370    :  
 371  E :    EXPECT_TRUE(SetOmapToStream(omap_to_list, &pdb_file));
 372  E :    EXPECT_TRUE(SetOmapFromStream(omap_from_list, &pdb_file));
 373    :  
 374  E :    PdbWriter pdb_writer;
 375  E :    ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
 376    :  
 377    :    VerifyOmapData(temp_pdb_file_path_,
 378    :                   omap_to_list,
 379  E :                   omap_from_list);
 380  E :  }
 381    :  
 382  E :  TEST_F(PdbUtilTest, PdbHeaderMatchesImageDebugDirectory) {
 383  E :    PdbReader reader;
 384  E :    PdbFile pdb_file;
 385    :    EXPECT_TRUE(reader.Read(
 386    :        testing::GetSrcRelativePath(testing::kTestPdbFilePath),
 387  E :        &pdb_file));
 388    :  
 389  E :    PdbInfoHeader70 header = { 0 };
 390  E :    ASSERT_GE(pdb_file.StreamCount(), kPdbHeaderInfoStream);
 391  E :    ASSERT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream) != NULL);
 392  E :    EXPECT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream)->Read(&header, 1));
 393  E :    EXPECT_EQ(header.version, kPdbCurrentVersion);
 394    :  
 395  E :    std::string error;
 396    :    base::NativeLibrary test_dll =
 397    :        base::LoadNativeLibrary(
 398    :            testing::GetSrcRelativePath(testing::kTestDllFilePath),
 399  E :            &error);
 400  E :    ASSERT_TRUE(test_dll != NULL);
 401    :  
 402    :    // Make sure the DLL is unloaded on exit.
 403  E :    base::ScopedNativeLibrary test_dll_keeper(test_dll);
 404  E :    base::win::PEImage image(test_dll);
 405    :  
 406    :    // Retrieve the NT headers to make it easy to look at them in debugger.
 407  E :    const IMAGE_NT_HEADERS* nt_headers = image.GetNTHeaders();
 408    :  
 409    :    ASSERT_EQ(sizeof(IMAGE_DEBUG_DIRECTORY),
 410  E :              image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG));
 411    :    const IMAGE_DEBUG_DIRECTORY* debug_directory =
 412    :        reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(
 413  E :            image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
 414    :  
 415  E :    ASSERT_EQ(IMAGE_DEBUG_TYPE_CODEVIEW, debug_directory->Type);
 416  E :    ASSERT_GE(debug_directory->SizeOfData, sizeof(pe::CvInfoPdb70));
 417    :  
 418    :    const pe::CvInfoPdb70* cv_info =
 419    :        reinterpret_cast<const pe::CvInfoPdb70*>(
 420  E :            image.RVAToAddr(debug_directory->AddressOfRawData));
 421    :  
 422  E :    ASSERT_EQ(pe::kPdb70Signature, cv_info->cv_signature);
 423  E :    ASSERT_EQ(header.signature, cv_info->signature);
 424  E :    ASSERT_EQ(header.pdb_age, cv_info->pdb_age);
 425  E :  }
 426    :  
 427  E :  TEST_F(PdbUtilTest, ReadPdbHeader) {
 428    :    const FilePath pdb_path = testing::GetSrcRelativePath(
 429  E :        testing::kTestPdbFilePath);
 430  E :    PdbInfoHeader70 pdb_header = {};
 431  E :    EXPECT_TRUE(ReadPdbHeader(pdb_path, &pdb_header));
 432  E :  }
 433    :  
 434  E :  TEST(EnsureStreamWritableTest, DoesNothingWhenAlreadyWritable) {
 435  E :    PdbFile pdb_file;
 436  E :    scoped_refptr<PdbStream> stream = new PdbByteStream();
 437  E :    size_t index = pdb_file.AppendStream(stream.get());
 438  E :    EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
 439  E :    scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
 440  E :    EXPECT_EQ(stream.get(), stream2.get());
 441  E :  }
 442    :  
 443  E :  TEST(EnsureStreamWritableTest, WorksWhenReadOnly) {
 444  E :    PdbFile pdb_file;
 445  E :    scoped_refptr<PdbStream> stream = new TestPdbStream();
 446  E :    size_t index = pdb_file.AppendStream(stream.get());
 447  E :    EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
 448  E :    scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
 449  E :    EXPECT_TRUE(stream2.get() != NULL);
 450  E :    EXPECT_NE(stream.get(), stream2.get());
 451  E :    EXPECT_TRUE(stream2->GetWritablePdbStream() != NULL);
 452  E :  }
 453    :  
 454  E :  TEST(EnsureStreamWritableTest, FailsWhenNonExistent) {
 455  E :    PdbFile pdb_file;
 456  E :    EXPECT_FALSE(EnsureStreamWritable(45, &pdb_file));
 457  E :  }
 458    :  
 459  E :  TEST(SetGuidTest, FailsWhenStreamsDoNotExist) {
 460  E :    PdbFile pdb_file;
 461    :  
 462    :    // Leave the Pdb header missing.
 463  E :    pdb_file.SetStream(kPdbHeaderInfoStream, NULL);
 464  E :    pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
 465  E :    EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
 466    :  
 467    :    // Add the header stream, but leave the Dbi header missing.
 468  E :    pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
 469  E :    pdb_file.SetStream(kDbiStream, NULL);
 470  E :    EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
 471  E :  }
 472    :  
 473  E :  TEST(SetGuidTest, FailsWhenStreamsAreTooShort) {
 474  E :    PdbFile pdb_file;
 475    :  
 476  E :    const uint8 kByte = 6;
 477  E :    pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kByte));
 478  E :    pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
 479  E :    EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
 480    :  
 481  E :    pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
 482  E :    pdb_file.SetStream(kDbiStream, new TestPdbStream(kByte));
 483  E :    EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
 484  E :  }
 485    :  
 486  E :  TEST(SetGuidTest, Succeeds) {
 487  E :    PdbFile pdb_file;
 488    :  
 489  E :    pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
 490  E :    pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
 491    :  
 492    :    scoped_refptr<PdbStream> stream =
 493  E :        pdb_file.GetStream(kPdbHeaderInfoStream);
 494  E :    ASSERT_TRUE(stream.get() != NULL);
 495  E :    ASSERT_EQ(stream->length(), sizeof(PdbInfoHeader70));
 496    :  
 497  E :    uint32 time1 = static_cast<uint32>(time(NULL));
 498  E :    EXPECT_TRUE(SetGuid(kSampleGuid, &pdb_file));
 499  E :    uint32 time2 = static_cast<uint32>(time(NULL));
 500    :  
 501    :    // Read the new header.
 502  E :    PdbInfoHeader70 pdb_header = {};
 503  E :    stream = pdb_file.GetStream(kPdbHeaderInfoStream);
 504  E :    EXPECT_TRUE(stream->Seek(0));
 505  E :    EXPECT_TRUE(stream->Read(&pdb_header, 1));
 506    :  
 507    :    // Validate that the fields are as expected.
 508  E :    EXPECT_LE(time1, pdb_header.timestamp);
 509  E :    EXPECT_LE(pdb_header.timestamp, time2);
 510  E :    EXPECT_EQ(1u, pdb_header.pdb_age);
 511  E :    EXPECT_EQ(kSampleGuid, pdb_header.signature);
 512    :  
 513  E :    DbiHeader dbi_header = {};
 514  E :    stream = pdb_file.GetStream(kDbiStream);
 515  E :    ASSERT_TRUE(stream.get() != NULL);
 516  E :    ASSERT_EQ(stream->length(), sizeof(dbi_header));
 517    :  
 518  E :    EXPECT_TRUE(stream->Seek(0));
 519  E :    EXPECT_TRUE(stream->Read(&dbi_header, 1));
 520  E :    EXPECT_EQ(1u, dbi_header.age);
 521  E :  }
 522    :  
 523  E :  TEST(ReadHeaderInfoStreamTest, ReadFromPdbFile) {
 524    :    const FilePath pdb_path = testing::GetSrcRelativePath(
 525  E :        testing::kTestPdbFilePath);
 526    :  
 527  E :    PdbFile pdb_file;
 528  E :    PdbReader pdb_reader;
 529  E :    ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
 530    :  
 531  E :    PdbInfoHeader70 pdb_header = {};
 532  E :    NameStreamMap name_stream_map;
 533  E :    EXPECT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
 534  E :  }
 535    :  
 536  E :  TEST(ReadHeaderInfoStreamTest, ReadEmptyStream) {
 537  E :    scoped_refptr<PdbStream> stream(new TestPdbStream());
 538  E :    PdbInfoHeader70 pdb_header = {};
 539  E :    NameStreamMap name_stream_map;
 540  E :    EXPECT_FALSE(ReadHeaderInfoStream(stream, &pdb_header, &name_stream_map));
 541  E :  }
 542    :  
 543  E :  TEST(ReadHeaderInfoStreamTest, ReadStreamWithOnlyHeader) {
 544  E :    scoped_refptr<PdbStream> reader(new PdbByteStream());
 545  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 546    :  
 547  E :    PdbInfoHeader70 pdb_header = {};
 548  E :    ASSERT_TRUE(writer->Write(pdb_header));
 549    :  
 550  E :    NameStreamMap name_stream_map;
 551  E :    EXPECT_FALSE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
 552  E :  }
 553    :  
 554  E :  TEST(ReadHeaderInfoStreamTest, ReadStreamWithEmptyNameStreamMap) {
 555  E :    scoped_refptr<PdbStream> reader(new PdbByteStream());
 556  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 557    :  
 558  E :    PdbInfoHeader70 pdb_header = {};
 559  E :    ASSERT_TRUE(writer->Write(pdb_header));
 560  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // total string length.
 561  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // number of names.
 562  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // size of bitsets.
 563  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // first bitset.
 564  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // second bitset.
 565    :  
 566  E :    NameStreamMap name_stream_map;
 567  E :    EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
 568  E :    EXPECT_EQ(name_stream_map.size(), 0u);
 569  E :  }
 570    :  
 571  E :  TEST(ReadHeaderInfoStreamTest, ReadStreamWithNameStreamMap) {
 572  E :    scoped_refptr<PdbStream> reader(new PdbByteStream());
 573  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 574    :  
 575  E :    PdbInfoHeader70 pdb_header = {};
 576  E :    ASSERT_TRUE(writer->Write(pdb_header));
 577  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(9)));  // total string length.
 578  E :    uint32 offset1 = writer->pos();
 579  E :    ASSERT_TRUE(writer->Write(3, "/a"));  // name 1.
 580  E :    uint32 offset2 = writer->pos();
 581  E :    ASSERT_TRUE(writer->Write(3, "/b"));  // name 2.
 582  E :    uint32 offset3 = writer->pos();
 583  E :    ASSERT_TRUE(writer->Write(3, "/c"));  // name 3.
 584  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(3)));  // number of names.
 585  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(3)));  // size of bitsets.
 586    :  
 587  E :    PdbBitSet present;
 588  E :    present.Resize(3);
 589  E :    present.Set(0);
 590  E :    present.Set(1);
 591  E :    present.Set(2);
 592  E :    ASSERT_TRUE(present.Write(writer));
 593    :  
 594  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(0)));  // second bitset.
 595    :  
 596  E :    ASSERT_TRUE(writer->Write(0));
 597  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(42)));
 598  E :    ASSERT_TRUE(writer->Write(offset2 - offset1));
 599  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(7)));
 600  E :    ASSERT_TRUE(writer->Write(offset3 - offset1));
 601  E :    ASSERT_TRUE(writer->Write(static_cast<uint32>(95)));
 602    :  
 603  E :    NameStreamMap name_stream_map;
 604  E :    EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
 605    :  
 606  E :    NameStreamMap expected;
 607  E :    expected["/a"] = 42;
 608  E :    expected["/b"] = 7;
 609  E :    expected["/c"] = 95;
 610  E :    EXPECT_THAT(name_stream_map, testing::ContainerEq(expected));
 611  E :  }
 612    :  
 613  E :  TEST(ReadHeaderInfoStreamTest, ReadFromPdb) {
 614    :    const FilePath pdb_path = testing::GetSrcRelativePath(
 615  E :        testing::kTestPdbFilePath);
 616  E :    PdbFile pdb_file;
 617  E :    PdbReader pdb_reader;
 618  E :    EXPECT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
 619    :  
 620  E :    PdbInfoHeader70 pdb_header = {};
 621  E :    NameStreamMap name_stream_map;
 622    :    EXPECT_TRUE(ReadHeaderInfoStream(pdb_file.GetStream(kPdbHeaderInfoStream),
 623    :                                     &pdb_header,
 624  E :                                     &name_stream_map));
 625  E :  }
 626    :  
 627  E :  TEST(WriteHeaderInfoStreamTest, WriteToPdbFile) {
 628    :    const FilePath pdb_path = testing::GetSrcRelativePath(
 629  E :        testing::kTestPdbFilePath);
 630    :  
 631  E :    PdbFile pdb_file;
 632  E :    PdbReader pdb_reader;
 633  E :    ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
 634    :  
 635  E :    PdbInfoHeader70 pdb_header = {};
 636  E :    NameStreamMap name_stream_map;
 637  E :    ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
 638    :  
 639  E :    pdb_header.pdb_age++;
 640  E :    name_stream_map["NewStream!"] = 999;
 641    :  
 642  E :    EXPECT_TRUE(WriteHeaderInfoStream(pdb_header, name_stream_map, &pdb_file));
 643    :  
 644  E :    PdbInfoHeader70 pdb_header2 = {};
 645  E :    NameStreamMap name_stream_map2;
 646  E :    ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header2, &name_stream_map2));
 647    :  
 648  E :    EXPECT_TRUE(AreEqual(pdb_header, pdb_header2));
 649  E :    EXPECT_EQ(name_stream_map, name_stream_map2);
 650  E :  }
 651    :  
 652  E :  TEST(WriteHeaderInfoStreamTest, WriteEmpty) {
 653  E :    scoped_refptr<PdbStream> reader(new PdbByteStream());
 654  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 655    :  
 656  E :    NameStreamMap name_stream_map;
 657    :    EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
 658    :                                      name_stream_map,
 659  E :                                      writer.get()));
 660    :  
 661  E :    PdbInfoHeader70 read_pdb_header = {};
 662  E :    NameStreamMap read_name_stream_map;
 663    :    EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
 664    :                                     &read_pdb_header,
 665  E :                                     &read_name_stream_map));
 666    :  
 667    :    EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
 668    :                          &read_pdb_header,
 669  E :                          sizeof(kSamplePdbHeader)));
 670  E :    EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
 671  E :  }
 672    :  
 673  E :  TEST(WriteHeaderInfoStreamTest, WriteNonEmpty) {
 674  E :    scoped_refptr<PdbStream> reader(new PdbByteStream());
 675  E :    scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
 676    :  
 677  E :    NameStreamMap name_stream_map;
 678  E :    name_stream_map["/StreamFoo"] = 9;
 679  E :    name_stream_map["/StreamBar"] = 42;
 680  E :    name_stream_map["/Stream/With/A/Path"] = 19;
 681    :    EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
 682    :                                      name_stream_map,
 683  E :                                      writer.get()));
 684    :  
 685  E :    PdbInfoHeader70 read_pdb_header = {};
 686  E :    NameStreamMap read_name_stream_map;
 687    :    EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
 688    :                                     &read_pdb_header,
 689  E :                                     &read_name_stream_map));
 690    :  
 691    :    EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
 692    :                          &read_pdb_header,
 693  E :                          sizeof(kSamplePdbHeader)));
 694  E :    EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
 695  E :  }
 696    :  
 697  E :  TEST_F(PdbUtilTest, NamedStreamsWorkWithPdbStr) {
 698    :    // We start by creating a PDB file (a copy of a checked in sample one) and
 699    :    // adding a new stream to it using our named-stream implementation.
 700    :    {
 701    :      FilePath orig_pdb_path = testing::GetSrcRelativePath(
 702  E :          testing::kTestPdbFilePath);
 703    :  
 704    :      // Read the sample PDB.
 705  E :      PdbReader pdb_reader;
 706  E :      PdbFile pdb_file;
 707  E :      ASSERT_TRUE(pdb_reader.Read(orig_pdb_path, &pdb_file));
 708    :  
 709    :      // Add a new stream to it.
 710  E :      scoped_refptr<PdbStream> foo_reader(new PdbByteStream());
 711    :      scoped_refptr<WritablePdbStream> foo_writer(
 712  E :          foo_reader->GetWritablePdbStream());
 713  E :      size_t foo_index = pdb_file.AppendStream(foo_reader.get());
 714  E :      foo_writer->WriteString("foo");
 715    :  
 716    :      // Get the PDB header stream.
 717    :      scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
 718  E :          kPdbHeaderInfoStream));
 719  E :      ASSERT_TRUE(header_stream.get() != NULL);
 720    :  
 721    :      // Read the existing name-stream map.
 722  E :      PdbInfoHeader70 pdb_header = {};
 723  E :      NameStreamMap name_stream_map;
 724    :      ASSERT_TRUE(ReadHeaderInfoStream(
 725  E :          header_stream, &pdb_header, &name_stream_map));
 726    :  
 727    :      // Add an entry for the new stream.
 728  E :      name_stream_map["foo"] = foo_index;
 729    :  
 730    :      // Write the new header stream to it.
 731  E :      scoped_refptr<PdbStream> new_header_reader(new PdbByteStream());
 732    :      scoped_refptr<WritablePdbStream> new_header_writer(
 733  E :          new_header_reader->GetWritablePdbStream());
 734    :      ASSERT_TRUE(pdb::WriteHeaderInfoStream(
 735  E :          pdb_header, name_stream_map, new_header_writer));
 736  E :      pdb_file.ReplaceStream(kPdbHeaderInfoStream, new_header_reader);
 737    :  
 738    :      // Write the PDB.
 739  E :      PdbWriter pdb_writer;
 740  E :      ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
 741  E :    }
 742    :  
 743    :    // We've now created a new PDB file. We want to make sure that pdbstr.exe
 744    :    // plays nicely with our named streams by doing a few things:
 745    :    // (1) If we try to read a non-existing stream, we should get empty output.
 746    :    // (2) We should be able to read an existing stream and get non-empty output.
 747    :    // (3) We should be able to add a new stream, and then read it using our
 748    :    //     mechanisms.
 749    :  
 750    :    // Get the path to pdbstr.exe, which we redistribute in third_party.
 751  E :    FilePath pdbstr_path = testing::GetSrcRelativePath(testing::kPdbStrPath);
 752    :  
 753    :    // Create the argument specifying the PDB path.
 754  E :    std::string pdb_arg = ::WideToUTF8(temp_pdb_file_path_.value());
 755  E :    pdb_arg.insert(0, "-p:");
 756    :  
 757    :    // First test: try to read a non-existing stream. Should produce no output.
 758    :    {
 759  E :      CommandLine cmd(pdbstr_path);
 760  E :      cmd.AppendArg(pdb_arg);
 761  E :      cmd.AppendArg("-r");
 762  E :      cmd.AppendArg("-s:nonexistent-stream-name");
 763  E :      std::string output;
 764  E :      ASSERT_TRUE(base::GetAppOutput(cmd, &output));
 765  E :      ASSERT_TRUE(output.empty());
 766  E :    }
 767    :  
 768    :    // Second test: read an existing stream (the one we just added). Should
 769    :    // exit without error and return the expected contents (with a trailing
 770    :    // newline).
 771    :    {
 772  E :      CommandLine cmd(pdbstr_path);
 773  E :      cmd.AppendArg(pdb_arg);
 774  E :      cmd.AppendArg("-r");
 775  E :      cmd.AppendArg("-s:foo");
 776  E :      std::string output;
 777  E :      ASSERT_TRUE(base::GetAppOutput(cmd, &output));
 778  E :      ASSERT_EQ(std::string("foo\r\n"), output);
 779  E :    }
 780    :  
 781    :    // Third test: Add another new stream. This should return without error, and
 782    :    // we should then be able to read the stream using our mechanisms.
 783    :    {
 784  E :      FilePath bar_txt = temp_dir_.path().Append(L"bar.txt");
 785    :      file_util::ScopedFILE bar_file(file_util::OpenFile(
 786  E :          bar_txt, "wb"));
 787  E :      fprintf(bar_file.get(), "bar");
 788  E :      bar_file.reset();
 789    :  
 790  E :      std::string bar_arg = WideToUTF8(bar_txt.value());
 791  E :      bar_arg.insert(0, "-i:");
 792    :  
 793  E :      CommandLine cmd(pdbstr_path);
 794  E :      cmd.AppendArg(pdb_arg);
 795  E :      cmd.AppendArg("-w");
 796  E :      cmd.AppendArg("-s:bar");
 797  E :      cmd.AppendArg(bar_arg);
 798  E :      std::string output;
 799  E :      ASSERT_TRUE(base::GetAppOutput(cmd, &output));
 800  E :      ASSERT_TRUE(output.empty());
 801    :  
 802  E :      PdbFile pdb_file;
 803  E :      PdbReader pdb_reader;
 804  E :      ASSERT_TRUE(pdb_reader.Read(temp_pdb_file_path_, &pdb_file));
 805    :  
 806    :      // Get the PDB header stream.
 807    :      scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
 808  E :          kPdbHeaderInfoStream));
 809  E :      ASSERT_TRUE(header_stream.get() != NULL);
 810    :  
 811    :      // Read the existing name-stream map.
 812  E :      PdbInfoHeader70 pdb_header = {};
 813  E :      NameStreamMap name_stream_map;
 814    :      ASSERT_TRUE(ReadHeaderInfoStream(
 815  E :          header_stream, &pdb_header, &name_stream_map));
 816    :  
 817    :      // There should be a 'bar' stream.
 818  E :      ASSERT_TRUE(name_stream_map.count("bar"));
 819    :  
 820    :      // Get the bar stream.
 821    :      scoped_refptr<PdbStream> bar_stream(pdb_file.GetStream(
 822  E :          name_stream_map["bar"]));
 823  E :      ASSERT_TRUE(bar_stream.get() != NULL);
 824    :  
 825    :      // Read all of the data and ensure it is as expected.
 826  E :      bar_stream->Seek(0);
 827  E :      std::string bar_data;
 828  E :      bar_data.resize(bar_stream->length());
 829  E :      ASSERT_TRUE(bar_stream->Read(&bar_data.at(0), bar_data.size()));
 830  E :      ASSERT_EQ("bar", bar_data);
 831  E :    }
 832  E :  }
 833    :  
 834  E :  TEST_F(PdbUtilTest, LoadNamedStreamFromPdbFile) {
 835  E :    PdbReader reader;
 836  E :    PdbFile pdb_file;
 837    :    EXPECT_TRUE(reader.Read(
 838    :        testing::GetOutputRelativePath(L"test_dll.pdb"),
 839  E :        &pdb_file));
 840    :  
 841  E :    scoped_refptr<PdbStream> stream;
 842    :    EXPECT_TRUE(LoadNamedStreamFromPdbFile(
 843  E :        "StreamThatDoesNotExist", &pdb_file, &stream));
 844  E :    EXPECT_TRUE(stream.get() == NULL);
 845    :  
 846    :    // The MSVC toolchain produces a handful of named streams whose existence we
 847    :    // can rely on.
 848  E :    EXPECT_TRUE(LoadNamedStreamFromPdbFile("/LinkInfo", &pdb_file, &stream));
 849  E :    ASSERT_TRUE(stream.get() != NULL);
 850  E :  }
 851    :  
 852    :  }  // namespace pdb

Coverage information generated Thu Mar 14 11:53:36 2013.