1 : // Copyright 2013 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/sampler/unittest_util.h"
16 :
17 : #include "gtest/gtest.h"
18 : #include "syzygy/core/unittest_util.h"
19 : #include "syzygy/pe/pe_file.h"
20 : #include "syzygy/pe/unittest_util.h"
21 : #include "syzygy/trace/common/unittest_util.h"
22 : #include "syzygy/trace/protocol/call_trace_defs.h"
23 :
24 : namespace testing {
25 :
26 : namespace {
27 :
28 : static uint32 kDummyModuleAddress = 0x07000000;
29 : static uint32 kDummyBucketSize = 4;
30 :
31 : // Returns the address of 'LabelTestFunc'.
32 : void GetLabelTestFuncAdddress(const pe::PEFile& test_dll_pe_file,
33 E : pe::PEFile::RelativeAddress* function_rva) {
34 E : DCHECK(function_rva != NULL);
35 :
36 : // Get the address of the exported function.
37 E : pe::PEFile::ExportInfoVector exports;
38 E : ASSERT_TRUE(test_dll_pe_file.DecodeExports(&exports));
39 E : for (size_t i = 0; i < exports.size(); ++i) {
40 E : if (exports[i].name == "LabelTestFunc") {
41 E : *function_rva = exports[i].function;
42 E : break;
43 : }
44 E : };
45 E : ASSERT_NE(0u, function_rva->value());
46 E : }
47 :
48 : void InitializeDummyTraceSampleData(
49 : const trace::common::ClockInfo& clock_info,
50 : const pe::PEFile& test_dll_pe_file,
51 : const pe::PEFile::Signature& test_dll_pe_sig,
52 E : std::vector<uint8>* buffer) {
53 : const IMAGE_SECTION_HEADER* text_header =
54 E : test_dll_pe_file.GetSectionHeader(".text");
55 E : ASSERT_TRUE(text_header != NULL);
56 :
57 : // Get the index of the first bucket mapping to LabelTestFunc.
58 E : pe::PEFile::RelativeAddress text_rva(text_header->VirtualAddress);
59 E : pe::PEFile::RelativeAddress function_rva;
60 : ASSERT_NO_FATAL_FAILURE(GetLabelTestFuncAdddress(test_dll_pe_file,
61 E : &function_rva));
62 E : ASSERT_LE(text_rva, function_rva);
63 E : size_t offset = function_rva.value() - text_rva.value();
64 E : ASSERT_EQ(0u, offset % 4);
65 E : size_t index = offset / 4;
66 :
67 : // Initialize a TraceSampleData record. We make it look like we sampled
68 : // for 10 seconds at 100 Hz.
69 : size_t bucket_count =
70 : (text_header->Misc.VirtualSize + kDummyBucketSize - 1) /
71 E : kDummyBucketSize;
72 :
73 : buffer->resize(offsetof(TraceSampleData, buckets) +
74 E : sizeof(uint32) * bucket_count);
75 : TraceSampleData* sample_data = reinterpret_cast<TraceSampleData*>(
76 E : buffer->data());
77 :
78 : sample_data->module_base_addr =
79 E : reinterpret_cast<ModuleAddr>(kDummyModuleAddress);
80 E : sample_data->module_size = test_dll_pe_sig.module_size;
81 E : sample_data->module_checksum = test_dll_pe_sig.module_checksum;
82 : sample_data->module_time_date_stamp =
83 E : test_dll_pe_sig.module_time_date_stamp;
84 E : sample_data->bucket_size = kDummyBucketSize;
85 : sample_data->bucket_start = reinterpret_cast<ModuleAddr>(
86 E : kDummyModuleAddress + text_header->VirtualAddress);
87 E : sample_data->bucket_count = bucket_count;
88 : sample_data->sampling_start_time =
89 E : clock_info.tsc_reference - 10 * clock_info.tsc_info.frequency;
90 E : sample_data->sampling_end_time = clock_info.tsc_reference;
91 E : sample_data->sampling_interval = clock_info.tsc_info.frequency / 100;
92 :
93 : // We put 1000 samples (10s of heat) into the first bucket associated with
94 : // 'LabelTestFunc'.
95 E : sample_data->buckets[index] = 1000;
96 E : }
97 :
98 : } // namespace
99 :
100 E : void WriteDummySamplerTraceFile(const base::FilePath& path) {
101 E : trace::common::ClockInfo clock_info = {};
102 E : trace::common::GetClockInfo(&clock_info);
103 :
104 E : base::FilePath test_dll_path = GetOutputRelativePath(kTestDllName);
105 E : pe::PEFile test_dll_pe_file;
106 E : ASSERT_TRUE(test_dll_pe_file.Init(test_dll_path));
107 :
108 E : pe::PEFile::Signature test_dll_pe_sig;
109 E : test_dll_pe_file.GetSignature(&test_dll_pe_sig);
110 :
111 E : trace::service::TraceFileWriter writer;
112 E : ASSERT_TRUE(writer.Open(path));
113 :
114 : // Write a dummy header.
115 E : trace::service::ProcessInfo process_info;
116 E : ASSERT_TRUE(process_info.Initialize(::GetCurrentProcessId()));
117 E : ASSERT_TRUE(writer.WriteHeader(process_info));
118 :
119 : // Write a dummy module loaded event.
120 E : TraceModuleData module_data = {};
121 : module_data.module_base_addr =
122 E : reinterpret_cast<ModuleAddr>(kDummyModuleAddress);
123 E : module_data.module_base_size = test_dll_pe_sig.module_size;
124 E : module_data.module_checksum = test_dll_pe_sig.module_checksum;
125 : module_data.module_time_date_stamp =
126 E : test_dll_pe_sig.module_time_date_stamp;
127 : wcsncpy(module_data.module_name,
128 : test_dll_path.value().c_str(),
129 E : arraysize(module_data.module_name));
130 :
131 : ASSERT_NO_FATAL_FAILURE(testing::WriteRecord(
132 : clock_info.tsc_reference,
133 : TRACE_PROCESS_ATTACH_EVENT,
134 : &module_data,
135 : sizeof(module_data),
136 E : &writer));
137 :
138 : // The TraceSampleData should already be initialized
139 E : std::vector<uint8> buffer;
140 : InitializeDummyTraceSampleData(
141 E : clock_info, test_dll_pe_file, test_dll_pe_sig, &buffer);
142 E : ASSERT_FALSE(buffer.empty());
143 :
144 : // Write the sample data and close the file.
145 : ASSERT_NO_FATAL_FAILURE(testing::WriteRecord(
146 : clock_info.tsc_reference,
147 : TraceSampleData::kTypeId,
148 : buffer.data(),
149 : buffer.size(),
150 E : &writer));
151 :
152 E : ASSERT_TRUE(writer.Close());
153 E : }
154 :
155 : } // namespace testing
|