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 :
200 : static const DWORD kProcessId;
201 : static const DWORD kThreadId;
202 : static const ModuleInformation kExeInfo;
203 : static const ModuleInformation kDllInfo;
204 : static const TraceModuleData kModuleData;
205 : static const TraceIndexedFrequencyData kIndexedFrequencyData;
206 : static const TraceIndexedFrequencyData kShortIndexedFrequencyData;
207 :
208 : EVENT_TRACE event_record_;
209 :
210 : FunctionSet function_entries;
211 : FunctionSet function_exits;
212 : ModuleSet process_attaches;
213 : ModuleSet process_detaches;
214 : ModuleSet thread_attaches;
215 : ModuleSet thread_detaches;
216 : size_t basic_block_frequencies;
217 :
218 : const void* expected_data;
219 : };
220 :
221 : const DWORD ParseEngineUnitTest::kProcessId = 0xAAAAAAAA;
222 :
223 : const DWORD ParseEngineUnitTest::kThreadId = 0xBBBBBBBB;
224 :
225 E : const ModuleInformation ParseEngineUnitTest::kExeInfo = {
226 E : 0x11111111, 0x22222222, 0x33333333, 0x44444444, L"file_name.exe" };
227 :
228 E : const ModuleInformation ParseEngineUnitTest::kDllInfo = {
229 E : 0x55555555, 0x66666666, 0x77777777, 0x88888888, L"file_name.dll" };
230 :
231 : const TraceModuleData ParseEngineUnitTest::kModuleData = {
232 : reinterpret_cast<ModuleAddr>(0x99999999),
233 : 0x11111111,
234 : 0x22222222,
235 : 0x33333333,
236 : L"module",
237 : L"executable" };
238 :
239 : const TraceIndexedFrequencyData ParseEngineUnitTest::kIndexedFrequencyData = {
240 : reinterpret_cast<ModuleAddr>(0x11111111),
241 : 0x22222222,
242 : 0x33333333,
243 : 0x44444444,
244 : 1,
245 : 1,
246 : common::IndexedFrequencyData::BASIC_BLOCK_ENTRY,
247 : 1,
248 : 0 };
249 :
250 : // This indexed frequency struct does not contain enough data for its implicitly
251 : // encoded length.
252 : const TraceIndexedFrequencyData
253 : ParseEngineUnitTest::kShortIndexedFrequencyData = {
254 : reinterpret_cast<ModuleAddr>(0x11111111),
255 : 0x22222222,
256 : 0x33333333,
257 : 0x44444444,
258 : 10,
259 : 1,
260 : common::IndexedFrequencyData::BASIC_BLOCK_ENTRY,
261 : 4,
262 : 0 };
263 :
264 : // A test function to show up in the trace events.
265 i : void TestFunc1() {
266 i : ::Sleep(100);
267 i : }
268 :
269 : // Another test function to show up in the trace events.
270 i : void TestFunc2() {
271 i : ::time(NULL);
272 i : }
273 :
274 E : TEST_F(ParseEngineUnitTest, ModuleInfo) {
275 E : const ModuleInformation* module_info = NULL;
276 :
277 : // Insert the module information.
278 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kExeInfo));
279 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kDllInfo));
280 E : ASSERT_EQ(1, processes_.size());
281 E : ASSERT_EQ(2, processes_[kProcessId].size());
282 :
283 : // Multiple identical insertions should be ok.
284 E : ASSERT_TRUE(AddModuleInformation(kProcessId, kDllInfo));
285 E : ASSERT_EQ(2, processes_[kProcessId].size());
286 :
287 : // Intersecting but not identical insertions should fail if disallowed.
288 E : ModuleInformation bad_dll_info(kDllInfo);
289 E : bad_dll_info.base_address += 100;
290 E : ASSERT_TRUE(fail_on_module_conflict_);
291 E : ASSERT_FALSE(AddModuleInformation(kProcessId, bad_dll_info));
292 E : ASSERT_EQ(2, processes_[kProcessId].size());
293 :
294 : // If conflicting module info is non-fatal, insertions should appear to
295 : // succeed but not actually happen.
296 E : fail_on_module_conflict_ = false;
297 E : ASSERT_TRUE(AddModuleInformation(kProcessId, bad_dll_info));
298 E : ASSERT_EQ(2, processes_[kProcessId].size());
299 E : fail_on_module_conflict_ = true;
300 :
301 : // Search for unknown process.
302 E : module_info = GetModuleInformation(kProcessId + 1, kExeInfo.base_address);
303 E : ASSERT_TRUE(module_info == NULL);
304 :
305 : // Search before exe start address
306 E : const int kBeforeOffset = -1;
307 : module_info = GetModuleInformation(kProcessId,
308 E : kExeInfo.base_address + kBeforeOffset);
309 E : ASSERT_TRUE(module_info == NULL);
310 :
311 : // Search after exe end address.
312 E : const size_t kAfterOffset = kExeInfo.module_size;
313 : module_info = GetModuleInformation(kProcessId,
314 E : kExeInfo.base_address + kAfterOffset);
315 E : ASSERT_TRUE(module_info == NULL);
316 :
317 : // Get exe module by start address.
318 E : const size_t kStartOffset = 0;
319 : module_info = GetModuleInformation(kProcessId,
320 E : kExeInfo.base_address + kStartOffset);
321 E : ASSERT_TRUE(module_info != NULL);
322 E : ASSERT_TRUE(*module_info == kExeInfo);
323 :
324 : // Get exe module by address somewhere in the middle.
325 E : const size_t kMiddleOffset = kExeInfo.module_size / 2;
326 : module_info = GetModuleInformation(kProcessId,
327 E : kExeInfo.base_address + kMiddleOffset);
328 E : ASSERT_TRUE(module_info != NULL);
329 E : ASSERT_TRUE(*module_info == kExeInfo);
330 :
331 : // Get exe module by address at the end.
332 E : const size_t kEndOffset = kExeInfo.module_size - 1;
333 : module_info = GetModuleInformation(kProcessId,
334 E : kExeInfo.base_address + kEndOffset);
335 E : ASSERT_TRUE(module_info != NULL);
336 E : ASSERT_TRUE(*module_info == kExeInfo);
337 :
338 : // We only remove modules from a given process if a conflicting module is
339 : // loaded after the module has been marked as dirty. This is because (1) we
340 : // don't guarantee temporal order of all events in a process, so you
341 : // might parse a function event after seeing the module get unloaded
342 : // if the buffers are flushed in that order; and (2) because process ids may
343 : // be reused (but not concurrently) so we do want to drop stale module info
344 : // when the process has been replaced.
345 :
346 : // Get dll module by address somewhere in the middle, then remove it and
347 : // see that it's STILL found by that address.
348 E : const size_t kDllOffset = kDllInfo.module_size / 2;
349 : module_info = GetModuleInformation(kProcessId,
350 E : kDllInfo.base_address + kDllOffset);
351 E : ASSERT_TRUE(module_info != NULL);
352 E : ASSERT_TRUE(*module_info == kDllInfo);
353 E : ASSERT_TRUE(RemoveModuleInformation(kProcessId, kDllInfo));
354 E : ASSERT_EQ(2, processes_[kProcessId].size());
355 : module_info = GetModuleInformation(kProcessId,
356 E : kDllInfo.base_address + kDllOffset);
357 E : ASSERT_TRUE(module_info != NULL);
358 E : ASSERT_TRUE(*module_info == kDllInfo);
359 :
360 : // Add conflicting module information and see that the old module is gone.
361 E : ModuleInformation new_dll_info = kDllInfo;
362 E : new_dll_info.base_address += 4;
363 E : ASSERT_TRUE(AddModuleInformation(kProcessId, new_dll_info));
364 E : ASSERT_EQ(2, processes_[kProcessId].size());
365 E : module_info = GetModuleInformation(kProcessId, kDllInfo.base_address);
366 E : ASSERT_TRUE(module_info == NULL);
367 E : module_info = GetModuleInformation(kProcessId, new_dll_info.base_address);
368 E : ASSERT_TRUE(module_info != NULL);
369 E : ASSERT_TRUE(*module_info == new_dll_info);
370 E : }
371 :
372 E : TEST_F(ParseEngineUnitTest, UnhandledEvent) {
373 E : EVENT_TRACE local_record = {};
374 E : ASSERT_FALSE(DispatchEvent(&local_record));
375 :
376 E : local_record.Header.ProcessId = kProcessId;
377 E : local_record.Header.ThreadId = kThreadId;
378 E : local_record.Header.Guid = kCallTraceEventClass;
379 E : local_record.Header.Class.Type = 0xFF; // Invalid value.
380 E : ASSERT_TRUE(DispatchEvent(&local_record));
381 E : ASSERT_TRUE(error_occurred());
382 E : }
383 :
384 E : TEST_F(ParseEngineUnitTest, FunctionEntryEvents) {
385 E : TraceEnterEventData event_data = {};
386 E : event_data.function = &TestFunc1;
387 E : expected_data = &event_data;
388 :
389 : ASSERT_NO_FATAL_FAILURE(
390 E : DispatchEventData(TRACE_ENTER_EVENT, &event_data, sizeof(event_data)));
391 E : ASSERT_FALSE(error_occurred());
392 : ASSERT_NO_FATAL_FAILURE(
393 E : DispatchEventData(TRACE_ENTER_EVENT, &event_data, sizeof(event_data)));
394 E : ASSERT_FALSE(error_occurred());
395 E : ASSERT_EQ(function_entries.size(), 2);
396 E : ASSERT_EQ(function_entries.count(&TestFunc1), 2);
397 :
398 : // Check for short event data.
399 : ASSERT_NO_FATAL_FAILURE(
400 : DispatchEventData(TRACE_ENTER_EVENT,
401 : &event_data,
402 E : sizeof(TraceEnterEventData) - 1));
403 E : ASSERT_TRUE(error_occurred());
404 E : }
405 :
406 E : TEST_F(ParseEngineUnitTest, FunctionExitEvents) {
407 E : TraceExitEventData event_data = {};
408 E : event_data.function = &TestFunc2;
409 E : expected_data = &event_data;
410 :
411 : ASSERT_NO_FATAL_FAILURE(
412 E : DispatchEventData(TRACE_EXIT_EVENT, &event_data, sizeof(event_data)));
413 E : ASSERT_FALSE(error_occurred());
414 : ASSERT_NO_FATAL_FAILURE(
415 E : DispatchEventData(TRACE_EXIT_EVENT, &event_data, sizeof(event_data)));
416 E : ASSERT_FALSE(error_occurred());
417 E : ASSERT_EQ(function_exits.size(), 2);
418 E : ASSERT_EQ(function_exits.count(&TestFunc2), 2);
419 :
420 : // Check for short event data.
421 : ASSERT_NO_FATAL_FAILURE(
422 : DispatchEventData(TRACE_EXIT_EVENT,
423 : &event_data,
424 E : sizeof(TraceEnterEventData) - 1));
425 E : ASSERT_TRUE(error_occurred());
426 E : }
427 :
428 E : TEST_F(ParseEngineUnitTest, BatchFunctionEntry) {
429 : uint8 raw_data[sizeof(TraceBatchEnterData) +
430 E : 4 * sizeof(TraceEnterEventData)] = {};
431 : TraceBatchEnterData& event_data =
432 E : *reinterpret_cast<TraceBatchEnterData*>(&raw_data);
433 E : event_data.thread_id = kThreadId;
434 E : event_data.num_calls = 5;
435 E : event_data.calls[0].function = &TestFunc1;
436 E : event_data.calls[1].function = &TestFunc2;
437 E : event_data.calls[2].function = &TestFunc1;
438 E : event_data.calls[3].function = &TestFunc2;
439 E : event_data.calls[4].function = NULL;
440 E : expected_data = &raw_data;
441 :
442 : ASSERT_NO_FATAL_FAILURE(
443 E : DispatchEventData(TRACE_BATCH_ENTER, &raw_data, sizeof(raw_data)));
444 E : ASSERT_FALSE(error_occurred());
445 : ASSERT_NO_FATAL_FAILURE(
446 E : DispatchEventData(TRACE_BATCH_ENTER, &raw_data, sizeof(raw_data)));
447 E : ASSERT_FALSE(error_occurred());
448 E : ASSERT_EQ(function_entries.size(), 8);
449 E : ASSERT_EQ(function_entries.count(&TestFunc1), 4);
450 E : ASSERT_EQ(function_entries.count(&TestFunc2), 4);
451 :
452 : // Check for short event header.
453 : ASSERT_NO_FATAL_FAILURE(
454 : DispatchEventData(TRACE_BATCH_ENTER,
455 : &raw_data,
456 E : FIELD_OFFSET(TraceBatchEnterData, num_calls)));
457 E : ASSERT_TRUE(error_occurred());
458 :
459 : // Check for short event tail (remove the empty record + one byte).
460 E : set_error_occurred(false);
461 : ASSERT_NO_FATAL_FAILURE(
462 : DispatchEventData(TRACE_BATCH_ENTER,
463 : &raw_data,
464 E : sizeof(raw_data) - sizeof(TraceEnterEventData) - 1));
465 E : ASSERT_TRUE(error_occurred());
466 E : }
467 :
468 E : TEST_F(ParseEngineUnitTest, ProcessAttachIncomplete) {
469 E : TraceModuleData incomplete(kModuleData);
470 E : incomplete.module_base_addr = NULL;
471 :
472 : // No error should be reported for NULL module addr, instead the record
473 : // should be ignored.
474 E : expected_data = &kModuleData;
475 : ASSERT_NO_FATAL_FAILURE(
476 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
477 : &incomplete,
478 E : sizeof(incomplete)));
479 :
480 E : ASSERT_FALSE(error_occurred());
481 E : ASSERT_EQ(process_attaches.size(), 0);
482 E : }
483 :
484 E : TEST_F(ParseEngineUnitTest, ProcessAttach) {
485 E : expected_data = &kModuleData;
486 :
487 : ASSERT_NO_FATAL_FAILURE(
488 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
489 : &kModuleData,
490 E : sizeof(kModuleData)));
491 E : ASSERT_FALSE(error_occurred());
492 E : ASSERT_EQ(process_attaches.size(), 1);
493 :
494 : // Check for short module event.
495 : ASSERT_NO_FATAL_FAILURE(
496 : DispatchEventData(TRACE_PROCESS_ATTACH_EVENT,
497 : &kModuleData,
498 E : sizeof(kModuleData) - 1));
499 E : ASSERT_TRUE(error_occurred());
500 E : }
501 :
502 E : TEST_F(ParseEngineUnitTest, ProcessDetach) {
503 E : expected_data = &kModuleData;
504 :
505 : ASSERT_NO_FATAL_FAILURE(
506 : DispatchEventData(TRACE_PROCESS_DETACH_EVENT,
507 : &kModuleData,
508 E : sizeof(kModuleData)));
509 E : ASSERT_FALSE(error_occurred());
510 E : ASSERT_EQ(process_detaches.size(), 1);
511 :
512 : // Check for short module event.
513 : ASSERT_NO_FATAL_FAILURE(
514 : DispatchEventData(TRACE_PROCESS_DETACH_EVENT,
515 : &kModuleData,
516 E : sizeof(kModuleData) - 1));
517 E : ASSERT_TRUE(error_occurred());
518 E : }
519 :
520 E : TEST_F(ParseEngineUnitTest, ThreadAttach) {
521 E : expected_data = &kModuleData;
522 :
523 : ASSERT_NO_FATAL_FAILURE(
524 : DispatchEventData(TRACE_THREAD_ATTACH_EVENT,
525 : &kModuleData,
526 E : sizeof(kModuleData)));
527 E : ASSERT_FALSE(error_occurred());
528 E : ASSERT_EQ(thread_attaches.size(), 1);
529 :
530 : // Check for short module event.
531 : ASSERT_NO_FATAL_FAILURE(
532 : DispatchEventData(TRACE_THREAD_ATTACH_EVENT,
533 : &kModuleData,
534 E : sizeof(kModuleData) - 1));
535 E : ASSERT_TRUE(error_occurred());
536 E : }
537 :
538 E : TEST_F(ParseEngineUnitTest, ThreadDetach) {
539 E : expected_data = &kModuleData;
540 :
541 : ASSERT_NO_FATAL_FAILURE(
542 : DispatchEventData(TRACE_THREAD_DETACH_EVENT,
543 : &kModuleData,
544 E : sizeof(kModuleData)));
545 E : ASSERT_FALSE(error_occurred());
546 E : ASSERT_EQ(thread_detaches.size(), 1);
547 :
548 : // Check for short module event.
549 : ASSERT_NO_FATAL_FAILURE(
550 : DispatchEventData(TRACE_THREAD_DETACH_EVENT,
551 : &kModuleData,
552 E : sizeof(kModuleData) - 1));
553 E : ASSERT_TRUE(error_occurred());
554 E : }
555 :
556 E : TEST_F(ParseEngineUnitTest, IndexedFrequencyTooSmallForHeader) {
557 : ASSERT_NO_FATAL_FAILURE(
558 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
559 : &kIndexedFrequencyData,
560 E : sizeof(kIndexedFrequencyData) - 1));
561 :
562 E : ASSERT_TRUE(error_occurred());
563 E : ASSERT_EQ(basic_block_frequencies, 0);
564 E : }
565 :
566 E : TEST_F(ParseEngineUnitTest, IndexedFrequencyTooSmallForContents) {
567 : ASSERT_NO_FATAL_FAILURE(
568 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
569 : &kShortIndexedFrequencyData,
570 E : sizeof(kShortIndexedFrequencyData)));
571 :
572 E : ASSERT_TRUE(error_occurred());
573 E : ASSERT_EQ(basic_block_frequencies, 0);
574 E : }
575 :
576 E : TEST_F(ParseEngineUnitTest, IndexedFrequency) {
577 E : expected_data = &kIndexedFrequencyData;
578 : ASSERT_NO_FATAL_FAILURE(
579 : DispatchEventData(TRACE_INDEXED_FREQUENCY,
580 : &kIndexedFrequencyData,
581 E : sizeof(kIndexedFrequencyData)));
582 E : ASSERT_FALSE(error_occurred());
583 E : ASSERT_EQ(basic_block_frequencies, 1);
584 E : }
585 :
586 E : TEST_F(ParseEngineUnitTest, DynamicSymbol) {
587 : static const char kSymbolName[] = "aDynamicSymbol";
588 E : const uint32 kSymbolId = 0x17459A;
589 : char data[FIELD_OFFSET(TraceDynamicSymbol, symbol_name) +
590 : sizeof(kSymbolName)];
591 E : TraceDynamicSymbol* symbol = reinterpret_cast<TraceDynamicSymbol*>(data);
592 E : symbol->symbol_id = kSymbolId;
593 E : ::memcpy(symbol->symbol_name, kSymbolName, sizeof(kSymbolName));
594 :
595 : // Dispatch a valid dynamic symbol record.
596 : EXPECT_CALL(*this,
597 E : OnDynamicSymbol(kProcessId, kSymbolId, base::StringPiece(kSymbolName)));
598 : ASSERT_NO_FATAL_FAILURE(
599 E : DispatchEventData(TRACE_DYNAMIC_SYMBOL, data, sizeof(data)));
600 E : ASSERT_FALSE(error_occurred());
601 :
602 : // Dispatch a short symbol record, make sure we err out.
603 : ASSERT_NO_FATAL_FAILURE(
604 : DispatchEventData(TRACE_DYNAMIC_SYMBOL,
605 : data,
606 E : FIELD_OFFSET(TraceDynamicSymbol, symbol_name) - 1));
607 E : ASSERT_TRUE(error_occurred());
608 E : }
609 :
610 E : TEST_F(ParseEngineUnitTest, SampleData) {
611 E : const uint32 kBucketCount = 42;
612 : char buffer[FIELD_OFFSET(TraceSampleData, buckets) +
613 E : kBucketCount * sizeof(uint32)] = {};
614 E : TraceSampleData* data = reinterpret_cast<TraceSampleData*>(buffer);
615 :
616 E : data->module_base_addr = reinterpret_cast<ModuleAddr>(0x01000000);
617 E : data->module_size = 32 * 1024 * 1024;
618 E : data->module_checksum = 0xDEADF00D;
619 E : data->module_time_date_stamp = 0x12345678;
620 E : data->bucket_size = 4;
621 E : data->bucket_start = reinterpret_cast<ModuleAddr>(0x01001000);
622 E : data->bucket_count = kBucketCount;
623 E : data->sampling_start_time = 0x0102030405060708;
624 E : data->sampling_end_time = 0x0203040506070809;
625 E : data->sampling_interval = 0x10000;
626 :
627 E : for (size_t i = 0; i < kBucketCount; ++i)
628 E : data->buckets[i] = i;
629 :
630 E : EXPECT_CALL(*this, OnSampleData(_, kProcessId, data));
631 : ASSERT_NO_FATAL_FAILURE(
632 E : DispatchEventData(TRACE_SAMPLE_DATA, data, sizeof(buffer)));
633 E : ASSERT_FALSE(error_occurred());
634 :
635 : // Dispatch a malformed record and make sure the parser errors.
636 : ASSERT_NO_FATAL_FAILURE(
637 E : DispatchEventData(TRACE_SAMPLE_DATA, data, sizeof(buffer) - 1));
638 E : ASSERT_TRUE(error_occurred());
639 E : }
640 :
641 : } // namespace
|