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