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
|