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
|