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