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
|