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

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

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