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

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

Coverage information generated Thu Jul 04 09:34:53 2013.