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