1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/trace/parse/parse_engine.h"
16 :
17 : #include <windows.h> // NOLINT
18 : #include <wmistr.h> // NOLINT
19 : #include <evntrace.h>
20 :
21 : #include <set>
22 : #include <vector>
23 :
24 : #include "base/logging.h"
25 : #include "gmock/gmock.h"
26 : #include "gtest/gtest.h"
27 : #include "syzygy/common/indexed_frequency_data.h"
28 : #include "syzygy/trace/parse/parser.h"
29 :
30 : namespace {
31 :
32 : using testing::_;
33 : using trace::parser::Parser;
34 : using trace::parser::ParseEngine;
35 : using trace::parser::ParseEventHandler;
36 : using trace::parser::ModuleInformation;
37 :
38 : typedef std::multiset<FuncAddr> FunctionSet;
39 : typedef std::vector<TraceModuleData> ModuleSet;
40 :
41 : class ParseEngineUnitTest
42 : : public testing::Test,
43 : public ParseEngine,
44 : public ParseEventHandler {
45 : public:
46 : ParseEngineUnitTest()
47 : : ParseEngine("Test", true),
48 : basic_block_frequencies(0),
49 E : expected_data(NULL) {
50 E : ::memset(&event_record_, 0, sizeof(event_record_));
51 E : set_event_handler(this);
52 E : }
53 :
54 E : ~ParseEngineUnitTest() {
55 E : }
56 :
57 E : void DispatchEventData(TraceEventType type, const void* data, size_t size) {
58 E : ::memset(&event_record_, 0, sizeof(event_record_));
59 E : event_record_.Header.ProcessId = kProcessId;
60 E : event_record_.Header.ThreadId = kThreadId;
61 E : event_record_.Header.Guid = kCallTraceEventClass;
62 E : event_record_.Header.Class.Type = type;
63 E : event_record_.MofData = const_cast<void*>(data);
64 E : event_record_.MofLength = size;
65 :
66 E : ASSERT_TRUE(DispatchEvent(&event_record_));
67 E : }
68 :
69 i : bool IsRecognizedTraceFile(const base::FilePath& trace_file_path) OVERRIDE {
70 i : return true;
71 i : }
72 :
73 i : bool OpenTraceFile(const base::FilePath& trace_file_path) OVERRIDE {
74 i : return true;
75 i : }
76 :
77 i : virtual bool ConsumeAllEvents() {
78 i : return true;
79 i : }
80 :
81 i : virtual bool CloseAllTraceFiles() {
82 i : return true;
83 i : }
84 :
85 : // ParseEventHander methods.
86 :
87 : virtual void OnProcessStarted(base::Time time,
88 : DWORD process_id,
89 i : const TraceSystemInfo* data) OVERRIDE {
90 i : ASSERT_EQ(process_id, kProcessId);
91 i : }
92 :
93 i : virtual void OnProcessEnded(base::Time time, DWORD process_id) OVERRIDE {
94 i : ASSERT_EQ(process_id, kProcessId);
95 i : }
96 :
97 : virtual void OnFunctionEntry(base::Time time,
98 : DWORD process_id,
99 : DWORD thread_id,
100 E : const TraceEnterExitEventData* data) OVERRIDE {
101 E : ASSERT_EQ(process_id, kProcessId);
102 E : ASSERT_EQ(thread_id, kThreadId);
103 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
104 E : EXPECT_TRUE(data->function != NULL);
105 E : function_entries.insert(data->function);
106 E : }
107 :
108 : virtual void OnFunctionExit(base::Time time,
109 : DWORD process_id,
110 : DWORD thread_id,
111 E : const TraceEnterExitEventData* data) OVERRIDE {
112 E : ASSERT_EQ(process_id, kProcessId);
113 E : ASSERT_EQ(thread_id, kThreadId);
114 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
115 E : EXPECT_TRUE(data->function != NULL);
116 E : function_exits.insert(data->function);
117 E : }
118 :
119 : virtual void OnBatchFunctionEntry(base::Time time,
120 : DWORD process_id,
121 : DWORD thread_id,
122 E : const TraceBatchEnterData* data) OVERRIDE {
123 E : ASSERT_EQ(process_id, kProcessId);
124 E : ASSERT_EQ(thread_id, kThreadId);
125 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
126 E : for (size_t i = 0; i < data->num_calls; ++i) {
127 E : function_entries.insert(data->calls[i].function);
128 E : }
129 E : }
130 :
131 : virtual void OnProcessAttach(base::Time time,
132 : DWORD process_id,
133 : DWORD thread_id,
134 E : const TraceModuleData* data) OVERRIDE {
135 E : ASSERT_EQ(process_id, kProcessId);
136 E : ASSERT_EQ(thread_id, kThreadId);
137 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
138 E : process_attaches.push_back(*data);
139 E : }
140 :
141 : virtual void OnProcessDetach(base::Time time,
142 : DWORD process_id,
143 : DWORD thread_id,
144 E : const TraceModuleData* data) OVERRIDE {
145 E : ASSERT_EQ(process_id, kProcessId);
146 E : ASSERT_EQ(thread_id, kThreadId);
147 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
148 E : process_detaches.push_back(*data);
149 E : }
150 :
151 : virtual void OnThreadAttach(base::Time time,
152 : DWORD process_id,
153 : DWORD thread_id,
154 E : const TraceModuleData* data) OVERRIDE {
155 E : ASSERT_EQ(process_id, kProcessId);
156 E : ASSERT_EQ(thread_id, kThreadId);
157 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
158 E : thread_attaches.push_back(*data);
159 E : }
160 :
161 : // Issued for DLL_THREAD_DETACH on an instrumented module.
162 : virtual void OnThreadDetach(base::Time time,
163 : DWORD process_id,
164 : DWORD thread_id,
165 E : const TraceModuleData* data) OVERRIDE {
166 E : ASSERT_EQ(process_id, kProcessId);
167 E : ASSERT_EQ(thread_id, kThreadId);
168 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
169 E : thread_detaches.push_back(*data);
170 E : }
171 :
172 : virtual void OnInvocationBatch(
173 : base::Time time, DWORD process_id, DWORD thread_id,
174 i : size_t num_invocations, const TraceBatchInvocationInfo* data) OVERRIDE {
175 : // TODO(anyone): Test this.
176 i : }
177 :
178 : virtual void OnIndexedFrequency(
179 : base::Time time,
180 : DWORD process_id,
181 : DWORD thread_id,
182 E : const TraceIndexedFrequencyData* data) OVERRIDE {
183 E : ASSERT_EQ(process_id, kProcessId);
184 E : ASSERT_EQ(thread_id, kThreadId);
185 E : ASSERT_TRUE(reinterpret_cast<const void*>(data) == expected_data);
186 E : ++basic_block_frequencies;
187 E : }
188 :
189 : MOCK_METHOD4(OnThreadName,
190 : void(base::Time time, DWORD process_id, DWORD thread_id,
191 i : const base::StringPiece& thread_name));
192 : MOCK_METHOD3(OnDynamicSymbol,
193 : void(DWORD process_id, uint32 symbol_id,
194 E : const base::StringPiece& symbol_name));
195 : MOCK_METHOD3(OnSampleData,
196 : void(base::Time time,
197 : DWORD process_id,
198 E : const TraceSampleData* data));
199 : MOCK_METHOD3(OnFunctionNameTableEntry,
200 : void(base::Time time,
201 : DWORD process_id,
202 E : const TraceFunctionNameTableEntry* data));
203 : MOCK_METHOD3(OnStackTrace,
204 : void(base::Time time,
205 : DWORD process_id,
206 E : const TraceStackTrace* data));
207 : MOCK_METHOD4(OnDetailedFunctionCall,
208 : void(base::Time time,
209 : DWORD process_id,
210 : DWORD thread_id,
211 E : const TraceDetailedFunctionCall* data));
212 : MOCK_METHOD3(OnComment,
213 : void(base::Time time,
214 : DWORD process_id,
215 E : const TraceComment* data));
216 :
217 : static const DWORD kProcessId;
218 : static const DWORD kThreadId;
219 : static const ModuleInformation kExeInfo;
220 : static const ModuleInformation kDllInfo;
221 : static const TraceModuleData kModuleData;
222 : static const TraceIndexedFrequencyData kIndexedFrequencyData;
223 : static const TraceIndexedFrequencyData kShortIndexedFrequencyData;
224 :
225 : EVENT_TRACE event_record_;
226 :
227 : FunctionSet function_entries;
228 : FunctionSet function_exits;
229 : ModuleSet process_attaches;
230 : ModuleSet process_detaches;
231 : ModuleSet thread_attaches;
232 : ModuleSet thread_detaches;
233 : size_t basic_block_frequencies;
234 :
235 : const void* expected_data;
236 : };
237 :
238 : const DWORD ParseEngineUnitTest::kProcessId = 0xAAAAAAAA;
239 :
240 : const DWORD ParseEngineUnitTest::kThreadId = 0xBBBBBBBB;
241 :
242 : const ModuleInformation ParseEngineUnitTest::kExeInfo(
243 : L"file_name.exe", pe::PEFile::AbsoluteAddress(0x11111111), 0x22222222,
244 E : 0x33333333, 0x44444444);
245 :
246 : const ModuleInformation ParseEngineUnitTest::kDllInfo(
247 : L"file_name.dll", pe::PEFile::AbsoluteAddress(0x55555555), 0x66666666,
248 E : 0x77777777, 0x88888888);
249 :
250 : const TraceModuleData ParseEngineUnitTest::kModuleData = {
251 : reinterpret_cast<ModuleAddr>(0x99999999),
252 : 0x11111111,
253 : 0x22222222,
254 : 0x33333333,
255 : L"module",
256 : L"executable" };
257 :
258 : const TraceIndexedFrequencyData ParseEngineUnitTest::kIndexedFrequencyData = {
259 : reinterpret_cast<ModuleAddr>(0x11111111),
260 : 0x22222222,
261 : 0x33333333,
262 : 0x44444444,
263 : 1,
264 : 1,
265 : common::IndexedFrequencyData::BASIC_BLOCK_ENTRY,
266 : 1,
267 : 0 };
268 :
269 : // This indexed frequency struct does not contain enough data for its implicitly
270 : // encoded length.
271 : const TraceIndexedFrequencyData
272 : ParseEngineUnitTest::kShortIndexedFrequencyData = {
273 : reinterpret_cast<ModuleAddr>(0x11111111),
274 : 0x22222222,
275 : 0x33333333,
276 : 0x44444444,
277 : 10,
278 : 1,
279 : common::IndexedFrequencyData::BASIC_BLOCK_ENTRY,
280 : 4,
281 : 0 };
282 :
283 : // A test function to show up in the trace events.
284 i : void TestFunc1() {
285 i : ::Sleep(100);
286 i : }
287 :
288 : // Another test function to show up in the trace events.
289 i : void TestFunc2() {
290 i : ::time(NULL);
291 i : }
292 :
293 E : TEST_F(ParseEngineUnitTest, ModuleInfo) {
294 E : const ModuleInformation* module_info = NULL;
295 :
296 : // Insert the module information.
297 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kExeInfo));
298 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kDllInfo));
299 E : ASSERT_EQ(1, processes_.size());
300 E : ASSERT_EQ(2, processes_[kProcessId].size());
301 :
302 : // Multiple identical insertions should be ok.
303 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kDllInfo));
304 E : ASSERT_EQ(2, processes_[kProcessId].size());
305 :
306 : // Intersecting but not identical insertions should fail if disallowed.
307 E : ModuleInformation bad_dll_info(kDllInfo);
308 E : bad_dll_info.base_address += 100;
309 E : ASSERT_TRUE(fail_on_module_conflict_);
310 E : ASSERT_FALSE(AddModuleInformation(kProcessId, bad_dll_info));
311 E : ASSERT_EQ(2, processes_[kProcessId].size());
312 :
313 : // If conflicting module info is non-fatal, insertions should appear to
314 : // succeed but not actually happen.
315 E : fail_on_module_conflict_ = false;
316 E : ASSERT_TRUE(AddModuleInformation(kProcessId, bad_dll_info));
317 E : ASSERT_EQ(2, processes_[kProcessId].size());
318 E : fail_on_module_conflict_ = true;
319 :
320 : // Search for unknown process.
321 : module_info = GetModuleInformation(
322 E : kProcessId + 1, kExeInfo.base_address.value());
323 E : ASSERT_TRUE(module_info == NULL);
324 :
325 : // Search before exe start address
326 E : const int kBeforeOffset = -1;
327 : module_info = GetModuleInformation(
328 E : kProcessId, kExeInfo.base_address.value() + kBeforeOffset);
329 E : ASSERT_TRUE(module_info == NULL);
330 :
331 : // Search after exe end address.
332 E : const size_t kAfterOffset = kExeInfo.module_size;
333 : module_info = GetModuleInformation(
334 E : kProcessId, kExeInfo.base_address.value() + kAfterOffset);
335 E : ASSERT_TRUE(module_info == NULL);
336 :
337 : // Get exe module by start address.
338 E : const size_t kStartOffset = 0;
339 : module_info = GetModuleInformation(
340 E : kProcessId, kExeInfo.base_address.value() + kStartOffset);
341 E : ASSERT_TRUE(module_info != NULL);
342 E : ASSERT_TRUE(*module_info == kExeInfo);
343 :
344 : // Get exe module by address somewhere in the middle.
345 E : const size_t kMiddleOffset = kExeInfo.module_size / 2;
346 : module_info = GetModuleInformation(
347 E : kProcessId, kExeInfo.base_address.value() + kMiddleOffset);
348 E : ASSERT_TRUE(module_info != NULL);
349 E : ASSERT_TRUE(*module_info == kExeInfo);
350 :
351 : // Get exe module by address at the end.
352 E : const size_t kEndOffset = kExeInfo.module_size - 1;
353 : module_info = GetModuleInformation(
354 E : kProcessId, kExeInfo.base_address.value() + kEndOffset);
355 E : ASSERT_TRUE(module_info != NULL);
356 E : ASSERT_TRUE(*module_info == kExeInfo);
357 :
358 : // We only remove modules from a given process if a conflicting module is
359 : // loaded after the module has been marked as dirty. This is because (1) we
360 : // don't guarantee temporal order of all events in a process, so you
361 : // might parse a function event after seeing the module get unloaded
362 : // if the buffers are flushed in that order; and (2) because process ids may
363 : // be reused (but not concurrently) so we do want to drop stale module info
364 : // when the process has been replaced.
365 :
366 : // Get dll module by address somewhere in the middle, then remove it and
367 : // see that it's STILL found by that address.
368 E : const size_t kDllOffset = kDllInfo.module_size / 2;
369 : module_info = GetModuleInformation(
370 E : kProcessId, kDllInfo.base_address.value() + kDllOffset);
371 E : ASSERT_TRUE(module_info != NULL);
372 E : ASSERT_TRUE(*module_info == kDllInfo);
373 E : ASSERT_TRUE(RemoveModuleInformation(kProcessId, kDllInfo));
374 E : ASSERT_EQ(2, processes_[kProcessId].size());
375 : module_info = GetModuleInformation(
376 E : kProcessId, kDllInfo.base_address.value() + kDllOffset);
377 E : ASSERT_TRUE(module_info != NULL);
378 E : ASSERT_TRUE(*module_info == kDllInfo);
379 :
380 : // Add conflicting module information and see that the old module is gone.
381 E : ModuleInformation new_dll_info(kDllInfo);
382 E : new_dll_info.base_address += 4;
383 E : ASSERT_TRUE(AddModuleInformation(kProcessId, new_dll_info));
384 E : ASSERT_EQ(2, processes_[kProcessId].size());
385 : module_info = GetModuleInformation(
386 E : kProcessId, kDllInfo.base_address.value());
387 E : ASSERT_TRUE(module_info == NULL);
388 : module_info = GetModuleInformation(
389 E : kProcessId, new_dll_info.base_address.value());
390 E : ASSERT_TRUE(module_info != NULL);
391 E : ASSERT_TRUE(*module_info == new_dll_info);
392 E : }
393 :
394 E : TEST_F(ParseEngineUnitTest, UnhandledEvent) {
395 E : EVENT_TRACE local_record = {};
396 E : ASSERT_FALSE(DispatchEvent(&local_record));
397 :
398 E : local_record.Header.ProcessId = kProcessId;
399 E : local_record.Header.ThreadId = kThreadId;
400 E : local_record.Header.Guid = kCallTraceEventClass;
401 E : local_record.Header.Class.Type = 0xFF; // Invalid value.
402 E : ASSERT_TRUE(DispatchEvent(&local_record));
403 E : ASSERT_TRUE(error_occurred());
404 E : }
405 :
406 E : TEST_F(ParseEngineUnitTest, FunctionEntryEvents) {
407 E : TraceEnterEventData event_data = {};
408 E : event_data.function = &TestFunc1;
409 E : expected_data = &event_data;
410 :
411 : ASSERT_NO_FATAL_FAILURE(
412 E : DispatchEventData(TRACE_ENTER_EVENT, &event_data, sizeof(event_data)));
413 E : ASSERT_FALSE(error_occurred());
414 : ASSERT_NO_FATAL_FAILURE(
415 E : DispatchEventData(TRACE_ENTER_EVENT, &event_data, sizeof(event_data)));
416 E : ASSERT_FALSE(error_occurred());
417 E : ASSERT_EQ(function_entries.size(), 2);
418 E : ASSERT_EQ(function_entries.count(&TestFunc1), 2);
419 :
420 : // Check for short event data.
421 : ASSERT_NO_FATAL_FAILURE(
422 : DispatchEventData(TRACE_ENTER_EVENT,
423 : &event_data,
424 E : sizeof(TraceEnterEventData) - 1));
425 E : ASSERT_TRUE(error_occurred());
426 E : }
427 :
428 E : TEST_F(ParseEngineUnitTest, FunctionExitEvents) {
429 E : TraceExitEventData event_data = {};
430 E : event_data.function = &TestFunc2;
431 E : expected_data = &event_data;
432 :
433 : ASSERT_NO_FATAL_FAILURE(
434 E : DispatchEventData(TRACE_EXIT_EVENT, &event_data, sizeof(event_data)));
435 E : ASSERT_FALSE(error_occurred());
436 : ASSERT_NO_FATAL_FAILURE(
437 E : DispatchEventData(TRACE_EXIT_EVENT, &event_data, sizeof(event_data)));
438 E : ASSERT_FALSE(error_occurred());
439 E : ASSERT_EQ(function_exits.size(), 2);
440 E : ASSERT_EQ(function_exits.count(&TestFunc2), 2);
441 :
442 : // Check for short event data.
443 : ASSERT_NO_FATAL_FAILURE(
444 : DispatchEventData(TRACE_EXIT_EVENT,
445 : &event_data,
446 E : sizeof(TraceEnterEventData) - 1));
447 E : ASSERT_TRUE(error_occurred());
448 E : }
449 :
450 E : TEST_F(ParseEngineUnitTest, BatchFunctionEntry) {
451 : uint8 raw_data[sizeof(TraceBatchEnterData) +
452 E : 4 * sizeof(TraceEnterEventData)] = {};
453 : TraceBatchEnterData& event_data =
454 E : *reinterpret_cast<TraceBatchEnterData*>(&raw_data);
455 E : event_data.thread_id = kThreadId;
456 E : event_data.num_calls = 5;
457 E : event_data.calls[0].function = &TestFunc1;
458 E : event_data.calls[1].function = &TestFunc2;
459 E : event_data.calls[2].function = &TestFunc1;
460 E : event_data.calls[3].function = &TestFunc2;
461 E : event_data.calls[4].function = NULL;
462 E : expected_data = &raw_data;
463 :
464 : ASSERT_NO_FATAL_FAILURE(
465 E : DispatchEventData(TRACE_BATCH_ENTER, &raw_data, sizeof(raw_data)));
466 E : ASSERT_FALSE(error_occurred());
467 : ASSERT_NO_FATAL_FAILURE(
468 E : DispatchEventData(TRACE_BATCH_ENTER, &raw_data, sizeof(raw_data)));
469 E : ASSERT_FALSE(error_occurred());
470 E : ASSERT_EQ(function_entries.size(), 8);
471 E : ASSERT_EQ(function_entries.count(&TestFunc1), 4);
472 E : ASSERT_EQ(function_entries.count(&TestFunc2), 4);
473 :
474 : // Check for short event header.
475 : ASSERT_NO_FATAL_FAILURE(
476 : DispatchEventData(TRACE_BATCH_ENTER,
477 : &raw_data,
478 E : FIELD_OFFSET(TraceBatchEnterData, num_calls)));
479 E : ASSERT_TRUE(error_occurred());
480 :
481 : // Check for short event tail (remove the empty record + one byte).
482 E : set_error_occurred(false);
483 : ASSERT_NO_FATAL_FAILURE(
484 : DispatchEventData(TRACE_BATCH_ENTER,
485 : &raw_data,
486 E : sizeof(raw_data) - sizeof(TraceEnterEventData) - 1));
487 E : ASSERT_TRUE(error_occurred());
488 E : }
489 :
490 E : TEST_F(ParseEngineUnitTest, ProcessAttachIncomplete) {
491 E : TraceModuleData incomplete(kModuleData);
492 E : incomplete.module_base_addr = NULL;
493 :
494 : // No error should be reported for NULL module addr, instead the record
495 : // should be ignored.
496 E : expected_data = &kModuleData;
497 : ASSERT_NO_FATAL_FAILURE(
498 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
499 : &incomplete,
500 E : sizeof(incomplete)));
501 :
502 E : ASSERT_FALSE(error_occurred());
503 E : ASSERT_EQ(process_attaches.size(), 0);
504 E : }
505 :
506 E : TEST_F(ParseEngineUnitTest, ProcessAttach) {
507 E : expected_data = &kModuleData;
508 :
509 : ASSERT_NO_FATAL_FAILURE(
510 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
511 : &kModuleData,
512 E : sizeof(kModuleData)));
513 E : ASSERT_FALSE(error_occurred());
514 E : ASSERT_EQ(process_attaches.size(), 1);
515 :
516 : // Check for short module event.
517 : ASSERT_NO_FATAL_FAILURE(
518 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
519 : &kModuleData,
520 E : sizeof(kModuleData) - 1));
521 E : ASSERT_TRUE(error_occurred());
522 E : }
523 :
524 E : TEST_F(ParseEngineUnitTest, ProcessDetach) {
525 E : expected_data = &kModuleData;
526 :
527 : ASSERT_NO_FATAL_FAILURE(
528 : DispatchEventData(TRACE_PROCESS_DETACH_EVENT,
529 : &kModuleData,
530 E : sizeof(kModuleData)));
531 E : ASSERT_FALSE(error_occurred());
532 E : ASSERT_EQ(process_detaches.size(), 1);
533 :
534 : // Check for short module event.
535 : ASSERT_NO_FATAL_FAILURE(
536 : DispatchEventData(TRACE_PROCESS_DETACH_EVENT,
537 : &kModuleData,
538 E : sizeof(kModuleData) - 1));
539 E : ASSERT_TRUE(error_occurred());
540 E : }
541 :
542 E : TEST_F(ParseEngineUnitTest, ThreadAttach) {
543 E : expected_data = &kModuleData;
544 :
545 : ASSERT_NO_FATAL_FAILURE(
546 : DispatchEventData(TRACE_THREAD_ATTACH_EVENT,
547 : &kModuleData,
548 E : sizeof(kModuleData)));
549 E : ASSERT_FALSE(error_occurred());
550 E : ASSERT_EQ(thread_attaches.size(), 1);
551 :
552 : // Check for short module event.
553 : ASSERT_NO_FATAL_FAILURE(
554 : DispatchEventData(TRACE_THREAD_ATTACH_EVENT,
555 : &kModuleData,
556 E : sizeof(kModuleData) - 1));
557 E : ASSERT_TRUE(error_occurred());
558 E : }
559 :
560 E : TEST_F(ParseEngineUnitTest, ThreadDetach) {
561 E : expected_data = &kModuleData;
562 :
563 : ASSERT_NO_FATAL_FAILURE(
564 : DispatchEventData(TRACE_THREAD_DETACH_EVENT,
565 : &kModuleData,
566 E : sizeof(kModuleData)));
567 E : ASSERT_FALSE(error_occurred());
568 E : ASSERT_EQ(thread_detaches.size(), 1);
569 :
570 : // Check for short module event.
571 : ASSERT_NO_FATAL_FAILURE(
572 : DispatchEventData(TRACE_THREAD_DETACH_EVENT,
573 : &kModuleData,
574 E : sizeof(kModuleData) - 1));
575 E : ASSERT_TRUE(error_occurred());
576 E : }
577 :
578 E : TEST_F(ParseEngineUnitTest, IndexedFrequencyTooSmallForHeader) {
579 : ASSERT_NO_FATAL_FAILURE(
580 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
581 : &kIndexedFrequencyData,
582 E : sizeof(kIndexedFrequencyData) - 1));
583 :
584 E : ASSERT_TRUE(error_occurred());
585 E : ASSERT_EQ(basic_block_frequencies, 0);
586 E : }
587 :
588 E : TEST_F(ParseEngineUnitTest, IndexedFrequencyTooSmallForContents) {
589 : ASSERT_NO_FATAL_FAILURE(
590 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
591 : &kShortIndexedFrequencyData,
592 E : sizeof(kShortIndexedFrequencyData)));
593 :
594 E : ASSERT_TRUE(error_occurred());
595 E : ASSERT_EQ(basic_block_frequencies, 0);
596 E : }
597 :
598 E : TEST_F(ParseEngineUnitTest, IndexedFrequency) {
599 E : expected_data = &kIndexedFrequencyData;
600 : ASSERT_NO_FATAL_FAILURE(
601 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
602 : &kIndexedFrequencyData,
603 E : sizeof(kIndexedFrequencyData)));
604 E : ASSERT_FALSE(error_occurred());
605 E : ASSERT_EQ(basic_block_frequencies, 1);
606 E : }
607 :
608 E : TEST_F(ParseEngineUnitTest, DynamicSymbol) {
609 : static const char kSymbolName[] = "aDynamicSymbol";
610 E : const uint32 kSymbolId = 0x17459A;
611 : char data[FIELD_OFFSET(TraceDynamicSymbol, symbol_name) +
612 : sizeof(kSymbolName)];
613 E : TraceDynamicSymbol* symbol = reinterpret_cast<TraceDynamicSymbol*>(data);
614 E : symbol->symbol_id = kSymbolId;
615 E : ::memcpy(symbol->symbol_name, kSymbolName, sizeof(kSymbolName));
616 :
617 : // Dispatch a valid dynamic symbol record.
618 : EXPECT_CALL(*this,
619 E : OnDynamicSymbol(kProcessId, kSymbolId, base::StringPiece(kSymbolName)));
620 : ASSERT_NO_FATAL_FAILURE(
621 E : DispatchEventData(TRACE_DYNAMIC_SYMBOL, data, sizeof(data)));
622 E : ASSERT_FALSE(error_occurred());
623 :
624 : // Dispatch a short symbol record, make sure we err out.
625 : ASSERT_NO_FATAL_FAILURE(
626 : DispatchEventData(TRACE_DYNAMIC_SYMBOL,
627 : data,
628 E : FIELD_OFFSET(TraceDynamicSymbol, symbol_name) - 1));
629 E : ASSERT_TRUE(error_occurred());
630 E : }
631 :
632 E : TEST_F(ParseEngineUnitTest, SampleData) {
633 E : const uint32 kBucketCount = 42;
634 : char buffer[FIELD_OFFSET(TraceSampleData, buckets) +
635 E : kBucketCount * sizeof(uint32)] = {};
636 E : TraceSampleData* data = reinterpret_cast<TraceSampleData*>(buffer);
637 :
638 E : data->module_base_addr = reinterpret_cast<ModuleAddr>(0x01000000);
639 E : data->module_size = 32 * 1024 * 1024;
640 E : data->module_checksum = 0xDEADF00D;
641 E : data->module_time_date_stamp = 0x12345678;
642 E : data->bucket_size = 4;
643 E : data->bucket_start = reinterpret_cast<ModuleAddr>(0x01001000);
644 E : data->bucket_count = kBucketCount;
645 E : data->sampling_start_time = 0x0102030405060708;
646 E : data->sampling_end_time = 0x0203040506070809;
647 E : data->sampling_interval = 0x10000;
648 :
649 E : for (size_t i = 0; i < kBucketCount; ++i)
650 E : data->buckets[i] = i;
651 :
652 E : EXPECT_CALL(*this, OnSampleData(_, kProcessId, data));
653 : ASSERT_NO_FATAL_FAILURE(
654 E : DispatchEventData(TRACE_SAMPLE_DATA, data, sizeof(buffer)));
655 E : ASSERT_FALSE(error_occurred());
656 :
657 : // Dispatch a malformed record and make sure the parser errors.
658 : ASSERT_NO_FATAL_FAILURE(
659 E : DispatchEventData(TRACE_SAMPLE_DATA, data, sizeof(buffer) - 1));
660 E : ASSERT_TRUE(error_occurred());
661 E : }
662 :
663 E : TEST_F(ParseEngineUnitTest, FunctionNameTableEntry) {
664 E : const char kDummyFunctionName[] = "DummyFunction";
665 : char buffer[FIELD_OFFSET(TraceFunctionNameTableEntry, name) +
666 E : arraysize(kDummyFunctionName)] = {};
667 : TraceFunctionNameTableEntry* data =
668 E : reinterpret_cast<TraceFunctionNameTableEntry*>(buffer);
669 :
670 E : data->function_id = 37;
671 E : data->name_length = arraysize(kDummyFunctionName);
672 E : ::strcpy(data->name, kDummyFunctionName);
673 :
674 E : EXPECT_CALL(*this, OnFunctionNameTableEntry(_, kProcessId, data));
675 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
676 E : TRACE_FUNCTION_NAME_TABLE_ENTRY, data, sizeof(buffer)));
677 E : ASSERT_FALSE(error_occurred());
678 :
679 : // Dispatch a malformed record and make sure the parser errors.
680 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
681 E : TRACE_FUNCTION_NAME_TABLE_ENTRY, data, sizeof(buffer) - 1));
682 E : ASSERT_TRUE(error_occurred());
683 E : }
684 :
685 E : TEST_F(ParseEngineUnitTest, StackTrace) {
686 : char buffer[FIELD_OFFSET(TraceStackTrace, frames) +
687 E : sizeof(void*) * 4] = {};
688 : TraceStackTrace* data =
689 E : reinterpret_cast<TraceStackTrace*>(buffer);
690 :
691 E : data->stack_trace_id = 42;
692 E : data->num_frames = 4;
693 E : data->frames[0] = reinterpret_cast<void*>(0xDEADBEEF);
694 E : data->frames[1] = reinterpret_cast<void*>(0x900DF00D);
695 E : data->frames[2] = reinterpret_cast<void*>(0xCAFEBABE);
696 E : data->frames[3] = reinterpret_cast<void*>(0x00031337);
697 :
698 E : EXPECT_CALL(*this, OnStackTrace(_, kProcessId, data));
699 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
700 E : TRACE_STACK_TRACE, data, sizeof(buffer)));
701 E : ASSERT_FALSE(error_occurred());
702 :
703 : // Dispatch a malformed record and make sure the parser errors.
704 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
705 E : TRACE_STACK_TRACE, data, sizeof(buffer) - 1));
706 E : ASSERT_TRUE(error_occurred());
707 E : }
708 :
709 E : TEST_F(ParseEngineUnitTest, DetailedFunctionCall) {
710 : const uint8 kDummyArguments[] = {
711 : 0x02, 0x00, 0x00, 0x00, // 2 aguments
712 : 0x04, 0x00, 0x00, 0x00, // Argument 0 length 4.
713 : 0x01, 0x00, 0x00, 0x00, // Argument 1 length 1.
714 : 0xDE, 0xAD, 0xBE, 0xEF, // Argument 0: 0xDEADBEEF.
715 : 'A' // Argument 1: 'A'
716 E : };
717 : char buffer[FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
718 E : arraysize(kDummyArguments)] = {};
719 : TraceDetailedFunctionCall* data =
720 E : reinterpret_cast<TraceDetailedFunctionCall*>(buffer);
721 :
722 E : data->timestamp = 0x0102030405060708;
723 E : data->function_id = 37;
724 E : data->argument_data_size = arraysize(kDummyArguments);
725 E : ::memcpy(data->argument_data, kDummyArguments, arraysize(kDummyArguments));
726 :
727 E : EXPECT_CALL(*this, OnDetailedFunctionCall(_, kProcessId, kThreadId, data));
728 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
729 E : TRACE_DETAILED_FUNCTION_CALL, data, sizeof(buffer)));
730 E : ASSERT_FALSE(error_occurred());
731 :
732 : // Dispatch a malformed record and make sure the parser errors.
733 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
734 E : TRACE_DETAILED_FUNCTION_CALL, data, sizeof(buffer) - 1));
735 E : ASSERT_TRUE(error_occurred());
736 E : }
737 :
738 E : TEST_F(ParseEngineUnitTest, Comment) {
739 E : const char kDummyComment[] = "This is a comment!";
740 : char buffer[FIELD_OFFSET(TraceComment, comment) +
741 E : arraysize(kDummyComment)] = {};
742 : TraceComment* data =
743 E : reinterpret_cast<TraceComment*>(buffer);
744 :
745 E : data->comment_size = arraysize(kDummyComment);
746 E : ::memcpy(data->comment, kDummyComment, arraysize(kDummyComment));
747 :
748 E : EXPECT_CALL(*this, OnComment(_, kProcessId, data));
749 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
750 E : TRACE_COMMENT, data, sizeof(buffer)));
751 E : ASSERT_FALSE(error_occurred());
752 :
753 : // Dispatch a malformed record and make sure the parser errors.
754 : ASSERT_NO_FATAL_FAILURE(DispatchEventData(
755 E : TRACE_COMMENT, data, sizeof(buffer) - 1));
756 E : ASSERT_TRUE(error_occurred());
757 E : }
758 :
759 : } // namespace
|