Coverage for /Syzygy/grinder/grinders/mem_replay_grinder_unittest.cc

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

Line-by-line coverage:

   1    :  // Copyright 2015 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/grinder/grinders/mem_replay_grinder.h"
  16    :  
  17    :  #include "base/command_line.h"
  18    :  #include "base/files/file.h"
  19    :  #include "base/files/scoped_temp_dir.h"
  20    :  #include "base/strings/string_util.h"
  21    :  #include "gtest/gtest.h"
  22    :  #include "syzygy/bard/events/heap_alloc_event.h"
  23    :  #include "syzygy/bard/events/linked_event.h"
  24    :  #include "syzygy/core/unittest_util.h"
  25    :  #include "syzygy/pe/unittest_util.h"
  26    :  
  27    :  namespace grinder {
  28    :  namespace grinders {
  29    :  
  30    :  namespace {
  31    :  
  32    :  const char kHeapAlloc[] = "asan_HeapAlloc";
  33    :  
  34    :  class TestMemReplayGrinder : public MemReplayGrinder {
  35    :   public:
  36    :    // Types.
  37    :    using ProcessData = MemReplayGrinder::ProcessData;
  38    :  
  39    :    // Member variables.
  40    :    using MemReplayGrinder::function_enum_map_;
  41    :    using MemReplayGrinder::missing_events_;
  42    :    using MemReplayGrinder::parse_error_;
  43    :    using MemReplayGrinder::process_data_map_;
  44    :  
  45    :    // Member functions.
  46    :    using MemReplayGrinder::FindOrCreateProcessData;
  47    :    using MemReplayGrinder::FindOrCreateThreadData;
  48    :  
  49    :    // Creates and dispatches a TraceFunctionNameTableEntry event.
  50    :    void PlayFunctionNameTableEntry(uint32_t process_id,
  51    :                                    uint32_t function_id,
  52  E :                                    const base::StringPiece& function_name) {
  53    :      size_t buffer_size =
  54  E :          offsetof(TraceFunctionNameTableEntry, name) + function_name.size() + 1;
  55  E :      std::vector<uint8_t> buffer(buffer_size, 0);
  56  E :      auto data = reinterpret_cast<TraceFunctionNameTableEntry*>(buffer.data());
  57  E :      data->function_id = function_id;
  58  E :      data->name_length = function_name.size();
  59    :      // The name doesn't need to be null terminated as the length is explicitly
  60    :      // encoded. So using strncpy is perfectly safe.
  61  E :      ::strncpy(data->name, function_name.data(), function_name.size());
  62  E :      OnFunctionNameTableEntry(base::Time::Now(), process_id, data);
  63  E :    }
  64    :  
  65    :    // Creates and dispatches a heap alloc function call.
  66    :    void PlayHeapAllocCall(uint32_t process_id,
  67    :                           uint32_t thread_id,
  68    :                           uint64_t timestamp,
  69    :                           uint32_t function_id,
  70    :                           uint32_t stack_trace_id,
  71    :                           HANDLE handle,
  72    :                           DWORD flags,
  73    :                           SIZE_T bytes,
  74  E :                           LPVOID ret) {
  75    :      size_t arg_data_size = 5 * sizeof(uint32_t) + sizeof(handle) +
  76  E :                             sizeof(flags) + sizeof(bytes) + sizeof(ret);
  77    :      size_t buffer_size =
  78  E :          offsetof(TraceDetailedFunctionCall, argument_data) + arg_data_size;
  79  E :      std::vector<uint8_t> buffer(buffer_size, 0);
  80  E :      auto data = reinterpret_cast<TraceDetailedFunctionCall*>(buffer.data());
  81  E :      data->timestamp = timestamp;
  82  E :      data->function_id = function_id;
  83  E :      data->stack_trace_id = stack_trace_id;
  84  E :      data->argument_data_size = arg_data_size;
  85    :  
  86    :      // Output the argument data.
  87  E :      uint8_t* cursor = data->argument_data;
  88  E :      *reinterpret_cast<uint32_t*>(cursor) = 4;
  89  E :      cursor += sizeof(uint32_t);
  90  E :      *reinterpret_cast<uint32_t*>(cursor) = sizeof(handle);
  91  E :      cursor += sizeof(uint32_t);
  92  E :      *reinterpret_cast<uint32_t*>(cursor) = sizeof(flags);
  93  E :      cursor += sizeof(uint32_t);
  94  E :      *reinterpret_cast<uint32_t*>(cursor) = sizeof(bytes);
  95  E :      cursor += sizeof(uint32_t);
  96  E :      *reinterpret_cast<uint32_t*>(cursor) = sizeof(ret);
  97  E :      cursor += sizeof(uint32_t);
  98  E :      *reinterpret_cast<HANDLE*>(cursor) = handle;
  99  E :      cursor += sizeof(HANDLE);
 100  E :      *reinterpret_cast<DWORD*>(cursor) = flags;
 101  E :      cursor += sizeof(DWORD);
 102  E :      *reinterpret_cast<SIZE_T*>(cursor) = bytes;
 103  E :      cursor += sizeof(SIZE_T);
 104  E :      *reinterpret_cast<LPVOID*>(cursor) = ret;
 105  E :      cursor += sizeof(LPVOID);
 106  E :      DCHECK_EQ(static_cast<ptrdiff_t>(arg_data_size),
 107    :                cursor - data->argument_data);
 108    :  
 109  E :      OnDetailedFunctionCall(base::Time::Now(), process_id, thread_id, data);
 110  E :    }
 111    :  };
 112    :  
 113    :  class MemReplayGrinderTest : public testing::Test {
 114    :   public:
 115  E :    MemReplayGrinderTest() : cmd_line_(base::FilePath(L"grinder.exe")) {}
 116    :  
 117    :    base::CommandLine cmd_line_;
 118    :  };
 119    :  
 120    :  }  // namespace
 121    :  
 122  E :  TEST_F(MemReplayGrinderTest, ParseCommandLine) {
 123  E :    TestMemReplayGrinder grinder;
 124  E :    EXPECT_TRUE(grinder.function_enum_map_.empty());
 125  E :    EXPECT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 126  E :    EXPECT_FALSE(grinder.function_enum_map_.empty());
 127  E :  }
 128    :  
 129  E :  TEST_F(MemReplayGrinderTest, RecognizedFunctionName) {
 130  E :    TestMemReplayGrinder grinder;
 131  E :    ASSERT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 132  E :    grinder.PlayFunctionNameTableEntry(1, 1, kHeapAlloc);
 133  E :    EXPECT_EQ(1u, grinder.process_data_map_.size());
 134    :  
 135  E :    auto proc_data = grinder.FindOrCreateProcessData(1);
 136  E :    EXPECT_EQ(1u, proc_data->function_id_map.size());
 137  E :    auto it = proc_data->function_id_map.begin();
 138  E :    EXPECT_EQ(1u, it->first);
 139  E :    EXPECT_EQ(bard::EventInterface::EventType::kHeapAllocEvent, it->second);
 140  E :  }
 141    :  
 142  E :  TEST_F(MemReplayGrinderTest, UnrecognizedFunctionName) {
 143    :    static const char kDummyFunction[] = "DummyFunction";
 144  E :    TestMemReplayGrinder grinder;
 145  E :    ASSERT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 146  E :    grinder.PlayFunctionNameTableEntry(1, 1, kDummyFunction);
 147  E :    EXPECT_TRUE(grinder.process_data_map_.empty());
 148  E :    EXPECT_EQ(1u, grinder.missing_events_.size());
 149  E :    EXPECT_STREQ(kDummyFunction, grinder.missing_events_.begin()->c_str());
 150  E :  }
 151    :  
 152  E :  TEST_F(MemReplayGrinderTest, NameBeforeCall) {
 153  E :    TestMemReplayGrinder grinder;
 154  E :    ASSERT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 155    :  
 156  E :    const HANDLE kHandle = reinterpret_cast<HANDLE>(0xDEADBEEF);
 157  E :    const DWORD kFlags = 0xFF;
 158  E :    const SIZE_T kBytes = 247;
 159  E :    const LPVOID kRet = reinterpret_cast<LPVOID>(0xBAADF00D);
 160    :  
 161  E :    grinder.PlayFunctionNameTableEntry(1, 1, kHeapAlloc);
 162  E :    EXPECT_EQ(1u, grinder.process_data_map_.size());
 163  E :    auto proc_data = grinder.FindOrCreateProcessData(1);
 164  E :    EXPECT_EQ(1u, proc_data->function_id_map.size());
 165  E :    EXPECT_TRUE(proc_data->pending_function_ids.empty());
 166  E :    EXPECT_TRUE(proc_data->pending_calls.empty());
 167  E :    EXPECT_TRUE(proc_data->thread_data_map.empty());
 168    :  
 169    :    // The function call is processed immediately upon being seen.
 170  E :    grinder.PlayHeapAllocCall(1, 1, 0, 1, 0, kHandle, kFlags, kBytes, kRet);
 171  E :    EXPECT_EQ(1u, proc_data->function_id_map.size());
 172  E :    EXPECT_TRUE(proc_data->pending_function_ids.empty());
 173  E :    EXPECT_TRUE(proc_data->pending_calls.empty());
 174  E :    EXPECT_EQ(1u, proc_data->thread_data_map.size());
 175  E :    auto thread_data = grinder.FindOrCreateThreadData(proc_data, 1);
 176  E :    EXPECT_EQ(1u, thread_data->plot_line->size());
 177  E :    auto evt = (*thread_data->plot_line)[0];
 178  E :    EXPECT_EQ(bard::EventInterface::EventType::kHeapAllocEvent, evt->type());
 179  E :    auto ha = reinterpret_cast<const bard::events::HeapAllocEvent*>(&(*evt));
 180  E :    EXPECT_EQ(kHandle, ha->trace_heap());
 181  E :    EXPECT_EQ(kFlags, ha->flags());
 182  E :    EXPECT_EQ(kBytes, ha->bytes());
 183  E :    EXPECT_EQ(kRet, ha->trace_alloc());
 184  E :  }
 185    :  
 186  E :  TEST_F(MemReplayGrinderTest, CallBeforeName) {
 187  E :    TestMemReplayGrinder grinder;
 188  E :    ASSERT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 189    :  
 190  E :    const HANDLE kHandle = reinterpret_cast<HANDLE>(0xDEADBEEF);
 191  E :    const DWORD kFlags = 0xFF;
 192  E :    const SIZE_T kBytes = 247;
 193  E :    const LPVOID kRet = reinterpret_cast<LPVOID>(0xBAADF00D);
 194    :  
 195    :    // The function call is seen before the corresponding function name is
 196    :    // defined so no parsing can happen. In this case the call should be
 197    :    // placed to the pending list.
 198  E :    grinder.PlayHeapAllocCall(1, 1, 0, 1, 0, kHandle, kFlags, kBytes, kRet);
 199  E :    EXPECT_EQ(1u, grinder.process_data_map_.size());
 200  E :    auto proc_data = grinder.FindOrCreateProcessData(1);
 201  E :    EXPECT_TRUE(proc_data->function_id_map.empty());
 202  E :    EXPECT_EQ(1u, proc_data->pending_function_ids.size());
 203  E :    EXPECT_EQ(1u, proc_data->pending_calls.size());
 204  E :    EXPECT_TRUE(proc_data->thread_data_map.empty());
 205    :  
 206    :    // And processed once the name is defined.
 207  E :    grinder.PlayFunctionNameTableEntry(1, 1, kHeapAlloc);
 208  E :    EXPECT_EQ(1u, proc_data->function_id_map.size());
 209  E :    EXPECT_TRUE(proc_data->pending_function_ids.empty());
 210  E :    EXPECT_TRUE(proc_data->pending_calls.empty());
 211  E :    EXPECT_EQ(1u, proc_data->thread_data_map.size());
 212  E :    auto thread_data = grinder.FindOrCreateThreadData(proc_data, 1);
 213  E :    EXPECT_EQ(1u, thread_data->plot_line->size());
 214  E :    auto evt = (*thread_data->plot_line)[0];
 215  E :    EXPECT_EQ(bard::EventInterface::EventType::kHeapAllocEvent, evt->type());
 216  E :    auto ha = reinterpret_cast<const bard::events::HeapAllocEvent*>(&(*evt));
 217  E :    EXPECT_EQ(kHandle, ha->trace_heap());
 218  E :    EXPECT_EQ(kFlags, ha->flags());
 219  E :    EXPECT_EQ(kBytes, ha->bytes());
 220  E :    EXPECT_EQ(kRet, ha->trace_alloc());
 221  E :  }
 222    :  
 223  E :  TEST_F(MemReplayGrinderTest, GrindHarnessTrace) {
 224  E :    TestMemReplayGrinder grinder;
 225  E :    EXPECT_TRUE(grinder.ParseCommandLine(&cmd_line_));
 226    :  
 227    :    // We don't control what happens on the main entry thread, so we specifically
 228    :    // filter out events there. This ensures that the analysis of the other two
 229    :    // threads in the harness remains distinct.
 230    :  
 231  E :    trace::parser::Parser parser;
 232  E :    ASSERT_TRUE(parser.Init(&grinder));
 233    :    base::FilePath trace_file =
 234  E :        testing::GetExeTestDataRelativePath(testing::kMemProfTraceFile);
 235  E :    ASSERT_TRUE(parser.OpenTraceFile(trace_file));
 236  E :    grinder.SetParser(&parser);
 237  E :    EXPECT_TRUE(parser.Consume());
 238  E :    EXPECT_FALSE(grinder.parse_error_);
 239    :  
 240    :    // Grind the data and expect there to be a single process entry that is
 241    :    // fully parsed.
 242  E :    EXPECT_TRUE(grinder.Grind());
 243  E :    EXPECT_EQ(1u, grinder.process_data_map_.size());
 244  E :    const auto& proc = grinder.process_data_map_.begin()->second;
 245  E :    EXPECT_TRUE(proc.pending_function_ids.empty());
 246  E :    EXPECT_TRUE(proc.story);
 247    :  
 248    :    // The story should consist of 3 plotlines, corresponding to the main thread
 249    :    // and the two worker threads.
 250  E :    EXPECT_EQ(3u, proc.story->plot_lines().size());
 251    :  
 252    :    // Find the plotline for thread 1 and thread 2 of the harness. The first has
 253    :    // 9 events, the second has 10.
 254  E :    bard::Story::PlotLine* pl1 = nullptr;
 255  E :    bard::Story::PlotLine* pl2 = nullptr;
 256  E :    for (size_t i = 0; i < proc.story->plot_lines().size(); ++i) {
 257  E :      if (pl1 == nullptr && proc.story->plot_lines()[i]->size() == 9)
 258  E :        pl1 = proc.story->plot_lines()[i];
 259  E :      else if (pl2 == nullptr && proc.story->plot_lines()[i]->size() == 10)
 260  E :        pl2 = proc.story->plot_lines()[i];
 261  E :    }
 262  E :    DCHECK(pl1 && pl2);
 263    :  
 264    :    // Validate the contents of plot line 1.
 265  E :    EXPECT_EQ((*pl1)[0]->type(), bard::EventInterface::kHeapCreateEvent);
 266  E :    EXPECT_EQ((*pl1)[1]->type(), bard::EventInterface::kHeapAllocEvent);
 267  E :    EXPECT_EQ((*pl1)[2]->type(), bard::EventInterface::kLinkedEvent);
 268  E :    EXPECT_EQ((*pl1)[3]->type(), bard::EventInterface::kLinkedEvent);
 269  E :    EXPECT_EQ((*pl1)[4]->type(), bard::EventInterface::kHeapAllocEvent);
 270  E :    EXPECT_EQ((*pl1)[5]->type(), bard::EventInterface::kLinkedEvent);
 271  E :    EXPECT_EQ((*pl1)[6]->type(), bard::EventInterface::kHeapSetInformationEvent);
 272  E :    EXPECT_EQ((*pl1)[7]->type(), bard::EventInterface::kHeapFreeEvent);
 273  E :    EXPECT_EQ((*pl1)[8]->type(), bard::EventInterface::kHeapDestroyEvent);
 274    :  
 275    :    // Validate the contents of plot line 2.
 276  E :    EXPECT_EQ((*pl2)[0]->type(), bard::EventInterface::kHeapCreateEvent);
 277  E :    EXPECT_EQ((*pl2)[1]->type(), bard::EventInterface::kHeapAllocEvent);
 278  E :    EXPECT_EQ((*pl2)[2]->type(), bard::EventInterface::kLinkedEvent);
 279  E :    EXPECT_EQ((*pl2)[3]->type(), bard::EventInterface::kLinkedEvent);
 280  E :    EXPECT_EQ((*pl2)[4]->type(), bard::EventInterface::kHeapReAllocEvent);
 281  E :    EXPECT_EQ((*pl2)[5]->type(), bard::EventInterface::kHeapFreeEvent);
 282  E :    EXPECT_EQ((*pl2)[6]->type(), bard::EventInterface::kHeapFreeEvent);
 283  E :    EXPECT_EQ((*pl2)[7]->type(), bard::EventInterface::kLinkedEvent);
 284  E :    EXPECT_EQ((*pl2)[8]->type(), bard::EventInterface::kHeapFreeEvent);
 285  E :    EXPECT_EQ((*pl2)[9]->type(), bard::EventInterface::kHeapDestroyEvent);
 286    :  
 287    :    // Validate the dependencies between the two plot lines.
 288    :  
 289    :    bard::events::LinkedEvent* pl12 =
 290  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl1)[2]);
 291  E :    EXPECT_EQ(pl12->event()->type(), bard::EventInterface::kHeapCreateEvent);
 292  E :    EXPECT_TRUE(pl12->deps().empty());
 293    :  
 294    :    bard::events::LinkedEvent* pl13 =
 295  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl1)[3]);
 296  E :    EXPECT_EQ(pl13->event()->type(), bard::EventInterface::kHeapAllocEvent);
 297  E :    EXPECT_TRUE(pl13->deps().empty());
 298    :  
 299    :    bard::events::LinkedEvent* pl15 =
 300  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl1)[5]);
 301  E :    EXPECT_EQ(pl15->event()->type(), bard::EventInterface::kHeapFreeEvent);
 302  E :    EXPECT_TRUE(pl15->deps().empty());
 303    :  
 304    :    bard::events::LinkedEvent* pl22 =
 305  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl2)[2]);
 306  E :    EXPECT_EQ(pl22->event()->type(), bard::EventInterface::kHeapAllocEvent);
 307  E :    EXPECT_EQ(1u, pl22->deps().size());
 308  E :    EXPECT_EQ((*pl1)[2], pl22->deps().front());
 309    :  
 310    :    bard::events::LinkedEvent* pl23 =
 311  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl2)[3]);
 312  E :    EXPECT_EQ(pl23->event()->type(), bard::EventInterface::kHeapSizeEvent);
 313  E :    EXPECT_EQ(1u, pl23->deps().size());
 314  E :    EXPECT_EQ((*pl1)[3], pl23->deps().front());
 315    :  
 316    :    bard::events::LinkedEvent* pl27 =
 317  E :        reinterpret_cast<bard::events::LinkedEvent*>((*pl2)[7]);
 318  E :    EXPECT_EQ(pl27->event()->type(), bard::EventInterface::kHeapDestroyEvent);
 319  E :    EXPECT_EQ(1u, pl27->deps().size());
 320  E :    EXPECT_EQ((*pl1)[5], pl27->deps().front());
 321    :  
 322    :    // Extra test: Ensure that serialization works for this more complicated
 323    :    // story.
 324  E :    testing::TestSerialization(*proc.story);
 325    :  
 326  E :    base::ScopedTempDir temp_dir;
 327  E :    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 328  E :    base::FilePath output_path = temp_dir.path().AppendASCII("output.bin");
 329  E :    base::ScopedFILE output_file(base::OpenFile(output_path, "wb"));
 330  E :    EXPECT_TRUE(grinder.OutputData(output_file.get()));
 331  E :    output_file.reset();
 332  E :  }
 333    :  
 334    :  }  // namespace grinders
 335    :  }  // namespace grinder

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