Coverage for /Syzygy/trace/parse/parse_engine_rpc_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
87.0%3484000.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/trace/parse/parse_engine_rpc.h"
  16    :  
  17    :  #include <windows.h>
  18    :  
  19    :  #include <list>
  20    :  #include <map>
  21    :  
  22    :  #include "base/environment.h"
  23    :  #include "base/file_util.h"
  24    :  #include "base/lazy_instance.h"
  25    :  #include "base/logging.h"
  26    :  #include "base/files/file_enumerator.h"
  27    :  #include "base/files/file_path.h"
  28    :  #include "base/memory/scoped_vector.h"
  29    :  #include "base/strings/stringprintf.h"
  30    :  #include "base/strings/utf_string_conversions.h"
  31    :  #include "base/threading/simple_thread.h"
  32    :  #include "base/win/event_trace_consumer.h"
  33    :  #include "base/win/event_trace_controller.h"
  34    :  #include "base/win/scoped_handle.h"
  35    :  #include "base/win/windows_version.h"
  36    :  #include "gmock/gmock.h"
  37    :  #include "gtest/gtest.h"
  38    :  #include "syzygy/pe/unittest_util.h"
  39    :  #include "syzygy/trace/common/unittest_util.h"
  40    :  #include "syzygy/trace/parse/parser.h"
  41    :  #include "syzygy/trace/service/process_info.h"
  42    :  
  43    :  namespace trace {
  44    :  namespace service {
  45    :  namespace {
  46    :  
  47    :  using ::trace::parser::Parser;
  48    :  using ::trace::parser::ParseEventHandlerImpl;
  49    :  
  50    :  static const uint32 kConstantInThisModule = 0;
  51    :  
  52    :  enum CallEntryType {
  53    :    kCallEntry,
  54    :    kCallExit,
  55    :  };
  56    :  
  57    :  struct Call {
  58    :    base::Time entry;
  59    :    size_t relative_order;
  60    :    DWORD thread_id;
  61    :    FuncAddr address;
  62    :    CallEntryType type;
  63    :  };
  64    :  
  65    :  struct ModuleEvent {
  66    :    base::Time entry;
  67    :    DWORD thread_id;
  68    :    TraceModuleData data;
  69    :    DWORD type;
  70    :  };
  71    :  
  72  E :  bool operator<(const Call& a, const Call& b) {
  73  E :    if (a.entry < b.entry)
  74  E :      return true;
  75  E :    if (a.entry > b.entry)
  76  E :      return false;
  77    :  
  78  E :    if (a.relative_order < b.relative_order)
  79  i :      return true;
  80  E :    if (a.relative_order > b.relative_order)
  81  E :      return false;
  82    :  
  83  i :    if (a.thread_id < b.thread_id)
  84  i :      return true;
  85  i :    if (a.thread_id > b.thread_id)
  86  i :      return false;
  87    :  
  88  i :    if (a.address < b.address)
  89  i :      return true;
  90  i :    if (a.address > b.address)
  91  i :      return false;
  92    :  
  93  i :    return a.type < b.type;
  94  E :  }
  95    :  
  96    :  typedef std::multiset<FuncAddr> CalledAddresses;
  97    :  typedef std::vector<Call> RawCalls;
  98    :  typedef RawCalls::iterator RawCallsIter;
  99    :  typedef std::multiset<Call> OrderedCalls;
 100    :  typedef OrderedCalls::iterator OrderedCallsIter;
 101    :  typedef std::list<ModuleEvent> ModuleEvents;
 102    :  
 103    :  class TestParseEventHandler : public ParseEventHandlerImpl {
 104    :   public:
 105  E :    TestParseEventHandler(): process_id_(::GetCurrentProcessId()), event_id_(0) {
 106  E :    }
 107    :  
 108  E :    ~TestParseEventHandler() {
 109  E :    }
 110    :  
 111    :    virtual void OnFunctionEntry(base::Time time,
 112    :                                 DWORD process_id,
 113    :                                 DWORD thread_id,
 114  i :                                 const TraceEnterExitEventData* data) {
 115  i :      entered_addresses_.insert(data->function);
 116  i :      Call call = { time, event_id_++, thread_id, data->function, kCallEntry };
 117  i :      raw_calls_.push_back(call);
 118  i :      ordered_calls_.insert(call);
 119  i :    }
 120    :  
 121    :    virtual void OnFunctionExit(base::Time time,
 122    :                                DWORD process_id,
 123    :                                DWORD thread_id,
 124  i :                                const TraceEnterExitEventData* data) {
 125  i :      exited_addresses_.insert(data->function);
 126  i :      Call call = { time, event_id_++, thread_id, data->function, kCallExit };
 127  i :      raw_calls_.push_back(call);
 128  i :      ordered_calls_.insert(call);
 129  i :    }
 130    :  
 131    :    virtual void OnBatchFunctionEntry(base::Time time,
 132    :                                      DWORD process_id,
 133    :                                      DWORD thread_id,
 134  E :                                      const TraceBatchEnterData* data) {
 135  E :      for (size_t i = 0; i < data->num_calls; ++i) {
 136  E :        entered_addresses_.insert(data->calls[i].function);
 137    :        Call call = { time, event_id_++, thread_id, data->calls[i].function,
 138  E :                      kCallEntry };
 139  E :        raw_calls_.push_back(call);
 140  E :        ordered_calls_.insert(call);
 141  E :      }
 142  E :    }
 143    :  
 144    :    virtual void OnProcessAttach(base::Time time,
 145    :                                 DWORD process_id,
 146    :                                 DWORD thread_id,
 147  E :                                 const TraceModuleData* data) {
 148  E :      ModuleEvent event = { time, thread_id, *data, DLL_PROCESS_ATTACH };
 149  E :      module_events_.push_back(event);
 150  E :    }
 151    :  
 152    :    virtual void OnProcessDetach(base::Time time,
 153    :                                 DWORD process_id,
 154    :                                 DWORD thread_id,
 155  i :                                 const TraceModuleData* data) {
 156  i :      ModuleEvent event = { time, thread_id, *data, DLL_PROCESS_DETACH };
 157  i :      module_events_.push_back(event);
 158  i :    }
 159    :  
 160    :    virtual void OnThreadAttach(base::Time time,
 161    :                                DWORD process_id,
 162    :                                DWORD thread_id,
 163  i :                                const TraceModuleData* data) {
 164  i :      ModuleEvent event = { time, thread_id, *data, DLL_THREAD_ATTACH };
 165  i :      module_events_.push_back(event);
 166  i :    }
 167    :  
 168    :    virtual void OnThreadDetach(base::Time time,
 169    :                                DWORD process_id,
 170    :                                DWORD thread_id,
 171  i :                                const TraceModuleData* data) {
 172  i :      ModuleEvent event = { time, thread_id, *data, DLL_THREAD_DETACH };
 173  i :      module_events_.push_back(event);
 174  i :    }
 175    :  
 176    :    virtual void OnInvocationBatch(base::Time time,
 177    :                                   DWORD process_id,
 178    :                                   DWORD thread_id,
 179    :                                   size_t num_invocations,
 180  i :                                   const TraceBatchInvocationInfo* data) {
 181  i :      ADD_FAILURE() << "Unexpected event.";
 182  i :    }
 183    :  
 184    :    virtual void OnThreadName(base::Time time,
 185    :                              DWORD process_id,
 186    :                              DWORD thread_id,
 187  i :                              const base::StringPiece& thread_name) {
 188  i :      ADD_FAILURE() << "Unexpected event.";
 189  i :    }
 190    :  
 191    :    virtual void OnIndexedFrequency(
 192    :        base::Time time,
 193    :        DWORD process_id,
 194    :        DWORD thread_id,
 195  i :        const TraceIndexedFrequencyData* data) {
 196  i :      ADD_FAILURE() << "Unexpected event.";
 197  i :    }
 198    :  
 199  E :    void GetEnteredAddresses(CalledAddresses* entered_addresses) {
 200  E :      ASSERT_TRUE(entered_addresses != NULL);
 201  E :      entered_addresses_.swap(*entered_addresses);
 202  E :    }
 203    :  
 204  E :    void GetExitedAddresses(CalledAddresses* exited_addresses) {
 205  E :      ASSERT_TRUE(exited_addresses != NULL);
 206  E :      exited_addresses_.swap(*exited_addresses);
 207  E :    }
 208    :  
 209  E :    void GetRawCalls(RawCalls* calls) {
 210  E :      ASSERT_TRUE(calls != NULL);
 211  E :      raw_calls_.swap(*calls);
 212  E :    }
 213    :  
 214  E :    void GetOrderedCalls(OrderedCalls* calls) {
 215  E :      ASSERT_TRUE(calls != NULL);
 216  E :      ordered_calls_.swap(*calls);
 217  E :    }
 218    :  
 219  E :    void GetModuleEvents(ModuleEvents* module_events) {
 220  E :      ASSERT_TRUE(module_events != NULL);
 221  E :      module_events_.swap(*module_events);
 222  E :    }
 223    :  
 224    :   private:
 225    :    DWORD process_id_;
 226    :    DWORD event_id_;  // Used to conserve relative ordering of calls.
 227    :    ModuleEvents module_events_;
 228    :    CalledAddresses entered_addresses_;
 229    :    CalledAddresses exited_addresses_;
 230    :    RawCalls raw_calls_;
 231    :    OrderedCalls ordered_calls_;
 232    :  };
 233    :  
 234    :  const wchar_t* const kTestSessionName = L"TestLogSession";
 235    :  
 236    :  typedef BOOL (WINAPI *DllMainFunc)(HMODULE module,
 237    :                                     DWORD reason,
 238    :                                     LPVOID reserved);
 239    :  
 240    :  extern const DllMainFunc IndirectThunkDllMain;
 241    :  
 242    :  // We run events through a file session to assert that
 243    :  // the content comes through.
 244    :  class ParseEngineRpcTest: public testing::PELibUnitTest {
 245    :   public:
 246    :    typedef testing::PELibUnitTest Super;
 247    :  
 248  E :    ParseEngineRpcTest() : module_(NULL) {
 249  E :    }
 250    :  
 251  E :    bool FindTraceFile(base::FilePath* trace_file_path) {
 252  E :      DCHECK(trace_file_path != NULL);
 253    :      base::FileEnumerator enumerator(temp_dir_, false,
 254    :                                      base::FileEnumerator::FILES,
 255  E :                                      L"trace-*.bin");
 256  E :      *trace_file_path = enumerator.Next();
 257  E :      return !trace_file_path->empty() && enumerator.Next().empty();
 258  E :    }
 259    :  
 260  E :    virtual void SetUp() {
 261  E :      Super::SetUp();
 262    :  
 263    :      // Create a temporary directory for the call trace files.
 264  E :      ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_));
 265    :  
 266  E :      ASSERT_NO_FATAL_FAILURE(service_.SetEnvironment());
 267    :  
 268    :      // The call trace DLL should not be already loaded.
 269  E :      ASSERT_EQ(NULL, ::GetModuleHandle(L"call_trace_client.dll"));
 270  E :    }
 271    :  
 272  E :    virtual void TearDown() {
 273  E :      UnloadCallTraceDll();
 274  E :      StopCallTraceService();
 275  E :      Super::TearDown();
 276  E :    }
 277    :  
 278  E :    void StartCallTraceService() {
 279  E :      service_.Start(temp_dir_);
 280  E :    }
 281    :  
 282  E :    void StopCallTraceService() {
 283  E :      service_.Stop();
 284  E :    }
 285    :  
 286  E :    void ConsumeEventsFromTempSession() {
 287    :      // Stop the call trace service to ensure all buffers have been flushed.
 288  E :      ASSERT_NO_FATAL_FAILURE(StopCallTraceService());
 289    :  
 290    :      // Parse the call trace log.
 291  E :      TestParseEventHandler consumer;
 292  E :      Parser parser;
 293  E :      ASSERT_TRUE(parser.Init(&consumer));
 294  E :      base::FilePath trace_file_path;
 295  E :      ASSERT_TRUE(FindTraceFile(&trace_file_path));
 296  E :      ASSERT_TRUE(parser.OpenTraceFile(trace_file_path));
 297  E :      ASSERT_TRUE(parser.Consume());
 298    :  
 299    :      // Get the information for this process.
 300  E :      uint32 pid = ::GetCurrentProcessId();
 301  E :      trace::service::ProcessInfo process_info;
 302  E :      ASSERT_TRUE(process_info.Initialize(pid));
 303    :  
 304    :      // Look up this process in the process map.
 305    :      trace::parser::AbsoluteAddress64 addr =
 306  E :          reinterpret_cast<uint32>(&kConstantInThisModule);
 307    :      const trace::parser::ModuleInformation* module_info =
 308  E :          parser.GetModuleInformation(pid, addr);
 309    :  
 310    :      // An entry should exist for this process, and it should match our
 311    :      // process info.
 312  E :      ASSERT_TRUE(module_info != NULL);
 313  E :      ASSERT_EQ(process_info.executable_path,
 314    :                base::FilePath(module_info->path));
 315  E :      ASSERT_EQ(process_info.exe_base_address, module_info->base_address.value());
 316  E :      ASSERT_EQ(process_info.exe_image_size, module_info->module_size);
 317  E :      ASSERT_EQ(process_info.exe_checksum, module_info->module_checksum);
 318  E :      ASSERT_EQ(process_info.exe_time_date_stamp,
 319    :                module_info->module_time_date_stamp);
 320    :  
 321    :      // And extract the results.
 322  E :      entered_addresses_.clear();
 323  E :      exited_addresses_.clear();
 324  E :      raw_calls_.clear();
 325  E :      ordered_calls_.clear();
 326  E :      consumer.GetModuleEvents(&module_events_);
 327  E :      consumer.GetEnteredAddresses(&entered_addresses_);
 328  E :      consumer.GetExitedAddresses(&exited_addresses_);
 329  E :      consumer.GetRawCalls(&raw_calls_);
 330  E :      consumer.GetOrderedCalls(&ordered_calls_);
 331  E :    }
 332    :  
 333  E :    void LoadCallTraceDll() {
 334  E :      ASSERT_TRUE(module_ == NULL);
 335  E :      const wchar_t* call_trace_dll = L"call_trace_client.dll";
 336  E :      ASSERT_EQ(NULL, ::GetModuleHandle(call_trace_dll));
 337  E :      module_ = ::LoadLibrary(call_trace_dll);
 338  E :      ASSERT_TRUE(module_ != NULL);
 339    :      _indirect_penter_dllmain_ =
 340  E :          GetProcAddress(module_, "_indirect_penter_dllmain");
 341  E :      _indirect_penter_ = GetProcAddress(module_, "_indirect_penter");
 342    :  
 343  E :      ASSERT_TRUE(_indirect_penter_dllmain_ != NULL);
 344  E :      ASSERT_TRUE(_indirect_penter_ != NULL);
 345  E :    }
 346    :  
 347  E :    void UnloadCallTraceDll() {
 348  E :      if (module_ != NULL) {
 349  E :        ASSERT_TRUE(::FreeLibrary(module_));
 350  E :        module_ = NULL;
 351  E :        _indirect_penter_ = NULL;
 352  E :        _indirect_penter_dllmain_ = NULL;
 353    :      }
 354  E :    }
 355    :  
 356    :    friend void IndirectThunkDllMainImpl();
 357    :    friend void IndirectThunkA();
 358    :    friend void IndirectThunkB();
 359    :  
 360    :   protected:
 361    :    // Our call trace service instance.
 362    :    testing::CallTraceService service_;
 363    :  
 364    :    // The directory where trace file output will be written.
 365    :    base::FilePath temp_dir_;
 366    :  
 367    :    // @name Book-keeping for the tests.
 368    :    // @{
 369    :    CalledAddresses entered_addresses_;
 370    :    CalledAddresses exited_addresses_;
 371    :    RawCalls raw_calls_;
 372    :    OrderedCalls ordered_calls_;
 373    :    ModuleEvents module_events_;
 374    :    // @}
 375    :  
 376    :    HMODULE module_;
 377    :    static FARPROC _indirect_penter_;
 378    :    static FARPROC _indirect_penter_dllmain_;
 379    :  };
 380    :  
 381    :  FARPROC ParseEngineRpcTest::_indirect_penter_dllmain_ = 0;
 382    :  FARPROC ParseEngineRpcTest::_indirect_penter_ = 0;
 383    :  
 384    :  static BOOL WINAPI IndirectDllMain(HMODULE module,
 385    :                                     DWORD reason,
 386  E :                                     LPVOID reserved) {
 387  E :    return TRUE;
 388  E :  }
 389    :  
 390  i :  void __declspec(naked) IndirectThunkDllMainImpl() {
 391    :    __asm {
 392  i :      push IndirectDllMain
 393  i :      jmp ParseEngineRpcTest::_indirect_penter_dllmain_
 394    :    }
 395    :  }
 396    :  
 397    :  const DllMainFunc IndirectThunkDllMain =
 398    :      reinterpret_cast<const DllMainFunc>(&IndirectThunkDllMainImpl);
 399    :  
 400  E :  void IndirectFunctionA() {
 401  E :    rand();
 402  E :  }
 403    :  
 404  i :  void __declspec(naked) IndirectThunkA() {
 405    :    __asm {
 406  i :      push IndirectFunctionA
 407  i :      jmp ParseEngineRpcTest::_indirect_penter_
 408    :    }
 409    :  }
 410    :  
 411  E :  void IndirectFunctionB() {
 412  E :    clock();
 413  E :  }
 414    :  
 415  i :  void __declspec(naked) IndirectThunkB() {
 416    :    __asm {
 417  i :      push IndirectFunctionB
 418  i :      jmp ParseEngineRpcTest::_indirect_penter_
 419    :    }
 420    :  }
 421    :  
 422    :  class IndirectFunctionThread : public base::DelegateSimpleThread::Delegate {
 423    :   public:
 424    :    IndirectFunctionThread(int invocation_count, void (*f)(void), HMODULE module,
 425    :                           DWORD delay = 0)
 426    :        : invocation_count_(invocation_count), f_(f), module_(module),
 427  E :          delay_(delay), thread_detach_(true) {
 428  E :      exit_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
 429  E :      CHECK(exit_event_);
 430  E :      done_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
 431  E :      CHECK(done_event_);
 432  E :    }
 433    :  
 434  E :    void set_thread_detach(bool value) {
 435  E :      thread_detach_ = value;
 436  E :    }
 437    :  
 438  E :    virtual void Run() {
 439  E :      IndirectThunkDllMain(module_, DLL_THREAD_ATTACH, NULL);
 440  E :      if (delay_ != 0) {
 441  E :        ::Sleep(delay_);
 442    :      }
 443  E :      for (int i = 0; i < invocation_count_; ++i) {
 444  E :        f_();
 445  E :        if (delay_ != 0) {
 446  E :          ::Sleep(delay_);
 447    :        }
 448  E :      }
 449  E :      ::SetEvent(done_event_);
 450  E :      ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(exit_event_, INFINITE));
 451  E :      if (thread_detach_)
 452  E :        IndirectThunkDllMain(module_, DLL_THREAD_DETACH, NULL);
 453  E :    }
 454    :  
 455  E :    void Exit() {
 456  E :      ::SetEvent(exit_event_);
 457  E :    }
 458    :  
 459  E :    void Wait() {
 460  E :      ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(done_event_, INFINITE));
 461  E :    }
 462    :  
 463    :   private:
 464    :    int invocation_count_;
 465    :    void (*f_)(void);
 466    :    DWORD delay_;
 467    :    base::win::ScopedHandle exit_event_;
 468    :    base::win::ScopedHandle done_event_;
 469    :    HMODULE module_;
 470    :    bool thread_detach_;
 471    :  };
 472    :  
 473    :  // IndirectFunctionThreads aren't copy constructible due to
 474    :  // base::win::ScopedHandle member variables. Thus we have to jump
 475    :  // through hoops to copy-initialize arrays of them.
 476    :  typedef ScopedVector<IndirectFunctionThread> IndirectFunctionThreads;
 477    :  
 478    :  }  // namespace
 479    :  
 480  E :  TEST_F(ParseEngineRpcTest, LoadUnload) {
 481  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 482  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 483    :  
 484  E :    base::FilePath trace_file_path;
 485  E :    ASSERT_FALSE(FindTraceFile(&trace_file_path));
 486  E :    ASSERT_TRUE(trace_file_path.empty());
 487  E :  }
 488    :  
 489  E :  TEST_F(ParseEngineRpcTest, NoServiceInstance) {
 490  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 491    :  
 492  E :    IndirectThunkDllMain(module_, DLL_PROCESS_ATTACH, this);
 493  E :    IndirectThunkA();
 494  E :    IndirectThunkA();
 495  E :    IndirectThunkA();
 496  E :    IndirectThunkDllMain(module_, DLL_PROCESS_DETACH, this);
 497    :  
 498  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 499    :  
 500  E :    base::FilePath trace_file_path;
 501  E :    ASSERT_FALSE(FindTraceFile(&trace_file_path));
 502  E :    ASSERT_TRUE(trace_file_path.empty());
 503  E :  }
 504    :  
 505  E :  TEST_F(ParseEngineRpcTest, NoSessionCreated) {
 506  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 507    :  
 508  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 509    :  
 510  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 511    :  
 512  E :    base::FilePath trace_file_path;
 513  E :    ASSERT_FALSE(FindTraceFile(&trace_file_path));
 514  E :    ASSERT_TRUE(trace_file_path.empty());
 515  E :  }
 516    :  
 517  E :  TEST_F(ParseEngineRpcTest, SingleThread) {
 518  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 519    :  
 520  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 521    :  
 522  E :    IndirectThunkDllMain(module_, DLL_PROCESS_ATTACH, this);
 523  E :    IndirectThunkA();
 524  E :    IndirectThunkA();
 525  E :    IndirectThunkA();
 526  E :    IndirectThunkDllMain(module_, DLL_PROCESS_DETACH, this);
 527    :  
 528  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 529    :  
 530  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 531    :  
 532  E :    ASSERT_EQ(5, entered_addresses_.size());
 533  E :    ASSERT_EQ(3, entered_addresses_.count(IndirectFunctionA));
 534  E :    ASSERT_EQ(2, entered_addresses_.count(IndirectDllMain));
 535  E :  }
 536    :  
 537  E :  TEST_F(ParseEngineRpcTest, MultiThreadWithDetach) {
 538  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 539    :  
 540  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 541    :  
 542  E :    IndirectThunkDllMain(module_, DLL_PROCESS_ATTACH, this);
 543  E :    IndirectFunctionThread runner_a(2, IndirectThunkA, module_);
 544    :  
 545  E :    base::DelegateSimpleThread thread(&runner_a, "thread a");
 546    :  
 547  E :    thread.Start();
 548  E :    runner_a.Exit();
 549  E :    thread.Join();
 550    :  
 551  E :    IndirectThunkDllMain(module_, DLL_PROCESS_DETACH, this);
 552    :  
 553  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 554    :  
 555  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 556    :  
 557  E :    ASSERT_EQ(6, entered_addresses_.size());
 558  E :    ASSERT_EQ(4, entered_addresses_.count(IndirectDllMain));
 559  E :    ASSERT_EQ(2, entered_addresses_.count(IndirectFunctionA));
 560  E :  }
 561    :  
 562  E :  TEST_F(ParseEngineRpcTest, MultiThreadWithoutDetach) {
 563  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 564    :  
 565  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 566    :  
 567  E :    IndirectFunctionThread runner_a(2, IndirectThunkA, module_);
 568  E :    runner_a.set_thread_detach(false);
 569  E :    base::DelegateSimpleThread thread(&runner_a, "thread a");
 570    :  
 571  E :    thread.Start();
 572  E :    runner_a.Wait();
 573    :  
 574  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 575    :  
 576  E :    runner_a.Exit();
 577  E :    thread.Join();
 578    :  
 579  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 580    :  
 581  E :    ASSERT_EQ(3, entered_addresses_.size());
 582  E :    ASSERT_EQ(2, entered_addresses_.count(IndirectFunctionA));
 583  E :    ASSERT_EQ(1, entered_addresses_.count(IndirectDllMain));
 584  E :  }
 585    :  
 586  E :  TEST_F(ParseEngineRpcTest, RawCallSequence) {
 587  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 588    :  
 589  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 590    :  
 591  E :    IndirectFunctionThreads runners;
 592    :    runners.push_back(
 593  E :        new IndirectFunctionThread(1, IndirectThunkA, module_, 10));
 594    :    runners.push_back(
 595  E :        new IndirectFunctionThread(2, IndirectThunkB, module_, 10));
 596    :    runners.push_back(
 597  E :        new IndirectFunctionThread(3, IndirectThunkA, module_, 10));
 598    :    runners.push_back(
 599  E :        new IndirectFunctionThread(4, IndirectThunkB, module_, 10));
 600    :    runners.push_back(
 601  E :        new IndirectFunctionThread(5, IndirectThunkA, module_, 10));
 602    :    runners.push_back(
 603  E :        new IndirectFunctionThread(6, IndirectThunkB, module_, 10));
 604    :  
 605  E :    runners[0]->set_thread_detach(false);
 606  E :    runners[5]->set_thread_detach(false);
 607    :  
 608    :    base::DelegateSimpleThread threads[] = {
 609    :        base::DelegateSimpleThread(runners[0], "thread 0"),
 610    :        base::DelegateSimpleThread(runners[1], "thread 1"),
 611    :        base::DelegateSimpleThread(runners[2], "thread 2"),
 612    :        base::DelegateSimpleThread(runners[3], "thread 3"),
 613    :        base::DelegateSimpleThread(runners[4], "thread 4"),
 614  E :        base::DelegateSimpleThread(runners[5], "thread 5")};
 615    :  
 616  E :    std::vector<FuncAddr> expected_call_sequence;
 617  E :    for (size_t i = 0; i < arraysize(threads); ++i) {
 618    :      // Thread i makes calls IndirectDllMain here and makes all of its calls to
 619    :      // IndirectFunctionA/B, but nothing gets committed yet.
 620  E :      threads[i].Start();
 621  E :      runners[i]->Wait();
 622  E :      ::Sleep(20);
 623    :  
 624  E :      if (i == 1 || i == 3) {
 625    :        // Threads i==1 and i==3 detach here. This commits their i+1 calls to
 626    :        // IndirectFunctionB sandwiched between their 2 call to IndirectDllMain.
 627  E :        runners[i]->Exit();
 628  E :        threads[i].Join();
 629  E :        expected_call_sequence.push_back(IndirectDllMain);
 630    :        expected_call_sequence.insert(
 631  E :            expected_call_sequence.end(), i + 1, IndirectFunctionB);
 632  E :        expected_call_sequence.push_back(IndirectDllMain);
 633    :      }
 634  E :    }
 635    :  
 636    :    // Threads 2 detaches here, which commits it's 3 calls to IndirectFunctionA
 637    :    // and sandwiched between its 2 calls to IndirectDllMain.
 638  E :    runners[2]->Exit();
 639  E :    threads[2].Join();
 640  E :    expected_call_sequence.push_back(IndirectDllMain);
 641    :    expected_call_sequence.insert(
 642  E :        expected_call_sequence.end(), 3, IndirectFunctionA);
 643  E :    expected_call_sequence.push_back(IndirectDllMain);
 644    :  
 645    :    // Threads 4 detaches here, which commits it's 5 calls to IndirectFunctionA
 646    :    // and it's 1 call to IndirectDllMain.
 647  E :    runners[4]->Exit();
 648  E :    threads[4].Join();
 649  E :    expected_call_sequence.push_back(IndirectDllMain);
 650    :    expected_call_sequence.insert(
 651  E :        expected_call_sequence.end(), 5, IndirectFunctionA);
 652  E :    expected_call_sequence.push_back(IndirectDllMain);
 653    :  
 654    :    // Unloading the test dll commits all outstanding events already written
 655    :    // to the shared memory trace log buffers.
 656  E :    UnloadCallTraceDll();
 657    :  
 658    :    // Threads 0 does not detach. We get its 1 call to IndirectFunctionA
 659    :    // prefaced by its initial call IndirectDllMain. No trailing call to
 660    :    // IndirectDllMain is recorded.
 661  E :    runners[0]->Exit();
 662  E :    threads[0].Join();
 663  E :    expected_call_sequence.push_back(IndirectDllMain);
 664    :    expected_call_sequence.insert(
 665  E :        expected_call_sequence.end(), 1, IndirectFunctionA);
 666    :  
 667    :    // Threads 5 does not detach. We get its 6 calls to IndirectFunctionB
 668    :    // prefaced by its initial call IndirectDllMain. No trailing call to
 669    :    // IndirectDllMain is recorded.
 670  E :    runners[5]->Exit();
 671  E :    threads[5].Join();
 672  E :    expected_call_sequence.push_back(IndirectDllMain);
 673    :    expected_call_sequence.insert(
 674  E :        expected_call_sequence.end(), 6, IndirectFunctionB);
 675    :  
 676  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 677    :  
 678  E :    ASSERT_EQ(31, entered_addresses_.size());
 679  E :    ASSERT_EQ(9, entered_addresses_.count(IndirectFunctionA));
 680  E :    ASSERT_EQ(12, entered_addresses_.count(IndirectFunctionB));
 681  E :    ASSERT_EQ(10, entered_addresses_.count(IndirectDllMain));
 682    :  
 683  E :    std::vector<FuncAddr> call_sequence;
 684  E :    for (RawCallsIter it = raw_calls_.begin(); it != raw_calls_.end(); ++it)
 685  E :      call_sequence.push_back(it->address);
 686    :  
 687  E :    ASSERT_THAT(call_sequence, testing::ContainerEq(expected_call_sequence));
 688  E :  }
 689    :  
 690  E :  TEST_F(ParseEngineRpcTest, OrderedCallSequence) {
 691  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 692    :  
 693  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 694    :  
 695  E :    DWORD delay = 30;  // milliseconds
 696  E :    IndirectFunctionThreads runners;
 697    :    runners.push_back(
 698  E :        new IndirectFunctionThread(1, IndirectThunkA, module_, delay));
 699    :    runners.push_back(
 700  E :        new IndirectFunctionThread(2, IndirectThunkB, module_, delay));
 701    :    runners.push_back(
 702  E :        new IndirectFunctionThread(3, IndirectThunkA, module_, delay));
 703    :    runners.push_back(
 704  E :        new IndirectFunctionThread(4, IndirectThunkB, module_, delay));
 705    :    runners.push_back(
 706  E :        new IndirectFunctionThread(5, IndirectThunkA, module_, delay));
 707    :    runners.push_back(
 708  E :        new IndirectFunctionThread(6, IndirectThunkB, module_, delay));
 709    :  
 710  E :    runners[0]->set_thread_detach(false);
 711  E :    runners[5]->set_thread_detach(false);
 712    :  
 713    :    base::DelegateSimpleThread threads[] = {
 714    :        base::DelegateSimpleThread(runners[0], "thread 0"),
 715    :        base::DelegateSimpleThread(runners[1], "thread 1"),
 716    :        base::DelegateSimpleThread(runners[2], "thread 2"),
 717    :        base::DelegateSimpleThread(runners[3], "thread 3"),
 718    :        base::DelegateSimpleThread(runners[4], "thread 4"),
 719  E :        base::DelegateSimpleThread(runners[5], "thread 5")};
 720    :  
 721  E :    std::vector<FuncAddr> expected_call_sequence;
 722  E :    for (size_t i = 0; i < arraysize(threads); ++i) {
 723    :      // Thread i calls IndirectDllMain and makes i + 1 calls to its indirect
 724    :      // function.
 725  E :      threads[i].Start();
 726  E :      runners[i]->Wait();
 727  E :      expected_call_sequence.push_back(IndirectDllMain);
 728    :      expected_call_sequence.insert(
 729    :          expected_call_sequence.end(),
 730    :          i + 1,
 731  E :          (i & 1) == 0 ? IndirectFunctionA : IndirectFunctionB);
 732    :  
 733    :      // Cleanly shutdown all threads except for 2 of them.
 734  E :      if (i != 0 && i != 5) {
 735  E :        runners[i]->Exit();
 736  E :        threads[i].Join();
 737  E :        expected_call_sequence.push_back(IndirectDllMain);
 738    :      }
 739  E :    }
 740    :  
 741    :    // We can't say anything about the relative order of events across threads
 742    :    // because of the batch nature of the events. Thus, we don't attempt to create
 743    :    // staggered thread terminations.
 744    :  
 745    :    // Unloading the test dll commits all outstanding events already written
 746    :    // to the shared memory trace log buffers.
 747  E :    UnloadCallTraceDll();
 748    :  
 749    :    // Threads 0 does not detach, so we don't see a closing IndirectDllMain call.
 750  E :    runners[0]->Exit();
 751  E :    threads[0].Join();
 752    :  
 753    :    // Threads 5 does not detach either.
 754  E :    runners[5]->Exit();
 755  E :    threads[5].Join();
 756    :  
 757  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 758    :  
 759  E :    ASSERT_EQ(31, entered_addresses_.size());
 760  E :    ASSERT_EQ(9, entered_addresses_.count(IndirectFunctionA));
 761  E :    ASSERT_EQ(12, entered_addresses_.count(IndirectFunctionB));
 762  E :    ASSERT_EQ(10, entered_addresses_.count(IndirectDllMain));
 763    :  
 764  E :    std::vector<FuncAddr> call_sequence;
 765  E :    OrderedCallsIter it = ordered_calls_.begin();
 766  E :    for (; it != ordered_calls_.end(); ++it) {
 767  E :      call_sequence.push_back(it->address);
 768  E :    }
 769    :  
 770  E :    ASSERT_THAT(call_sequence, testing::ContainerEq(expected_call_sequence));
 771  E :  }
 772    :  
 773  E :  TEST_F(ParseEngineRpcTest, MultiThreadWithStopCallTrace) {
 774  E :    ASSERT_NO_FATAL_FAILURE(StartCallTraceService());
 775    :  
 776  E :    ASSERT_NO_FATAL_FAILURE(LoadCallTraceDll());
 777    :  
 778  E :    IndirectFunctionThread runner_a(2, IndirectThunkA, module_);
 779  E :    IndirectFunctionThread runner_b(77, IndirectThunkB, module_);
 780    :  
 781  E :    runner_a.set_thread_detach(false);
 782  E :    runner_b.set_thread_detach(false);
 783    :  
 784  E :    base::DelegateSimpleThread thread_a(&runner_a, "thread a");
 785  E :    base::DelegateSimpleThread thread_b(&runner_b, "thread b");
 786    :  
 787  E :    thread_a.Start();
 788  E :    thread_b.Start();
 789  E :    runner_a.Wait();
 790  E :    runner_b.Wait();
 791    :  
 792  E :    ASSERT_NO_FATAL_FAILURE(UnloadCallTraceDll());
 793  E :    runner_a.Exit();
 794  E :    runner_b.Exit();
 795  E :    thread_a.Join();
 796  E :    thread_b.Join();
 797    :  
 798  E :    ASSERT_NO_FATAL_FAILURE(ConsumeEventsFromTempSession());
 799    :  
 800  E :    ASSERT_EQ(2, entered_addresses_.count(IndirectDllMain));
 801  E :    ASSERT_EQ(2, entered_addresses_.count(IndirectFunctionA));
 802  E :    ASSERT_EQ(77, entered_addresses_.count(IndirectFunctionB));
 803  E :  }
 804    :  
 805    :  }  // namespace service
 806    :  }  // namespace trace

Coverage information generated Thu Mar 26 16:15:41 2015.