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 : // BasicBlockEntry trace agent unit-tests.
16 :
17 : #include "syzygy/agent/basic_block_entry/basic_block_entry.h"
18 :
19 : #include "base/bind.h"
20 : #include "base/callback.h"
21 : #include "base/file_util.h"
22 : #include "base/files/file_enumerator.h"
23 : #include "base/files/scoped_temp_dir.h"
24 : #include "base/strings/stringprintf.h"
25 : #include "base/threading/thread.h"
26 : #include "gmock/gmock.h"
27 : #include "gtest/gtest.h"
28 : #include "syzygy/common/indexed_frequency_data.h"
29 : #include "syzygy/trace/common/unittest_util.h"
30 : #include "syzygy/trace/parse/unittest_util.h"
31 :
32 : // There's a quick and dirty way to get the HMODULE of this module for MS
33 : // linkers. HINSTANCE == HMODULE == &__ImageBase;
34 : // See http://blogs.msdn.com/b/oldnewthing/archive/2004/10/25/247180.aspx
35 : EXTERN_C IMAGE_DOS_HEADER __ImageBase;
36 :
37 : namespace agent {
38 : namespace basic_block_entry {
39 :
40 : namespace {
41 :
42 : using ::common::IndexedFrequencyData;
43 : using testing::_;
44 : using testing::StrictMockParseEventHandler;
45 : using trace::parser::Parser;
46 :
47 : // This is the name of the agent DLL.
48 : const wchar_t kBasicBlockEntryClientDll[] = L"basic_block_entry_client.dll";
49 :
50 : // The number of columns we'll work with for these tests.
51 : const uint32 kNumColumns = 1;
52 : const uint32 kNumBranchColumns = 3;
53 :
54 : // The number of basic blocks we'll work with for these tests.
55 : const uint32 kNumBasicBlocks = 2;
56 :
57 : // The number of threads used for parallel tests.
58 : const uint32 kNumThreads = 8;
59 :
60 : // Number of iterations done by each thread.
61 : const uint32 kNumThreadIteration = 4 * BasicBlockEntry::kBufferSize;
62 :
63 : // The module defining this lib/executable.
64 : const HMODULE kThisModule = reinterpret_cast<HMODULE>(&__ImageBase);
65 :
66 : // A helper to match modules by base address.
67 E : MATCHER_P(ModuleAtAddress, module, "") {
68 E : return arg->module_base_addr == module;
69 E : }
70 :
71 : // A helper to match basic-block frequency results to expectations.
72 E : MATCHER_P3(FrequencyDataMatches, module, values_count, bb_freqs, "") {
73 E : if (arg->module_base_addr != module)
74 i : return false;
75 :
76 E : if (arg->frequency_size != sizeof(uint32))
77 i : return false;
78 :
79 E : if (arg->num_entries * arg->num_columns != values_count)
80 i : return false;
81 :
82 E : return ::memcmp(bb_freqs, arg->frequency_data, values_count) == 0;
83 E : }
84 :
85 : // The test fixture for the basic-block entry agent.
86 : class BasicBlockEntryTest : public testing::Test {
87 : public:
88 : enum InstrumentationMode {
89 : kBasicBlockEntryInstrumentation,
90 : kBranchInstrumentation,
91 : kBufferedBranchInstrumentation,
92 : kBranchWithSlotInstrumentation,
93 : kBufferedBranchWithSlotInstrumentation
94 : };
95 :
96 : enum MainMode {
97 : kDllMain,
98 : kExeMain
99 : };
100 :
101 E : BasicBlockEntryTest()
102 : : agent_module_(NULL) {
103 E : }
104 :
105 E : void ConfigureBasicBlockAgent() {
106 E : common_data_->agent_id = ::common::kBasicBlockEntryAgentId;
107 E : common_data_->data_type = ::common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
108 E : common_data_->version = ::common::kBasicBlockFrequencyDataVersion;
109 E : module_data_.tls_index = TLS_OUT_OF_INDEXES;
110 E : module_data_.fs_slot = 0;
111 E : common_data_->initialization_attempted = 0U;
112 E : common_data_->num_entries = kNumBasicBlocks;
113 E : common_data_->num_columns = kNumColumns;
114 E : common_data_->frequency_size = sizeof(default_frequency_data_[0]);
115 E : common_data_->frequency_data = default_frequency_data_;
116 E : ::memset(&default_frequency_data_, 0, sizeof(default_frequency_data_));
117 E : }
118 :
119 E : void ConfigureBranchAgent() {
120 E : common_data_->agent_id = ::common::kBasicBlockEntryAgentId;
121 E : common_data_->data_type = ::common::IndexedFrequencyData::BRANCH;
122 E : common_data_->version = ::common::kBasicBlockFrequencyDataVersion;
123 E : module_data_.tls_index = TLS_OUT_OF_INDEXES;
124 E : module_data_.fs_slot = 0;
125 E : common_data_->initialization_attempted = 0U;
126 E : common_data_->num_entries = kNumBasicBlocks;
127 E : common_data_->num_columns = kNumBranchColumns;
128 E : common_data_->frequency_size = sizeof(default_branch_data_[0]);
129 E : common_data_->frequency_data = default_branch_data_;
130 E : ::memset(&default_branch_data_, 0, sizeof(default_branch_data_));
131 E : }
132 :
133 E : void ConfigureAgent(InstrumentationMode mode) {
134 E : switch (mode) {
135 : case kBasicBlockEntryInstrumentation:
136 E : ConfigureBasicBlockAgent();
137 E : break;
138 : case kBranchInstrumentation:
139 : case kBufferedBranchInstrumentation:
140 E : ConfigureBranchAgent();
141 E : break;
142 : case kBranchWithSlotInstrumentation:
143 : case kBufferedBranchWithSlotInstrumentation:
144 E : ConfigureBranchAgent();
145 E : module_data_.fs_slot = 1;
146 E : break;
147 : default:
148 i : NOTREACHED();
149 : break;
150 : }
151 E : }
152 :
153 E : void Startup(MainMode mode) {
154 E : switch (mode) {
155 : case kDllMain:
156 : // Simulate the process attach event.
157 E : SimulateModuleEvent(DLL_PROCESS_ATTACH);
158 E : break;
159 : case kExeMain:
160 : // Simulate the call to main.
161 E : ExeMainThunk();
162 E : break;
163 : default:
164 i : NOTREACHED();
165 : break;
166 : }
167 E : }
168 :
169 E : void Shutdown(MainMode mode) {
170 E : switch (mode) {
171 : case kDllMain:
172 : // Simulate the process detach event.
173 E : SimulateModuleEvent(DLL_PROCESS_DETACH);
174 E : break;
175 : case kExeMain:
176 E : break;
177 : default:
178 i : NOTREACHED();
179 : break;
180 : }
181 E : }
182 :
183 E : virtual void SetUp() OVERRIDE {
184 E : testing::Test::SetUp();
185 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
186 E : service_.SetEnvironment();
187 E : common_data_ = &module_data_.module_data;
188 E : }
189 :
190 E : virtual void TearDown() OVERRIDE {
191 E : UnloadDll();
192 E : service_.Stop();
193 E : }
194 :
195 E : void StartService() {
196 E : service_.Start(temp_dir_.path());
197 E : }
198 :
199 E : void StopService() {
200 E : service_.Stop();
201 E : }
202 :
203 E : void ReplayLogs(size_t files_expected) {
204 : // Stop the service if it's running.
205 E : ASSERT_NO_FATAL_FAILURE(StopService());
206 :
207 E : Parser parser;
208 E : ASSERT_TRUE(parser.Init(&handler_));
209 :
210 : // Queue up the trace file(s) we engendered.
211 : base::FileEnumerator enumerator(temp_dir_.path(),
212 : false,
213 E : base::FileEnumerator::FILES);
214 E : size_t num_files = 0;
215 E : while (true) {
216 E : base::FilePath trace_file = enumerator.Next();
217 E : if (trace_file.empty())
218 E : break;
219 E : ASSERT_TRUE(parser.OpenTraceFile(trace_file));
220 E : ++num_files;
221 E : }
222 :
223 E : EXPECT_EQ(files_expected, num_files);
224 :
225 E : if (num_files > 0)
226 E : ASSERT_TRUE(parser.Consume());
227 E : }
228 :
229 E : void LoadDll() {
230 E : ASSERT_EQ(NULL, agent_module_);
231 E : ASSERT_EQ(NULL, basic_block_enter_stub_);
232 E : ASSERT_EQ(NULL, ::GetModuleHandle(kBasicBlockEntryClientDll));
233 :
234 E : agent_module_ = ::LoadLibrary(kBasicBlockEntryClientDll);
235 E : ASSERT_TRUE(agent_module_ != NULL);
236 :
237 : basic_block_enter_stub_ =
238 E : ::GetProcAddress(agent_module_, "_branch_enter");
239 E : ASSERT_TRUE(basic_block_enter_stub_ != NULL);
240 :
241 : basic_block_enter_buffered_stub_ =
242 E : ::GetProcAddress(agent_module_, "_branch_enter_buffered");
243 E : ASSERT_TRUE(basic_block_enter_buffered_stub_ != NULL);
244 :
245 : basic_block_enter_s1_stub_ =
246 E : ::GetProcAddress(agent_module_, "_branch_enter_s1");
247 E : ASSERT_TRUE(basic_block_enter_s1_stub_ != NULL);
248 :
249 : basic_block_enter_buffered_s1_stub_ =
250 E : ::GetProcAddress(agent_module_, "_branch_enter_buffered_s1");
251 E : ASSERT_TRUE(basic_block_enter_buffered_s1_stub_ != NULL);
252 :
253 : basic_block_exit_stub_ =
254 E : ::GetProcAddress(agent_module_, "_branch_exit");
255 E : ASSERT_TRUE(basic_block_exit_stub_ != NULL);
256 :
257 : basic_block_exit_s1_stub_ =
258 E : ::GetProcAddress(agent_module_, "_branch_exit_s1");
259 E : ASSERT_TRUE(basic_block_exit_s1_stub_ != NULL);
260 :
261 : basic_block_function_enter_s1_stub_ =
262 E : ::GetProcAddress(agent_module_, "_function_enter_s1");
263 E : ASSERT_TRUE(basic_block_function_enter_s1_stub_ != NULL);
264 :
265 : basic_block_increment_stub_ =
266 E : ::GetProcAddress(agent_module_, "_increment_indexed_freq_data");
267 E : ASSERT_TRUE(basic_block_increment_stub_ != NULL);
268 :
269 : indirect_penter_dllmain_stub_ =
270 E : ::GetProcAddress(agent_module_, "_indirect_penter_dllmain");
271 E : ASSERT_TRUE(indirect_penter_dllmain_stub_ != NULL);
272 :
273 : indirect_penter_exemain_stub_ =
274 E : ::GetProcAddress(agent_module_, "_indirect_penter_exemain");
275 E : ASSERT_TRUE(indirect_penter_exemain_stub_ != NULL);
276 E : }
277 :
278 E : void UnloadDll() {
279 E : if (agent_module_ != NULL) {
280 E : ASSERT_TRUE(::FreeLibrary(agent_module_));
281 E : agent_module_ = NULL;
282 E : basic_block_enter_stub_ = NULL;
283 E : basic_block_enter_buffered_stub_ = NULL;
284 E : basic_block_enter_s1_stub_ = NULL;
285 E : basic_block_enter_buffered_s1_stub_ = NULL;
286 E : basic_block_exit_stub_ = NULL;
287 E : basic_block_exit_s1_stub_ = NULL;
288 E : basic_block_function_enter_s1_stub_ = NULL;
289 E : basic_block_increment_stub_ = NULL;
290 E : indirect_penter_dllmain_stub_ = NULL;
291 E : indirect_penter_exemain_stub_ = NULL;
292 : }
293 E : }
294 :
295 : protected:
296 : static BOOL WINAPI DllMain(HMODULE module, DWORD reason, LPVOID reserved);
297 : static BOOL WINAPI DllMainThunk(
298 : HMODULE module, DWORD reason, LPVOID reserved);
299 : static int __cdecl ExeMain();
300 : static int __cdecl ExeMainThunk();
301 : static int __cdecl GetFrequencyDataThunk();
302 :
303 E : void SimulateModuleEvent(DWORD reason) {
304 E : DllMainThunk(kThisModule, reason, NULL);
305 E : }
306 :
307 i : void SimulateBasicBlockEntry(uint32 basic_block_id) {
308 : __asm {
309 i : push basic_block_id
310 i : push offset module_data_
311 i : call basic_block_increment_stub_
312 : }
313 i : }
314 :
315 i : void SimulateBranchEnter(uint32 basic_block_id) {
316 : __asm {
317 i : push basic_block_id
318 i : push offset module_data_
319 i : call basic_block_enter_stub_
320 : }
321 i : }
322 :
323 i : void SimulateBranchEnterBuffered(uint32 basic_block_id) {
324 : __asm {
325 i : push basic_block_id
326 i : push offset module_data_
327 i : call basic_block_enter_buffered_stub_
328 : }
329 i : }
330 :
331 i : void SimulateFunctionEnter() {
332 : __asm {
333 i : push offset module_data_
334 i : call basic_block_function_enter_s1_stub_
335 : }
336 i : }
337 :
338 i : void SimulateBranchEnterSlot(uint32 basic_block_id) {
339 : __asm {
340 i : push basic_block_id
341 i : call basic_block_enter_s1_stub_
342 : }
343 i : }
344 :
345 i : void SimulateBranchEnterBufferedSlot(uint32 basic_block_id) {
346 : __asm {
347 i : push basic_block_id
348 i : call basic_block_enter_buffered_s1_stub_
349 : }
350 i : }
351 :
352 i : void SimulateBranchExit(uint32 basic_block_id) {
353 : __asm {
354 i : push basic_block_id
355 i : push offset module_data_
356 i : call basic_block_exit_stub_
357 : }
358 i : }
359 :
360 : void SimulateBranchExitSlot(uint32 basic_block_id) {
361 : __asm {
362 : push basic_block_id
363 : call basic_block_exit_s1_stub_
364 : }
365 : }
366 :
367 E : void SimulateThreadFunction(InstrumentationMode mode) {
368 E : switch (mode) {
369 : case kBranchWithSlotInstrumentation:
370 : case kBufferedBranchWithSlotInstrumentation:
371 E : SimulateFunctionEnter();
372 : break;
373 : }
374 E : }
375 :
376 E : void SimulateThreadStep(InstrumentationMode mode, uint32 basic_block_id) {
377 E : switch (mode) {
378 : case kBasicBlockEntryInstrumentation:
379 E : SimulateBasicBlockEntry(basic_block_id);
380 E : break;
381 : case kBranchInstrumentation:
382 E : SimulateBranchEnter(basic_block_id);
383 E : SimulateBranchExit(basic_block_id);
384 E : break;
385 : case kBufferedBranchInstrumentation:
386 E : SimulateBranchEnterBuffered(basic_block_id);
387 E : SimulateBranchExit(basic_block_id);
388 E : break;
389 : case kBranchWithSlotInstrumentation:
390 E : SimulateBranchEnterSlot(basic_block_id);
391 E : SimulateBranchExit(basic_block_id);
392 E : break;
393 : case kBufferedBranchWithSlotInstrumentation:
394 E : SimulateBranchEnterBufferedSlot(basic_block_id);
395 E : SimulateBranchExit(basic_block_id);
396 E : break;
397 : default:
398 i : NOTREACHED();
399 : break;
400 : }
401 E : }
402 :
403 E : void SimulateThreadExecution(MainMode main_mode, InstrumentationMode mode) {
404 : // Simulate the thread attach event.
405 E : if (main_mode == kDllMain)
406 E : SimulateModuleEvent(DLL_THREAD_ATTACH);
407 :
408 : // Simulate entering a function.
409 E : SimulateThreadFunction(mode);
410 :
411 : // Simulate the thread loop.
412 E : for (uint32 i = 0; i < kNumThreadIteration; ++i) {
413 E : for (uint32 j = 0; j < kNumBasicBlocks; ++j)
414 E : SimulateThreadStep(mode, j);
415 E : }
416 :
417 : // Simulate the thread detach event.
418 E : if (main_mode == kDllMain)
419 E : SimulateModuleEvent(DLL_THREAD_DETACH);
420 E : }
421 :
422 E : void CheckThreadExecution(MainMode main_mode, InstrumentationMode mode) {
423 : // Configure for instrumented mode.
424 E : ConfigureAgent(mode);
425 :
426 E : ASSERT_NO_FATAL_FAILURE(StartService());
427 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
428 :
429 E : Startup(main_mode);
430 :
431 E : std::vector<base::Thread*> threads;
432 E : for (size_t i = 0; i < kNumThreads; ++i) {
433 E : std::string thread_name = base::StringPrintf("thread-%d", i);
434 E : threads.push_back(new base::Thread(thread_name.c_str()));
435 :
436 E : threads[i]->Start();
437 : threads[i]->message_loop()->PostTask(FROM_HERE,
438 : base::Bind(&BasicBlockEntryTest::SimulateThreadExecution,
439 : base::Unretained(this),
440 : main_mode,
441 E : mode));
442 E : }
443 :
444 : // Stop all running tasks.
445 E : for (size_t i = 0; i < kNumThreads; ++i) {
446 E : threads[i]->Stop();
447 E : delete threads[i];
448 E : }
449 E : threads.clear();
450 :
451 E : Shutdown(main_mode);
452 :
453 : // Validate all events have been committed.
454 : const uint32* frequency_data =
455 E : reinterpret_cast<uint32*>(common_data_->frequency_data);
456 E : uint32 num_columns = common_data_->num_columns;
457 :
458 E : const uint32 expected_frequency = kNumThreads * kNumThreadIteration;
459 E : for (size_t i = 0; i < kNumBasicBlocks; ++i) {
460 E : EXPECT_EQ(expected_frequency, frequency_data[i * num_columns]);
461 E : }
462 :
463 : // Unload the DLL and stop the service.
464 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
465 E : ASSERT_NO_FATAL_FAILURE(StopService());
466 E : }
467 :
468 E : void CheckExecution(MainMode main_mode, InstrumentationMode mode) {
469 : // Configure for instrumented mode.
470 E : ConfigureAgent(mode);
471 :
472 E : ASSERT_NO_FATAL_FAILURE(StartService());
473 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
474 :
475 : // Simulate the process attach event.
476 E : Startup(main_mode);
477 :
478 : // Simulate entering a function.
479 E : SimulateThreadFunction(mode);
480 :
481 : // Keep a pointer to raw counters.
482 : const uint32* frequency_data =
483 E : reinterpret_cast<uint32*>(common_data_->frequency_data);
484 E : uint32 num_columns = common_data_->num_columns;
485 :
486 : // Validate no events have been committed.
487 E : for (size_t i = 0; i < num_columns; ++i) {
488 E : EXPECT_EQ(0U, frequency_data[i]);
489 E : }
490 :
491 : // Simulate a sequential execution.
492 E : for (size_t i = 0; i < kNumThreads; ++i) {
493 E : for (uint32 j = 0; j < kNumThreadIteration; ++j) {
494 E : for (uint32 k = 0; k < kNumBasicBlocks; ++k)
495 E : SimulateThreadStep(mode, k);
496 E : }
497 E : }
498 :
499 : // Simulate the process detach event.
500 E : Shutdown(main_mode);
501 :
502 : // Validate all events have been committed.
503 E : const uint32 expected_frequency = kNumThreads * kNumThreadIteration;
504 E : for (size_t i = 0; i < kNumBasicBlocks; ++i) {
505 E : EXPECT_EQ(expected_frequency, frequency_data[i * num_columns]);
506 E : }
507 :
508 : // Unload the DLL and stop the service.
509 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
510 E : ASSERT_NO_FATAL_FAILURE(StopService());
511 E : }
512 :
513 : // The directory where trace file output will be written.
514 : base::ScopedTempDir temp_dir_;
515 :
516 : // The handler to which the trace file parser will delegate events.
517 : StrictMockParseEventHandler handler_;
518 :
519 : // Our call trace service process instance.
520 : testing::CallTraceService service_;
521 :
522 : // The basic-block entry client module.
523 : HMODULE agent_module_;
524 :
525 : // This will be a stand-in for the (usually statically allocated) trace
526 : // data which would have been referenced by the instrumentation.
527 : static BasicBlockEntry::BasicBlockIndexedFrequencyData module_data_;
528 : static BasicBlockEntry::IndexedFrequencyData* common_data_;
529 :
530 : // This will be a stand-in for the (usually statically allocated) fall-back
531 : // frequency to which module_data_.frequency_data will point.
532 : static uint32 default_frequency_data_[kNumBasicBlocks];
533 : static uint32 default_branch_data_[kNumBranchColumns * kNumBasicBlocks];
534 :
535 : // The basic-block entry entrance hook.
536 : static FARPROC basic_block_enter_stub_;
537 :
538 : // The basic-block entry entrance hook (with buffering).
539 : static FARPROC basic_block_enter_buffered_stub_;
540 :
541 : // The basic-block entry entrance hook (FS-slot 1).
542 : static FARPROC basic_block_enter_s1_stub_;
543 :
544 : // The basic-block entry entrance hook (with buffering and FS-slot 1).
545 : static FARPROC basic_block_enter_buffered_s1_stub_;
546 :
547 : // The basic-block exit hook.
548 : static FARPROC basic_block_exit_stub_;
549 :
550 : // The basic-block exit hook (FS-slot 1).
551 : static FARPROC basic_block_exit_s1_stub_;
552 :
553 : // The function entrance hook (FS-slot 1).
554 : static FARPROC basic_block_function_enter_s1_stub_;
555 :
556 : // The basic-block increment hook.
557 : static FARPROC basic_block_increment_stub_;
558 :
559 : // The DllMain entry stub.
560 : static FARPROC indirect_penter_dllmain_stub_;
561 :
562 : // The ExeMain entry stub.
563 : static FARPROC indirect_penter_exemain_stub_;
564 : };
565 :
566 : BOOL WINAPI BasicBlockEntryTest::DllMain(
567 E : HMODULE module, DWORD reason, LPVOID reserved) {
568 E : return TRUE;
569 E : }
570 :
571 : BOOL __declspec(naked) WINAPI BasicBlockEntryTest::DllMainThunk(
572 i : HMODULE module, DWORD reason, LPVOID reserved) {
573 : __asm {
574 i : push offset module_data_
575 i : push DllMain
576 i : jmp indirect_penter_dllmain_stub_
577 : }
578 : }
579 :
580 E : int __cdecl BasicBlockEntryTest::ExeMain() {
581 E : return 0;
582 E : }
583 :
584 i : BOOL __declspec(naked) __cdecl BasicBlockEntryTest::ExeMainThunk() {
585 : __asm {
586 i : push offset module_data_
587 i : push ExeMain
588 i : jmp indirect_penter_exemain_stub_
589 : }
590 : }
591 :
592 : BasicBlockEntry::BasicBlockIndexedFrequencyData
593 : BasicBlockEntryTest::module_data_ = {};
594 : BasicBlockEntry::IndexedFrequencyData* BasicBlockEntryTest::common_data_ = NULL;
595 : uint32 BasicBlockEntryTest::default_frequency_data_[] = {};
596 : uint32 BasicBlockEntryTest::default_branch_data_[] = {};
597 : FARPROC BasicBlockEntryTest::basic_block_enter_stub_ = NULL;
598 : FARPROC BasicBlockEntryTest::basic_block_enter_buffered_stub_ = NULL;
599 : FARPROC BasicBlockEntryTest::basic_block_enter_s1_stub_ = NULL;
600 : FARPROC BasicBlockEntryTest::basic_block_enter_buffered_s1_stub_ = NULL;
601 : FARPROC BasicBlockEntryTest::basic_block_exit_stub_ = NULL;
602 : FARPROC BasicBlockEntryTest::basic_block_exit_s1_stub_ = NULL;
603 : FARPROC BasicBlockEntryTest::basic_block_function_enter_s1_stub_ = NULL;
604 : FARPROC BasicBlockEntryTest::basic_block_increment_stub_ = NULL;
605 : FARPROC BasicBlockEntryTest::indirect_penter_dllmain_stub_ = NULL;
606 : FARPROC BasicBlockEntryTest::indirect_penter_exemain_stub_ = NULL;
607 :
608 : } // namespace
609 :
610 E : TEST_F(BasicBlockEntryTest, NoServerNoCrash) {
611 : // Configure for BasicBlock mode.
612 E : ConfigureBasicBlockAgent();
613 :
614 : // Load the agent dll.
615 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
616 :
617 : // Simulate the process attach event.
618 E : SimulateModuleEvent(DLL_PROCESS_ATTACH);
619 :
620 : // Validate that it only modified the tls_index and initialization_attempted
621 : // values.
622 E : ASSERT_EQ(::common::kBasicBlockEntryAgentId, common_data_->agent_id);
623 E : ASSERT_EQ(::common::kBasicBlockFrequencyDataVersion, common_data_->version);
624 E : ASSERT_EQ(IndexedFrequencyData::BASIC_BLOCK_ENTRY, common_data_->data_type);
625 E : ASSERT_NE(TLS_OUT_OF_INDEXES, module_data_.tls_index);
626 E : ASSERT_EQ(0U, module_data_.fs_slot);
627 E : ASSERT_NE(0U, common_data_->initialization_attempted);
628 E : ASSERT_EQ(kNumColumns, common_data_->num_columns);
629 E : ASSERT_EQ(kNumBasicBlocks, common_data_->num_entries);
630 E : ASSERT_EQ(default_frequency_data_, common_data_->frequency_data);
631 :
632 : // Visiting an initial basic-block should not fail. It should increment the
633 : // call count in the default array.
634 E : SimulateBasicBlockEntry(0);
635 E : ASSERT_EQ(1U, default_frequency_data_[0]);
636 E : ASSERT_EQ(0U, default_frequency_data_[1]);
637 :
638 : // Re-visiting the same basic-block should only update the frequency array.
639 E : DWORD new_tls_index = module_data_.tls_index;
640 E : SimulateBasicBlockEntry(0);
641 E : ASSERT_EQ(new_tls_index, module_data_.tls_index);
642 E : ASSERT_EQ(2U, default_frequency_data_[0]);
643 E : ASSERT_EQ(0U, default_frequency_data_[1]);
644 :
645 : // Visiting a different basic-block should only update the frequency array.
646 E : SimulateBasicBlockEntry(1);
647 E : ASSERT_EQ(new_tls_index, module_data_.tls_index);
648 E : ASSERT_EQ(2U, default_frequency_data_[0]);
649 E : ASSERT_EQ(1U, default_frequency_data_[1]);
650 :
651 : // FS-Slot must stay unchanged.
652 E : ASSERT_EQ(0U, module_data_.fs_slot);
653 :
654 : // Simulate the process detach event.
655 E : SimulateModuleEvent(DLL_PROCESS_DETACH);
656 :
657 : // Unload the DLL.
658 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
659 :
660 : // Replay the log. There should be none as we didn't start the service.
661 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(0));
662 E : }
663 :
664 E : TEST_F(BasicBlockEntryTest, SingleThreadedDllBasicBlockEvents) {
665 : // Configure for BasicBlock mode.
666 E : ConfigureBasicBlockAgent();
667 :
668 E : ASSERT_NO_FATAL_FAILURE(StartService());
669 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
670 :
671 : // Simulate the process attach event.
672 E : SimulateModuleEvent(DLL_PROCESS_ATTACH);
673 :
674 : // Validate that it does not modify any of our initialization values.
675 E : ASSERT_EQ(::common::kBasicBlockEntryAgentId, common_data_->agent_id);
676 E : ASSERT_EQ(::common::kBasicBlockFrequencyDataVersion, common_data_->version);
677 E : ASSERT_EQ(IndexedFrequencyData::BASIC_BLOCK_ENTRY, common_data_->data_type);
678 E : ASSERT_NE(TLS_OUT_OF_INDEXES, module_data_.tls_index);
679 E : ASSERT_EQ(0U, module_data_.fs_slot);
680 E : ASSERT_NE(0U, common_data_->initialization_attempted);
681 E : ASSERT_EQ(kNumColumns, common_data_->num_columns);
682 E : ASSERT_EQ(kNumBasicBlocks, common_data_->num_entries);
683 :
684 : // The frequency_data must be allocated and frequency_data must point to it.
685 E : ASSERT_NE(default_branch_data_, common_data_->frequency_data);
686 :
687 : // Visiting an initial basic-block should not fail.
688 E : SimulateBasicBlockEntry(0);
689 E : ASSERT_EQ(0U, default_frequency_data_[0]);
690 :
691 : // Make a few more calls, just to keep things interesting.
692 E : SimulateBasicBlockEntry(0);
693 E : SimulateBasicBlockEntry(1);
694 E : SimulateBasicBlockEntry(0);
695 :
696 : // Simulate the process detach event.
697 E : SimulateModuleEvent(DLL_PROCESS_DETACH);
698 :
699 : // Unload the DLL and stop the service.
700 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
701 :
702 E : HMODULE self = ::GetModuleHandle(NULL);
703 E : DWORD process_id = ::GetCurrentProcessId();
704 E : DWORD thread_id = ::GetCurrentThreadId();
705 :
706 : static const uint32 kExpectedFrequencyData[kNumBasicBlocks] = { 3, 1 };
707 :
708 : // Set up expectations for what should be in the trace.
709 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
710 : EXPECT_CALL(handler_, OnProcessAttach(_,
711 : process_id,
712 : thread_id,
713 E : ModuleAtAddress(self)));
714 : EXPECT_CALL(handler_, OnIndexedFrequency(
715 : _,
716 : process_id,
717 : thread_id,
718 E : FrequencyDataMatches(self, kNumBasicBlocks, kExpectedFrequencyData)));
719 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
720 :
721 : // Replay the log.
722 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(1));
723 E : }
724 :
725 E : TEST_F(BasicBlockEntryTest, SingleThreadedExeBasicBlockEvents) {
726 : // Configure for BasicBlock mode.
727 E : ConfigureBasicBlockAgent();
728 :
729 E : ASSERT_NO_FATAL_FAILURE(StartService());
730 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
731 :
732 : // Simulate the process attach event.
733 E : ExeMainThunk();
734 :
735 : // Validate that it does not modify any of our initialization values.
736 E : ASSERT_EQ(::common::kBasicBlockEntryAgentId, common_data_->agent_id);
737 E : ASSERT_EQ(::common::kBasicBlockFrequencyDataVersion, common_data_->version);
738 E : ASSERT_EQ(IndexedFrequencyData::BASIC_BLOCK_ENTRY, common_data_->data_type);
739 E : ASSERT_NE(TLS_OUT_OF_INDEXES, module_data_.tls_index);
740 E : ASSERT_EQ(0U, module_data_.fs_slot);
741 E : ASSERT_NE(0U, common_data_->initialization_attempted);
742 E : ASSERT_EQ(kNumColumns, common_data_->num_columns);
743 E : ASSERT_EQ(kNumBasicBlocks, common_data_->num_entries);
744 :
745 : // The frequency_data must be allocated and frequency_data must point to it.
746 E : ASSERT_NE(default_branch_data_, common_data_->frequency_data);
747 :
748 : // Visiting an initial basic-block should not fail.
749 E : SimulateBasicBlockEntry(0);
750 E : ASSERT_EQ(0U, default_frequency_data_[0]);
751 :
752 : // Make a few more calls, just to keep things interesting.
753 E : SimulateBasicBlockEntry(0);
754 E : SimulateBasicBlockEntry(1);
755 E : SimulateBasicBlockEntry(0);
756 :
757 : // Simulate the process detach event.
758 E : SimulateModuleEvent(DLL_PROCESS_DETACH);
759 :
760 : // Unload the DLL and stop the service.
761 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
762 :
763 E : HMODULE self = ::GetModuleHandle(NULL);
764 E : DWORD process_id = ::GetCurrentProcessId();
765 E : DWORD thread_id = ::GetCurrentThreadId();
766 :
767 : static const uint32 kExpectedFrequencyData[kNumBasicBlocks] = { 3, 1 };
768 :
769 : // Set up expectations for what should be in the trace.
770 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
771 : EXPECT_CALL(handler_, OnProcessAttach(_,
772 : process_id,
773 : thread_id,
774 E : ModuleAtAddress(self)));
775 : EXPECT_CALL(handler_, OnIndexedFrequency(
776 : _,
777 : process_id,
778 : thread_id,
779 E : FrequencyDataMatches(self, kNumBasicBlocks, kExpectedFrequencyData)));
780 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
781 :
782 : // Replay the log.
783 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(1));
784 E : }
785 :
786 E : TEST_F(BasicBlockEntryTest, SingleThreadedExeBranchEvents) {
787 : // Configure for Branch mode.
788 E : ConfigureBranchAgent();
789 :
790 E : ASSERT_NO_FATAL_FAILURE(StartService());
791 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
792 :
793 : // Simulate the process attach event.
794 E : ExeMainThunk();
795 :
796 : // Validate that it does not modify any of our initialization values.
797 E : ASSERT_EQ(::common::kBasicBlockEntryAgentId, common_data_->agent_id);
798 E : ASSERT_EQ(::common::kBasicBlockFrequencyDataVersion, common_data_->version);
799 E : ASSERT_EQ(IndexedFrequencyData::BRANCH, common_data_->data_type);
800 E : ASSERT_NE(TLS_OUT_OF_INDEXES, module_data_.tls_index);
801 E : ASSERT_EQ(0U, module_data_.fs_slot);
802 E : ASSERT_NE(0U, common_data_->initialization_attempted);
803 E : ASSERT_EQ(kNumBranchColumns, common_data_->num_columns);
804 E : ASSERT_EQ(kNumBasicBlocks, common_data_->num_entries);
805 :
806 : // The frequency_data must be allocated and frequency_data must point to it.
807 E : ASSERT_NE(default_branch_data_, common_data_->frequency_data);
808 :
809 : // Visiting an initial basic-block should not fail.
810 E : SimulateBranchEnter(0);
811 E : SimulateBranchExit(0);
812 E : ASSERT_NE(default_branch_data_, common_data_->frequency_data);
813 E : for (size_t i = 0; i < kNumBranchColumns; ++i) {
814 E : ASSERT_EQ(0U, default_branch_data_[i]);
815 E : }
816 :
817 : // Make a few more calls, just to keep things interesting.
818 E : SimulateBranchEnter(1);
819 E : SimulateBranchExit(1);
820 E : SimulateBranchEnter(0);
821 E : SimulateBranchExit(0);
822 E : SimulateBranchEnter(1);
823 E : SimulateBranchExit(1);
824 E : SimulateBranchEnter(0);
825 E : SimulateBranchExit(0);
826 E : for (int i = 0; i < 6; ++i) {
827 E : SimulateBranchEnter(1);
828 E : SimulateBranchExit(1);
829 E : }
830 E : for (int i = 0; i < 6; ++i) {
831 E : SimulateBranchEnter(0);
832 E : SimulateBranchExit(0);
833 E : }
834 :
835 : // Simulate the process detach event.
836 E : SimulateModuleEvent(DLL_PROCESS_DETACH);
837 :
838 : // Unload the DLL and stop the service.
839 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
840 :
841 E : HMODULE self = ::GetModuleHandle(NULL);
842 E : DWORD process_id = ::GetCurrentProcessId();
843 E : DWORD thread_id = ::GetCurrentThreadId();
844 :
845 : static const uint32 kExpectedBranchData[kNumBranchColumns * kNumBasicBlocks] =
846 : { 9, 5, 2, 8, 2, 2 };
847 :
848 : // Set up expectations for what should be in the trace.
849 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
850 : EXPECT_CALL(handler_, OnProcessAttach(_,
851 : process_id,
852 : thread_id,
853 E : ModuleAtAddress(self)));
854 E : const uint32 kNumData = kNumBranchColumns * kNumBasicBlocks;
855 : EXPECT_CALL(handler_, OnIndexedFrequency(
856 : _,
857 : process_id,
858 : thread_id,
859 E : FrequencyDataMatches(self, kNumData, kExpectedBranchData)));
860 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
861 :
862 : // Replay the log.
863 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(1));
864 E : }
865 :
866 E : TEST_F(BasicBlockEntryTest, BranchWithBufferingEvents) {
867 : // Configure for Branch mode.
868 E : ConfigureBranchAgent();
869 :
870 E : ASSERT_NO_FATAL_FAILURE(StartService());
871 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
872 :
873 : // Simulate the process attach event.
874 E : ExeMainThunk();
875 :
876 : // Visiting an initial basic-block should not fail.
877 E : SimulateBranchEnterBuffered(0);
878 E : SimulateBranchExit(0);
879 E : SimulateBranchEnterBuffered(1);
880 E : SimulateBranchExit(1);
881 E : ASSERT_NE(default_branch_data_, common_data_->frequency_data);
882 :
883 : // Keep a pointer to raw counters.
884 : uint32* frequency_data =
885 E : reinterpret_cast<uint32*>(common_data_->frequency_data);
886 :
887 : // Validate no events have been committed.
888 E : for (size_t i = 0; i < kNumBranchColumns; ++i) {
889 E : EXPECT_EQ(0U, frequency_data[i]);
890 E : }
891 :
892 : // Force a flush.
893 E : const int kBigEnoughToCauseAFlush = BasicBlockEntry::kBufferSize + 1;
894 E : for (int i = 0; i < kBigEnoughToCauseAFlush; ++i) {
895 E : SimulateBranchEnterBuffered(0);
896 E : SimulateBranchExit(0);
897 E : }
898 :
899 : // Validate some events are committed.
900 E : EXPECT_NE(0U, frequency_data[0 * kNumBranchColumns]);
901 : // Entering basic block 1 must be committed.
902 E : EXPECT_EQ(1U, frequency_data[1 * kNumBranchColumns]);
903 :
904 : // Force a flush.
905 E : uint32 old_count = frequency_data[0];
906 E : for (int i = 0; i < kBigEnoughToCauseAFlush; ++i) {
907 E : SimulateBranchEnterBuffered(0);
908 E : SimulateBranchExit(0);
909 E : }
910 :
911 : // Expect to have increasing values.
912 E : uint32 new_count = frequency_data[0];
913 E : EXPECT_LT(old_count, new_count);
914 :
915 E : ASSERT_NO_FATAL_FAILURE(StopService());
916 E : }
917 :
918 E : TEST_F(BasicBlockEntryTest, SingleExeBranchEvents) {
919 : ASSERT_NO_FATAL_FAILURE(
920 E : CheckExecution(kExeMain, kBranchInstrumentation));
921 E : }
922 :
923 E : TEST_F(BasicBlockEntryTest, SingleDllBranchEvents) {
924 : ASSERT_NO_FATAL_FAILURE(
925 E : CheckExecution(kDllMain, kBranchInstrumentation));
926 E : }
927 :
928 E : TEST_F(BasicBlockEntryTest, SingleExeBranchWithSlotEvents) {
929 : ASSERT_NO_FATAL_FAILURE(
930 E : CheckExecution(kExeMain, kBranchWithSlotInstrumentation));
931 E : }
932 :
933 E : TEST_F(BasicBlockEntryTest, SingleDllBranchWithSlotEvents) {
934 : ASSERT_NO_FATAL_FAILURE(
935 E : CheckExecution(kDllMain, kBranchWithSlotInstrumentation));
936 E : }
937 :
938 E : TEST_F(BasicBlockEntryTest, SingleExeBranchBufferedEvents) {
939 : ASSERT_NO_FATAL_FAILURE(
940 E : CheckExecution(kExeMain, kBufferedBranchInstrumentation));
941 E : }
942 :
943 E : TEST_F(BasicBlockEntryTest, SingleDllBranchBufferedEvents) {
944 : ASSERT_NO_FATAL_FAILURE(
945 E : CheckExecution(kDllMain, kBufferedBranchInstrumentation));
946 E : }
947 :
948 E : TEST_F(BasicBlockEntryTest, SingleExeBranchBufferedWithSlotEvents) {
949 : ASSERT_NO_FATAL_FAILURE(
950 E : CheckExecution(kExeMain, kBufferedBranchWithSlotInstrumentation));
951 E : }
952 :
953 E : TEST_F(BasicBlockEntryTest, SingleDllBranchBufferedWithSlotEvents) {
954 : ASSERT_NO_FATAL_FAILURE(
955 E : CheckExecution(kDllMain, kBufferedBranchWithSlotInstrumentation));
956 E : }
957 :
958 E : TEST_F(BasicBlockEntryTest, MultiThreadedDllBasicBlockEvents) {
959 : ASSERT_NO_FATAL_FAILURE(
960 E : CheckThreadExecution(kDllMain, kBasicBlockEntryInstrumentation));
961 E : }
962 :
963 E : TEST_F(BasicBlockEntryTest, MultiThreadedExeBasicBlockEvents) {
964 : ASSERT_NO_FATAL_FAILURE(
965 E : CheckThreadExecution(kExeMain, kBasicBlockEntryInstrumentation));
966 E : }
967 :
968 E : TEST_F(BasicBlockEntryTest, MultiThreadedDllBranchEvents) {
969 : ASSERT_NO_FATAL_FAILURE(
970 E : CheckThreadExecution(kDllMain, kBranchInstrumentation));
971 E : }
972 :
973 E : TEST_F(BasicBlockEntryTest, MultiThreadedExeBranchEvents) {
974 : ASSERT_NO_FATAL_FAILURE(
975 E : CheckThreadExecution(kExeMain, kBranchInstrumentation));
976 E : }
977 :
978 E : TEST_F(BasicBlockEntryTest, MultiThreadedDllBranchWithSlotEvents) {
979 : ASSERT_NO_FATAL_FAILURE(
980 E : CheckThreadExecution(kDllMain, kBranchWithSlotInstrumentation));
981 E : }
982 :
983 E : TEST_F(BasicBlockEntryTest, MultiThreadedExeBranchWithSlotEvents) {
984 : ASSERT_NO_FATAL_FAILURE(
985 E : CheckThreadExecution(kExeMain, kBranchWithSlotInstrumentation));
986 E : }
987 :
988 E : TEST_F(BasicBlockEntryTest, MultiThreadedDllBufferedBranchEvents) {
989 : ASSERT_NO_FATAL_FAILURE(
990 E : CheckThreadExecution(kDllMain, kBufferedBranchInstrumentation));
991 E : }
992 :
993 E : TEST_F(BasicBlockEntryTest, MultiThreadedExeBufferedBranchEvents) {
994 : ASSERT_NO_FATAL_FAILURE(
995 E : CheckThreadExecution(kExeMain, kBufferedBranchInstrumentation));
996 E : }
997 :
998 E : TEST_F(BasicBlockEntryTest, MultiThreadedDllBufferedBranchWithSlotEvents) {
999 : ASSERT_NO_FATAL_FAILURE(
1000 E : CheckThreadExecution(kDllMain, kBufferedBranchWithSlotInstrumentation));
1001 E : }
1002 :
1003 E : TEST_F(BasicBlockEntryTest, MultiThreadedExeBufferedBranchWithSlotEvents) {
1004 : ASSERT_NO_FATAL_FAILURE(
1005 E : CheckThreadExecution(kExeMain, kBufferedBranchWithSlotInstrumentation));
1006 E : }
1007 :
1008 : } // namespace basic_block_entry
1009 : } // namespace agent
|