Coverage for /Syzygy/pe/dia_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.8%1801840.C++test

Line-by-line coverage:

   1    :  // Copyright 2011 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/dia_util.h"
  16    :  
  17    :  #include <map>
  18    :  #include <set>
  19    :  #include <vector>
  20    :  
  21    :  #include "base/bind.h"
  22    :  #include "base/files/file_path.h"
  23    :  #include "base/files/file_util.h"
  24    :  #include "base/win/scoped_bstr.h"
  25    :  #include "base/win/scoped_comptr.h"
  26    :  #include "gmock/gmock.h"
  27    :  #include "syzygy/core/file_util.h"
  28    :  #include "syzygy/core/unittest_util.h"
  29    :  #include "syzygy/pdb/pdb_data.h"
  30    :  #include "syzygy/pe/unittest_util.h"
  31    :  
  32    :  namespace pe {
  33    :  
  34    :  namespace {
  35    :  
  36    :  using base::win::ScopedBstr;
  37    :  using base::win::ScopedComPtr;
  38    :  
  39    :  typedef std::vector<std::wstring> StringVector;
  40    :  
  41    :  static const wchar_t kNonsenseStreamName[] =
  42    :      L"ThisStreamNameCertainlyDoesNotExist";
  43    :  
  44    :  // The test_dll output file name configured by the build system.
  45    :  static const char kTestDllObjPath[] = TEST_DLL_OBJECT_FILE;
  46    :  
  47    :  struct FilePathLess {
  48  E :    bool operator()(const std::wstring& lhs, const std::wstring& rhs) const {
  49  E :      return base::FilePath::CompareLessIgnoreCase(lhs, rhs);
  50  E :    }
  51    :  };
  52    :  
  53    :  class DiaUtilTest : public testing::PELibUnitTest {
  54    :  };
  55    :  
  56    :  bool PathsAreEquivalent(const base::FilePath::StringType& path1_val,
  57  E :                          const base::FilePath::StringType& path2_val) {
  58  E :    base::FilePath path1(path1_val);
  59  E :    base::FilePath path2(path2_val);
  60  E :    core::FilePathCompareResult result = core::CompareFilePaths(path1, path2);
  61  E :    return result == core::kEquivalentFilePaths;
  62  E :  }
  63    :  
  64  E :  MATCHER_P(IsSameFile, value, "") {
  65  E :    return PathsAreEquivalent(arg, value);
  66  E :  }
  67    :  
  68    :  bool StringVectorContainsPath(const StringVector& string_vector,
  69  E :                                const base::FilePath::StringType& path) {
  70  E :    for (const auto& iter : string_vector) {
  71  E :      if (PathsAreEquivalent(iter, path))
  72  E :        return true;
  73  i :    }
  74  i :    return false;
  75  E :  }
  76    :  
  77    :  }  // namespace
  78    :  
  79  E :  TEST_F(DiaUtilTest, CreateDiaSource) {
  80  E :    ScopedComPtr<IDiaDataSource> dia_source;
  81  E :    EXPECT_TRUE(CreateDiaSource(dia_source.Receive()));
  82  E :  }
  83    :  
  84  E :  TEST_F(DiaUtilTest, CreateDiaSesssionDll) {
  85  E :    ScopedComPtr<IDiaDataSource> dia_source;
  86  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
  87    :  
  88  E :    ScopedComPtr<IDiaSession> dia_session;
  89  E :    EXPECT_TRUE(CreateDiaSession(
  90    :        testing::GetExeRelativePath(testing::kTestDllName),
  91    :        dia_source.get(),
  92  E :        dia_session.Receive()));
  93  E :  }
  94    :  
  95  E :  TEST_F(DiaUtilTest, CreateDiaSesssionPdb) {
  96  E :    ScopedComPtr<IDiaDataSource> dia_source;
  97  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
  98    :  
  99  E :    ScopedComPtr<IDiaSession> dia_session;
 100  E :    EXPECT_TRUE(CreateDiaSession(
 101    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 102    :        dia_source.get(),
 103  E :        dia_session.Receive()));
 104  E :  }
 105    :  
 106  E :  TEST_F(DiaUtilTest, FindDiaTableByIid) {
 107  E :    ScopedComPtr<IDiaDataSource> dia_source;
 108  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
 109    :  
 110  E :    ScopedComPtr<IDiaSession> dia_session;
 111  E :    ASSERT_TRUE(CreateDiaSession(
 112    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 113    :        dia_source.get(),
 114  E :        dia_session.Receive()));
 115    :  
 116  E :    ScopedComPtr<IDiaEnumSectionContribs> section_contribs;
 117  E :    EXPECT_EQ(kSearchSucceeded,
 118    :              FindDiaTable(section_contribs.iid(),
 119    :                           dia_session.get(),
 120  E :                           reinterpret_cast<void**>(section_contribs.Receive())));
 121  E :  }
 122    :  
 123  E :  TEST_F(DiaUtilTest, FindDiaTableByType) {
 124  E :    ScopedComPtr<IDiaDataSource> dia_source;
 125  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
 126    :  
 127  E :    ScopedComPtr<IDiaSession> dia_session;
 128  E :    ASSERT_TRUE(CreateDiaSession(
 129    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 130    :        dia_source.get(),
 131  E :        dia_session.Receive()));
 132    :  
 133  E :    ScopedComPtr<IDiaEnumSectionContribs> section_contribs;
 134  E :    EXPECT_EQ(kSearchSucceeded,
 135  E :              FindDiaTable(dia_session.get(), section_contribs.Receive()));
 136  E :  }
 137    :  
 138  E :  TEST_F(DiaUtilTest, FindDiaDebugStream) {
 139  E :    ScopedComPtr<IDiaDataSource> dia_source;
 140  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
 141    :  
 142  E :    ScopedComPtr<IDiaSession> dia_session;
 143  E :    ASSERT_TRUE(CreateDiaSession(
 144    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 145    :        dia_source.get(),
 146  E :        dia_session.Receive()));
 147    :  
 148  E :    ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
 149    :  
 150  E :    EXPECT_EQ(kSearchFailed,
 151    :              FindDiaDebugStream(kNonsenseStreamName,
 152    :                                 dia_session.get(),
 153  E :                                 debug_stream.Receive()));
 154    :  
 155  E :    EXPECT_EQ(kSearchSucceeded,
 156    :              FindDiaDebugStream(kFixupDiaDebugStreamName,
 157    :                                 dia_session.get(),
 158  E :                                 debug_stream.Receive()));
 159  E :  }
 160    :  
 161  E :  TEST_F(DiaUtilTest, LoadDiaDebugStream) {
 162  E :    ScopedComPtr<IDiaDataSource> dia_source;
 163  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
 164    :  
 165  E :    ScopedComPtr<IDiaSession> dia_session;
 166  E :    ASSERT_TRUE(CreateDiaSession(
 167    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 168    :        dia_source.get(),
 169  E :        dia_session.Receive()));
 170    :  
 171  E :    ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
 172  E :    ASSERT_EQ(kSearchSucceeded,
 173    :              FindDiaDebugStream(kFixupDiaDebugStreamName,
 174    :                                 dia_session.get(),
 175  E :                                 debug_stream.Receive()));
 176    :  
 177  E :    std::vector<pdb::PdbFixup> fixups;
 178  E :    EXPECT_TRUE(LoadDiaDebugStream(debug_stream.get(), &fixups));
 179  E :    EXPECT_FALSE(fixups.empty());
 180  E :  }
 181    :  
 182  E :  TEST_F(DiaUtilTest, FindAndLoadDiaDebugStreamByName) {
 183  E :    ScopedComPtr<IDiaDataSource> dia_source;
 184  E :    ASSERT_TRUE(CreateDiaSource(dia_source.Receive()));
 185    :  
 186  E :    ScopedComPtr<IDiaSession> dia_session;
 187  E :    ASSERT_TRUE(CreateDiaSession(
 188    :        testing::GetExeRelativePath(testing::kTestDllPdbName),
 189    :        dia_source.get(),
 190  E :        dia_session.Receive()));
 191    :  
 192  E :    std::vector<pdb::PdbFixup> fixups;
 193    :  
 194  E :    EXPECT_EQ(kSearchFailed,
 195    :              FindAndLoadDiaDebugStreamByName(kNonsenseStreamName,
 196    :                                              dia_session.get(),
 197  E :                                              &fixups));
 198  E :    EXPECT_TRUE(fixups.empty());
 199    :  
 200  E :    EXPECT_EQ(kSearchSucceeded,
 201    :              FindAndLoadDiaDebugStreamByName(kFixupDiaDebugStreamName,
 202    :                                              dia_session.get(),
 203  E :                                              &fixups));
 204  E :    EXPECT_FALSE(fixups.empty());
 205  E :  }
 206    :  
 207    :  class DiaUtilVisitorTest : public DiaUtilTest {
 208    :   public:
 209  E :    void SetUp() override {
 210  E :      ASSERT_TRUE(CreateDiaSource(dia_source_.Receive()));
 211  E :      ASSERT_TRUE(CreateDiaSession(
 212    :          testing::GetExeRelativePath(testing::kTestDllName),
 213    :          dia_source_.get(),
 214    :          dia_session_.Receive()));
 215  E :      ASSERT_EQ(S_OK, dia_session_->get_globalScope(dia_globals_.Receive()));
 216  E :    }
 217    :  
 218  E :    bool OnFunction(StringVector* names, IDiaSymbol* function) {
 219  E :      EXPECT_TRUE(IsSymTag(function, SymTagFunction));
 220  E :      ScopedBstr name;
 221  E :      EXPECT_EQ(S_OK, function->get_name(name.Receive()));
 222  E :      names->push_back(common::ToString(name));
 223  E :      return true;
 224  E :    }
 225    :  
 226  E :    bool OnCompiland(StringVector* names, IDiaSymbol* compiland) {
 227  E :      EXPECT_TRUE(IsSymTag(compiland, SymTagCompiland));
 228  E :      ScopedBstr name;
 229  E :      EXPECT_EQ(S_OK, compiland->get_name(name.Receive()));
 230  E :      names->push_back(common::ToString(name));
 231  E :      return true;
 232  E :    }
 233    :  
 234    :    bool OnCompilandFind(const std::wstring& compiland_path,
 235    :                         ScopedComPtr<IDiaSymbol>* compiland_out,
 236  E :                         IDiaSymbol* compiland) {
 237  E :      EXPECT_TRUE(IsSymTag(compiland, SymTagCompiland));
 238  E :      ScopedBstr name;
 239  E :      EXPECT_EQ(S_OK, compiland->get_name(name.Receive()));
 240  E :      if (testing::Value(common::ToString(name), IsSameFile(compiland_path))) {
 241  E :        *compiland_out = compiland;
 242  E :        return false;
 243    :      }
 244  i :      return true;
 245  E :    }
 246    :  
 247    :    typedef std::set<std::pair<DWORD, DWORD>> LineSet;
 248    :    typedef std::map<std::wstring, LineSet, FilePathLess> LineMap;
 249  E :    bool OnLine(LineMap* line_map, IDiaLineNumber* line) {
 250  E :      DCHECK_NE(reinterpret_cast<LineMap*>(NULL), line_map);
 251  E :      DCHECK_NE(reinterpret_cast<IDiaLineNumber*>(NULL), line);
 252    :  
 253  E :      ScopedComPtr<IDiaSourceFile> source_file;
 254  E :      EXPECT_HRESULT_SUCCEEDED(line->get_sourceFile(source_file.Receive()));
 255    :  
 256  E :      ScopedBstr source_name;
 257  E :      EXPECT_HRESULT_SUCCEEDED(source_file->get_fileName(source_name.Receive()));
 258    :  
 259  E :      ScopedComPtr<IDiaSymbol> compiland;
 260  E :      EXPECT_HRESULT_SUCCEEDED(line->get_compiland(compiland.Receive()));
 261    :  
 262  E :      DWORD line_number = 0;
 263  E :      EXPECT_HRESULT_SUCCEEDED(line->get_lineNumber(&line_number));
 264  E :      DWORD line_number_end = 0;
 265  E :      EXPECT_HRESULT_SUCCEEDED(line->get_lineNumberEnd(&line_number_end));
 266    :  
 267    :      // This doesn't necessarily have to hold, but so far it seems to do so.
 268  E :      EXPECT_EQ(line_number, line_number_end);
 269    :  
 270  E :      (*line_map)[common::ToString(source_name)].insert(
 271    :          std::make_pair(line_number, line_number_end));
 272    :  
 273  E :      return true;
 274  E :    }
 275    :  
 276    :    ScopedComPtr<IDiaDataSource> dia_source_;
 277    :    ScopedComPtr<IDiaSession> dia_session_;
 278    :    ScopedComPtr<IDiaSymbol> dia_globals_;
 279    :  };
 280    :  
 281  E :  TEST_F(DiaUtilVisitorTest, ChildVisitorTest) {
 282  E :    ChildVisitor visitor(dia_globals_.get(), SymTagFunction);
 283    :  
 284  E :    StringVector function_names;
 285  E :    ASSERT_TRUE(visitor.VisitChildren(
 286    :        base::Bind(&DiaUtilVisitorTest::OnFunction,
 287    :                   base::Unretained(this),
 288  E :                   &function_names)));
 289    :  
 290    :    // Expect that we found a bunch of functions.
 291  E :    ASSERT_LT(1U, function_names.size());
 292    :    // One of them should be "DllMain".
 293  E :    ASSERT_THAT(function_names, testing::Contains(L"DllMain"));
 294  E :  }
 295    :  
 296  E :  TEST_F(DiaUtilVisitorTest, CompilandVisitorTest) {
 297  E :    CompilandVisitor visitor(dia_session_.get());
 298    :  
 299  E :    StringVector compiland_names;
 300  E :    ASSERT_TRUE(visitor.VisitAllCompilands(
 301    :        base::Bind(&DiaUtilVisitorTest::OnCompiland,
 302    :                   base::Unretained(this),
 303  E :                   &compiland_names)));
 304    :  
 305    :    // We expect to have seen some compiland_names.
 306  E :    ASSERT_LT(0U, compiland_names.size());
 307    :  
 308    :    // One of the compiland_names should be the test_dll.obj file.
 309  E :    std::string test_dll_path(kTestDllObjPath);
 310  E :    std::wstring test_dll_wide_path(test_dll_path.begin(), test_dll_path.end());
 311    :    base::FilePath test_dll_obj =
 312  E :        base::MakeAbsoluteFilePath(
 313    :            testing::GetOutputRelativePath(test_dll_wide_path.c_str()));
 314    :  
 315  E :    ASSERT_TRUE(StringVectorContainsPath(compiland_names, test_dll_obj.value()));
 316  E :  }
 317    :  
 318  E :  TEST_F(DiaUtilVisitorTest, LineVisitorTest) {
 319  E :    CompilandVisitor compiland_visitor(dia_session_.get());
 320    :  
 321    :    // Start by finding the test dll compiland.
 322  E :    ScopedComPtr<IDiaSymbol> compiland;
 323  E :    std::string test_dll_path(kTestDllObjPath);
 324  E :    std::wstring test_dll_wide_path(test_dll_path.begin(), test_dll_path.end());
 325    :    base::FilePath test_dll_obj =
 326  E :        base::MakeAbsoluteFilePath(
 327    :            testing::GetOutputRelativePath(test_dll_wide_path.c_str()));
 328  E :    ASSERT_FALSE(compiland_visitor.VisitAllCompilands(
 329    :        base::Bind(&DiaUtilVisitorTest::OnCompilandFind,
 330    :                   base::Unretained(this),
 331    :                   test_dll_obj.value(),
 332  E :                   &compiland)));
 333    :  
 334  E :    ASSERT_TRUE(compiland != NULL);
 335    :  
 336    :    // Now enumerate all line entries in that compiland.
 337  E :    LineVisitor line_visitor(dia_session_.get(), compiland.get());
 338    :  
 339  E :    LineMap line_map;
 340  E :    ASSERT_TRUE(line_visitor.VisitLines(
 341    :        base::Bind(&DiaUtilVisitorTest::OnLine,
 342    :                   base::Unretained(this),
 343  E :                   &line_map)));
 344    :  
 345    :    // We expect to have at least one file.
 346  E :    ASSERT_LE(1U, line_map.size());
 347    :  
 348    :    // Expect test_dll.cc to be in the line map, and to contain at least one line
 349    :    // worth of information. Search for equivalent paths because under some
 350    :    // mysterious poorly understood conditions the drive letter in the PDB may or
 351    :    // may not be capitalized.
 352    :    base::FilePath test_dll_cc =
 353  E :        testing::GetSrcRelativePath(L"syzygy\\pe\\test_dll.cc");
 354  E :    LineMap::const_iterator it = line_map.begin();
 355  E :    for (; it != line_map.end(); ++it) {
 356  E :      if (PathsAreEquivalent(it->first, test_dll_cc.value()))
 357  E :        break;
 358  i :    }
 359  E :    ASSERT_TRUE(it != line_map.end());
 360  E :    ASSERT_LT(1U, it->second.size());
 361  E :  }
 362    :  
 363    :  }  // namespace pe

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