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