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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.0%3814140.C++test

Line-by-line coverage:

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

Coverage information generated Thu Sep 06 11:30:46 2012.