Coverage for /Syzygy/pe/unittest_util.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.4%1501540.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/unittest_util.h"
  16    :  
  17    :  #include <imagehlp.h>
  18    :  #include <functional>
  19    :  
  20    :  #include "base/command_line.h"
  21    :  #include "base/logging.h"
  22    :  #include "base/path_service.h"
  23    :  #include "base/files/file_util.h"
  24    :  #include "base/process/launch.h"
  25    :  #include "base/strings/stringprintf.h"
  26    :  #include "base/strings/utf_string_conversions.h"
  27    :  #include "base/win/pe_image.h"
  28    :  #include "gmock/gmock.h"
  29    :  #include "gtest/gtest.h"
  30    :  #include "syzygy/block_graph/typed_block.h"
  31    :  #include "syzygy/block_graph/orderers/original_orderer.h"
  32    :  #include "syzygy/common/com_utils.h"
  33    :  #include "syzygy/core/unittest_util.h"
  34    :  #include "syzygy/pe/coff_decomposer.h"
  35    :  #include "syzygy/pe/coff_file.h"
  36    :  #include "syzygy/pe/coff_file_writer.h"
  37    :  #include "syzygy/pe/coff_image_layout_builder.h"
  38    :  #include "syzygy/pe/decomposer.h"
  39    :  #include "syzygy/pe/pe_data.h"
  40    :  
  41    :  namespace testing {
  42    :  
  43    :  namespace {
  44    :  
  45    :  using block_graph::BlockGraph;
  46    :  using block_graph::ConstTypedBlock;
  47    :  using block_graph::OrderedBlockGraph;
  48    :  using block_graph::TypedBlock;
  49    :  using core::RelativeAddress;
  50    :  using pe::CvInfoPdb70;
  51    :  
  52    :  typedef TypedBlock<CvInfoPdb70> CvInfoPdb;
  53    :  typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
  54    :  typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
  55    :  typedef TypedBlock<IMAGE_DEBUG_DIRECTORY> ImageDebugDirectory;
  56    :  
  57    :  bool EnumImportsProc(const base::win::PEImage &image,
  58    :                       const char* module,
  59    :                       DWORD ordinal,
  60    :                       const char* name,
  61    :                       DWORD hint,
  62    :                       IMAGE_THUNK_DATA* iat,
  63  E :                       void* cookie) {
  64  E :    DCHECK(module != NULL);
  65  E :    DCHECK(iat != NULL);
  66  E :    DCHECK(cookie != NULL);
  67    :  
  68    :    std::set<std::string>* export_dll_imports =
  69  E :        reinterpret_cast<std::set<std::string>*>(cookie);
  70    :  
  71  E :    if (strcmp(module, "export_dll.dll") == 0) {
  72  E :      if (name != NULL) {
  73  E :        EXPECT_TRUE(export_dll_imports->insert(name).second);
  74  E :      } else {
  75  E :        std::string ordinal_name(base::StringPrintf("#%d", ordinal));
  76  E :        EXPECT_TRUE(export_dll_imports->insert(ordinal_name).second);
  77  E :      }
  78    :    }
  79    :  
  80  E :    return true;
  81  E :  }
  82    :  
  83  E :  void CheckLoadedDllHasSortedSafeSehTable(HMODULE module) {
  84    :    // Verify that the Safe SEH Table is sorted.
  85    :    // http://code.google.com/p/sawbuck/issues/detail?id=42
  86  E :    ASSERT_TRUE(module != NULL);
  87  E :    base::win::PEImage image(module);
  88    :  
  89    :    // Locate the load config directory.
  90    :    PIMAGE_LOAD_CONFIG_DIRECTORY load_config_directory =
  91    :        reinterpret_cast<PIMAGE_LOAD_CONFIG_DIRECTORY>(
  92  E :            image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG));
  93  E :    ASSERT_TRUE(load_config_directory != NULL);
  94    :  
  95    :    // Find the bounds of the Safe SEH Table.
  96    :    DWORD* seh_table_begin =
  97  E :        reinterpret_cast<DWORD*>(load_config_directory->SEHandlerTable);
  98  E :    size_t seh_table_size = load_config_directory->SEHandlerCount;
  99  E :    DWORD* seh_table_end = seh_table_begin + seh_table_size;
 100    :  
 101    :    // Unfortunately, std::is_sorted is an extension pre-c++0x. An equivalent
 102    :    // test is to see if there are any adjacent elements such that the first
 103    :    // is greater than its successor. So, let's look for the first element for
 104    :    // which this is true, and if we get to the end, then there were no such
 105    :    // elements.
 106    :    DWORD* out_of_order_iter = std::adjacent_find(seh_table_begin,
 107    :                                                  seh_table_end,
 108  E :                                                  std::greater<DWORD>());
 109  E :    ASSERT_TRUE(out_of_order_iter == seh_table_end)
 110  E :        << "The Safe SEH Table must be sorted.";
 111  E :  }
 112    :  
 113  E :  void CheckLoadedTestDll(HMODULE module) {
 114    :    // Validate that the DLL is properly constructed.
 115  E :    CheckLoadedDllHasSortedSafeSehTable(module);
 116    :  
 117    :    // Load the exported TestExport function and invoke it.
 118    :    typedef DWORD (WINAPI* TestExportFunc)(size_t buf_len, char* buf);
 119    :    TestExportFunc test_func = reinterpret_cast<TestExportFunc>(
 120  E :        ::GetProcAddress(module, "TestExport"));
 121  E :    ASSERT_TRUE(test_func != NULL);
 122    :  
 123  E :    char buffer[1024] = { 0 };
 124  E :    EXPECT_EQ(0, test_func(arraysize(buffer), buffer));
 125  E :    EXPECT_STREQ("The quick brown fox jumped over the lazy dog", buffer);
 126    :  
 127    :    // Load the exported TestUnusedFunc function and invoke it.
 128    :    typedef void (CALLBACK* TestUnusedFuncs)(HWND, HINSTANCE, LPSTR, int);
 129    :    TestUnusedFuncs test_func2 = reinterpret_cast<TestUnusedFuncs>(
 130  E :        ::GetProcAddress(module, "TestUnusedFuncs"));
 131  E :    ASSERT_TRUE(test_func2 != NULL);
 132  E :    test_func2(0, 0, 0, 0);
 133    :  
 134    :    // Check the image file for sanity.
 135  E :    base::win::PEImage image(module);
 136  E :    ASSERT_TRUE(image.VerifyMagic());
 137    :  
 138  E :    std::set<std::string> export_dll_imports;
 139    :    // Verify all the imports from export_dll.
 140  E :    ASSERT_TRUE(image.EnumAllImports(EnumImportsProc, &export_dll_imports));
 141    :  
 142  E :    std::set<std::string> expected_imports;
 143  E :    expected_imports.insert("kExportedData");
 144  E :    expected_imports.insert("function1");
 145  E :    expected_imports.insert("#7");
 146  E :    expected_imports.insert("function3");
 147  E :    EXPECT_THAT(expected_imports, testing::ContainerEq(export_dll_imports));
 148  E :  }
 149    :  
 150    :  }  // namespace
 151    :  
 152    :  const wchar_t testing::kTestDllName[] = L"test_dll.dll";
 153    :  const wchar_t testing::kTestDllPdbName[] = L"test_dll.dll.pdb";
 154    :  
 155    :  const wchar_t testing::kTestDllName64[] = L"test_dll_x64.dll";
 156    :  const wchar_t testing::kTestDllPdbName64[] = L"test_dll_x64.dll.pdb";
 157    :  
 158    :  const wchar_t testing::kIntegrationTestsDllName[] =
 159    :      L"integration_tests_dll.dll";
 160    :  const wchar_t testing::kIntegrationTestsDllPdbName[] =
 161    :      L"integration_tests_dll.dll.pdb";
 162    :  
 163    :  const wchar_t kNoExportsDllName[] = L"no_exports_dll.dll";
 164    :  const wchar_t kNoExportsDllPdbName[] = L"no_exports_dll.dll.pdb";
 165    :  
 166    :  const wchar_t testing::kTestDllCoffObjName[] = L"test_dll.coff_obj";
 167    :  const wchar_t testing::kTestDllLtcgObjName[] = L"test_dll.ltcg_obj";
 168    :  const wchar_t testing::kTestDllCoffObjPdbName[] = L"test_dll.coff_obj.pdb";
 169    :  const wchar_t testing::kTestDllLtcgObjPdbName[] = L"test_dll.ltcg_obj.pdb";
 170    :  
 171    :  const wchar_t testing::kCodeView2Name[] =
 172    :      L"syzygy\\pe\\test_data\\codeview2.obj";
 173    :  const wchar_t testing::kEmptyStringTableCoffName[] =
 174    :      L"syzygy\\pe\\test_data\\empty_string_table.obj";
 175    :  
 176    :  const wchar_t kAsanInstrumentedTestDllName[] =
 177    :      L"asan_instrumented_test_dll.dll";
 178    :  const wchar_t kAsanInstrumentedTestDllPdbName[] =
 179    :      L"asan_instrumented_test_dll.dll.pdb";
 180    :  const wchar_t kBBEntryInstrumentedTestDllName[] =
 181    :      L"basic_block_entry_instrumented_test_dll.dll";
 182    :  const wchar_t kBBEntryInstrumentedTestDllPdbName[] =
 183    :      L"basic_block_entry_instrumented_test_dll.dll.pdb";
 184    :  const wchar_t kCallTraceInstrumentedTestDllName[] =
 185    :      L"call_trace_instrumented_test_dll.dll";
 186    :  const wchar_t kCallTraceInstrumentedTestDllPdbName[] =
 187    :      L"call_trace_instrumented_test_dll.dll.pdb";
 188    :  const wchar_t kCoverageInstrumentedTestDllName[] =
 189    :      L"coverage_instrumented_test_dll.dll";
 190    :  const wchar_t kCoverageInstrumentedTestDllPdbName[] =
 191    :      L"coverage_instrumented_test_dll.dll.pdb";
 192    :  const wchar_t kProfileInstrumentedTestDllName[] =
 193    :      L"profile_instrumented_test_dll.dll";
 194    :  const wchar_t kProfileInstrumentedTestDllPdbName[] =
 195    :      L"profile_instrumented_test_dll.dll.pdb";
 196    :  const wchar_t kRandomizedTestDllName[] = L"randomized_test_dll.dll";
 197    :  const wchar_t kRandomizedTestDllPdbName[] = L"randomized_test_dll.dll.pdb";
 198    :  const wchar_t kSignedTestDllName[] = L"signed_test_dll.dll";
 199    :  
 200    :  const wchar_t* kBBEntryTraceFiles[4] = {
 201    :      L"basic_block_entry_traces\\trace-1.bin",
 202    :      L"basic_block_entry_traces\\trace-2.bin",
 203    :      L"basic_block_entry_traces\\trace-3.bin",
 204    :      L"basic_block_entry_traces\\trace-4.bin",
 205    :  };
 206    :  
 207    :  const wchar_t* kBranchTraceFiles[4] = {
 208    :      L"branch_traces\\trace-1.bin",
 209    :      L"branch_traces\\trace-2.bin",
 210    :      L"branch_traces\\trace-3.bin",
 211    :      L"branch_traces\\trace-4.bin",
 212    :  };
 213    :  
 214    :  const wchar_t* kCallTraceTraceFiles[4] = {
 215    :      L"call_trace_traces\\trace-1.bin",
 216    :      L"call_trace_traces\\trace-2.bin",
 217    :      L"call_trace_traces\\trace-3.bin",
 218    :      L"call_trace_traces\\trace-4.bin",
 219    :  };
 220    :  
 221    :  const wchar_t* kCoverageTraceFiles[4] = {
 222    :      L"coverage_traces\\trace-1.bin",
 223    :      L"coverage_traces\\trace-2.bin",
 224    :      L"coverage_traces\\trace-3.bin",
 225    :      L"coverage_traces\\trace-4.bin",
 226    :  };
 227    :  
 228    :  const wchar_t kMemProfTraceFile[] = L"memprof_traces\\trace-1.bin";
 229    :  
 230    :  const wchar_t* kProfileTraceFiles[4] = {
 231    :      L"profile_traces\\trace-1.bin",
 232    :      L"profile_traces\\trace-2.bin",
 233    :      L"profile_traces\\trace-3.bin",
 234    :      L"profile_traces\\trace-4.bin",
 235    :  };
 236    :  
 237  E :  ScopedHMODULE::ScopedHMODULE() : value_(0) {
 238  E :  }
 239    :  
 240    :  ScopedHMODULE::ScopedHMODULE(HMODULE v) : value_(v) {
 241    :  }
 242    :  
 243  E :  void ScopedHMODULE::Reset(HMODULE value) {
 244  E :    if (value_ != value) {
 245  E :      Release();
 246  E :      value_ = value;
 247    :    }
 248  E :  }
 249    :  
 250  E :  void ScopedHMODULE::Release() {
 251  E :    if (value_) {
 252  E :      ::FreeLibrary(value_);
 253  E :      value_ = 0;
 254    :    }
 255  E :  }
 256    :  
 257  E :  ScopedHMODULE::~ScopedHMODULE() {
 258  E :    Release();
 259  E :  }
 260    :  
 261  E :  void TwiddlePdbGuidAndPath(BlockGraph::Block* dos_header_block) {
 262  E :    ASSERT_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
 263    :  
 264  E :    DosHeader dos_header;
 265  E :    ASSERT_TRUE(dos_header.Init(0, dos_header_block));
 266    :  
 267  E :    NtHeaders nt_headers;
 268  E :    ASSERT_TRUE(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
 269    :  
 270    :    const IMAGE_DATA_DIRECTORY& debug_dir_info =
 271  E :      nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
 272  E :    ImageDebugDirectory debug_dir;
 273    :    ASSERT_TRUE(nt_headers.Dereference(debug_dir_info.VirtualAddress,
 274  E :                                       &debug_dir));
 275    :  
 276    :    // Find the codeview debug directory entry.
 277  E :    int32 index = -1;
 278  E :    for (size_t i = 0; i < debug_dir.ElementCount(); ++i) {
 279  E :      if (debug_dir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
 280  E :        index = i;
 281  E :        break;
 282    :      }
 283  i :    }
 284  E :    ASSERT_NE(-1, index);
 285    :  
 286  E :    CvInfoPdb cv_info_pdb;
 287    :    ASSERT_TRUE(debug_dir.Dereference(debug_dir[index].PointerToRawData,
 288  E :                                      &cv_info_pdb));
 289    :  
 290    :    // Modify the GUID.
 291  E :    cv_info_pdb->signature.Data1 ^= 0xFFFFFFFF;
 292    :  
 293    :    // Write a nonsense name using a simple encoding.
 294  E :    size_t block_size = cv_info_pdb.block()->size();
 295  E :    size_t string_start = cv_info_pdb.OffsetOf(cv_info_pdb->pdb_file_name);
 296  E :    ASSERT_LT(string_start, block_size);
 297  E :    size_t string_len = block_size - string_start;
 298  E :    for (size_t i = 0; i < string_len && cv_info_pdb->pdb_file_name[i] != 0;
 299  E :         ++i) {
 300  E :      char& c = cv_info_pdb->pdb_file_name[i];
 301  E :      if (c >= 'a' && c <= 'z') {
 302  E :        c = 'z' - (c - 'a');
 303  E :      } else if (c >= 'A' && c <= 'Z') {
 304  E :        c = 'Z' - (c - 'A');
 305  E :      } else if (c >= '0' && c <= '9') {
 306  i :        c = '9' - (c - '0');
 307    :      }
 308  E :    }
 309  E :  }
 310    :  
 311    :  void PELibUnitTest::LoadTestDll(const base::FilePath& path,
 312  E :                                  ScopedHMODULE* module) {
 313  E :    DCHECK(module != NULL);
 314    :  
 315  E :    LOADED_IMAGE loaded_image = {};
 316    :    BOOL success = ::MapAndLoad(base::WideToUTF8(path.value()).c_str(),
 317    :                                NULL,
 318    :                                &loaded_image,
 319    :                                FALSE,
 320  E :                                TRUE);
 321  E :    EXPECT_EQ(ERROR_SUCCESS, ::GetLastError());
 322  E :    ASSERT_TRUE(success);
 323  E :    EXPECT_TRUE(::UnMapAndLoad(&loaded_image));
 324    :  
 325  E :    module->Reset(::LoadLibrary(path.value().c_str()));
 326  E :    if (*module == NULL) {
 327  i :      DWORD error = ::GetLastError();
 328  i :      LOG(ERROR) << "LoadLibrary failed: " << common::LogWe(error);
 329    :    }
 330  E :    ASSERT_TRUE(module != NULL);
 331  E :  }
 332    :  
 333    :  void PELibUnitTest::DecomposeTestDll(pe::PEFile* pe_file,
 334  E :                                       pe::ImageLayout* image_layout) {
 335  E :    ASSERT_TRUE(pe_file != NULL);
 336  E :    ASSERT_TRUE(image_layout != NULL);
 337    :  
 338  E :    base::FilePath test_dll = GetOutputRelativePath(kTestDllName);
 339  E :    ASSERT_TRUE(pe_file->Init(test_dll));
 340    :  
 341  E :    pe::Decomposer decomposer(*pe_file);
 342  E :    ASSERT_TRUE(decomposer.Decompose(image_layout));
 343  E :  }
 344    :  
 345  E :  void PELibUnitTest::CheckTestDll(const base::FilePath& path) {
 346  E :    ScopedHMODULE module;
 347  E :    LoadTestDll(path, &module);
 348  E :    CheckLoadedTestDll(module);
 349  E :  }
 350    :  
 351  E :  void CoffUnitTest::SetUp() {
 352  E :    testing::PELibUnitTest::SetUp();
 353    :  
 354    :    test_dll_obj_path_ =
 355  E :        testing::GetExeTestDataRelativePath(testing::kTestDllCoffObjName);
 356  E :    ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_path_));
 357  E :    new_test_dll_obj_path_ = temp_dir_path_.Append(L"test_dll.obj");
 358  E :  }
 359    :  
 360  E :  void CoffUnitTest::DecomposeOriginal() {
 361  E :    ASSERT_TRUE(image_file_.Init(test_dll_obj_path_));
 362  E :    pe::CoffDecomposer decomposer(image_file_);
 363  E :    ASSERT_TRUE(decomposer.Decompose(&image_layout_));
 364    :  
 365  E :    headers_block_ = image_layout_.blocks.GetBlockByAddress(RelativeAddress(0));
 366  E :    ASSERT_TRUE(headers_block_ != NULL);
 367  E :  }
 368    :  
 369    :  void CoffUnitTest::LayoutAndWriteNew(
 370  E :    block_graph::BlockGraphOrdererInterface* orderer) {
 371  E :    ASSERT_TRUE(orderer != NULL);
 372    :  
 373    :    // Cast headers block.
 374  E :    ConstTypedBlock<IMAGE_FILE_HEADER> file_header;
 375  E :    ASSERT_TRUE(file_header.Init(0, headers_block_));
 376    :  
 377    :    // Reorder using the specified ordering.
 378  E :    OrderedBlockGraph ordered_graph(&block_graph_);
 379  E :    ASSERT_TRUE(orderer->OrderBlockGraph(&ordered_graph, headers_block_));
 380    :  
 381    :    // Wipe references from headers, so we can remove relocation blocks
 382    :    // during laying out.
 383  E :    ASSERT_TRUE(headers_block_->RemoveAllReferences());
 384    :  
 385    :    // Lay out new image.
 386  E :    pe::ImageLayout new_image_layout(&block_graph_);
 387  E :    pe::CoffImageLayoutBuilder layout_builder(&new_image_layout);
 388  E :    ASSERT_TRUE(layout_builder.LayoutImage(ordered_graph));
 389    :  
 390    :    // Write temporary image file.
 391  E :    pe::CoffFileWriter writer(&new_image_layout);
 392  E :    ASSERT_TRUE(writer.WriteImage(new_test_dll_obj_path_));
 393  E :  }
 394    :  
 395  E :  void CoffUnitTest::TestRoundTrip() {
 396    :    // Rewrite file and parse new symbol table.
 397  E :    block_graph::orderers::OriginalOrderer orig_orderer;
 398  E :    ASSERT_NO_FATAL_FAILURE(LayoutAndWriteNew(&orig_orderer));
 399  E :    pe::CoffFile image_file;
 400  E :    ASSERT_TRUE(image_file.Init(new_test_dll_obj_path_));
 401  E :  }
 402    :  
 403    :  }  // namespace testing

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