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/grinder/basic_block_util.h"
16 :
17 : #include "base/files/scoped_temp_dir.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/common/indexed_frequency_data.h"
21 : #include "syzygy/core/unittest_util.h"
22 : #include "syzygy/grinder/grinder.h"
23 : #include "syzygy/grinder/indexed_frequency_data_serializer.h"
24 : #include "syzygy/pe/pe_file.h"
25 : #include "syzygy/pe/unittest_util.h"
26 :
27 : namespace grinder {
28 : namespace basic_block_util {
29 :
30 : namespace {
31 :
32 : using testing::GetExeTestDataRelativePath;
33 : using trace::parser::AbsoluteAddress64;
34 : using trace::parser::Parser;
35 :
36 : class TestGrinder : public GrinderInterface {
37 : public:
38 E : TestGrinder() : parser_(NULL), on_bb_freq_was_called_(false) {
39 : // Nothing else to initialize.
40 E : }
41 :
42 : // @name GrinderInterface implementation.
43 : // @{
44 E : virtual bool ParseCommandLine(const CommandLine*) OVERRIDE { return true; }
45 E : virtual void SetParser(Parser* parser) OVERRIDE {
46 E : ASSERT_TRUE(parser != NULL);
47 E : parser_ = parser;
48 E : }
49 E : virtual bool Grind() OVERRIDE { return true; }
50 E : virtual bool OutputData(FILE*) OVERRIDE { return true; }
51 : // @}
52 :
53 : // @name ParseEventHandler overrides.
54 : // @{
55 : virtual void OnIndexedFrequency(
56 : base::Time time,
57 : DWORD process_id,
58 : DWORD thread_id,
59 E : const TraceIndexedFrequencyData* data) OVERRIDE {
60 E : on_bb_freq_was_called_ = true;
61 E : ASSERT_TRUE(data != NULL);
62 :
63 E : ASSERT_TRUE(
64 : data->data_type == common::IndexedFrequencyData::BASIC_BLOCK_ENTRY ||
65 : data->data_type == common::IndexedFrequencyData::COVERAGE);
66 :
67 : // Lookup the module information.
68 : const ModuleInformation* module_info = parser_->GetModuleInformation(
69 E : process_id, AbsoluteAddress64(data->module_base_addr));
70 E : ASSERT_TRUE(module_info != NULL);
71 :
72 : // Load the PDB information.
73 E : PdbInfo* pdb_info = NULL;
74 E : ASSERT_TRUE(LoadPdbInfo(&pdb_info_cache_, *module_info, &pdb_info));
75 E : ASSERT_TRUE(pdb_info != NULL);
76 :
77 : // Validate that the cache works.
78 E : PdbInfo* dup_pdb_info = NULL;
79 E : ASSERT_TRUE(LoadPdbInfo(&pdb_info_cache_, *module_info, &dup_pdb_info));
80 E : ASSERT_EQ(pdb_info, dup_pdb_info);
81 E : }
82 :
83 : Parser* parser_;
84 : PdbInfoMap pdb_info_cache_;
85 : bool on_bb_freq_was_called_;
86 : };
87 :
88 E : void PopulateModuleInformation(ModuleInformation* module_info) {
89 E : ASSERT_TRUE(module_info != NULL);
90 E : module_info->base_address = 0xDEADBEEF;
91 E : module_info->image_checksum = 0xCAFEBABE;
92 E : module_info->image_file_name = L"image_file_name";
93 E : module_info->module_size = 0x12345678;
94 E : module_info->time_date_stamp = 0x87654321;
95 E : }
96 :
97 : } // namespace
98 :
99 E : TEST(GrinderBasicBlockUtilTest, ModuleIdentityComparator) {
100 E : ModuleInformation a;
101 E : PopulateModuleInformation(&a);
102 :
103 E : ModuleInformation b = a;
104 : ModuleIdentityComparator comp;
105 : // The two should compare equal.
106 E : EXPECT_FALSE(comp(a, b));
107 E : EXPECT_FALSE(comp(b, a));
108 :
109 : // Jiggle b's base address and checksum.
110 E : b.base_address -= 10;
111 E : b.image_checksum += 100;
112 : // The two should still compare equal.
113 E : EXPECT_FALSE(comp(a, b));
114 E : EXPECT_FALSE(comp(b, a));
115 :
116 E : b = a;
117 E : b.module_size -= 1;
118 E : EXPECT_FALSE(comp(a, b));
119 E : EXPECT_TRUE(comp(b, a));
120 :
121 E : b = a;
122 E : b.time_date_stamp += 1;
123 E : EXPECT_TRUE(comp(a, b));
124 E : EXPECT_FALSE(comp(b, a));
125 :
126 E : b = a;
127 E : b.image_file_name = L"foo";
128 E : EXPECT_FALSE(comp(a, b));
129 E : EXPECT_TRUE(comp(b, a));
130 E : }
131 :
132 E : TEST(GrinderBasicBlockUtilTest, InitModuleInfo) {
133 : // Create a prototype module info structure.
134 E : ModuleInformation orig_module_info;
135 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&orig_module_info));
136 :
137 : // Initialize a signature matching the prototype.
138 E : pe::PEFile::Signature signature(orig_module_info);
139 :
140 : // Extract the module information from the signature. It should match the
141 : // prototype.
142 E : ModuleInformation new_module_info;
143 E : InitModuleInfo(signature, &new_module_info);
144 E : EXPECT_EQ(orig_module_info, new_module_info);
145 E : }
146 :
147 E : TEST(GrinderBasicBlockUtilTest, FindEntryCountVector) {
148 : // Create a prototype module info structure.
149 E : ModuleInformation module_info;
150 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&module_info));
151 :
152 : // Initialize a signature matching the module_info.
153 E : pe::PEFile::Signature signature(module_info);
154 :
155 : // Create an empty count map.
156 E : ModuleIndexedFrequencyMap module_count_map;
157 E : EXPECT_TRUE(module_count_map.empty());
158 :
159 : // Search the empty map for the module..
160 E : const IndexedFrequencyInformation* count_map = NULL;
161 : EXPECT_FALSE(
162 E : FindIndexedFrequencyInfo(signature, module_count_map, &count_map));
163 E : EXPECT_EQ(NULL, count_map);
164 :
165 : // Insert a matching module and search again.
166 : const IndexedFrequencyInformation* count_map_1 =
167 E : &module_count_map[module_info];
168 : EXPECT_TRUE(
169 E : FindIndexedFrequencyInfo(signature, module_count_map, &count_map));
170 E : EXPECT_EQ(count_map_1, count_map);
171 :
172 : // Insert a second matching module and search again. This should fail.
173 E : module_info.image_file_name = L"Some other file name";
174 : const IndexedFrequencyInformation* count_map_2 =
175 E : &module_count_map[module_info];
176 E : ASSERT_NE(count_map_1, count_map_2);
177 : EXPECT_FALSE(
178 E : FindIndexedFrequencyInfo(signature, module_count_map, &count_map));
179 E : EXPECT_EQ(NULL, count_map);
180 E : }
181 :
182 E : TEST(GrinderBasicBlockUtilTest, LoadBranchStatisticsFromFileFailed) {
183 : // A temporary directory into which temp files will be written.
184 E : base::ScopedTempDir temp_dir;
185 E : ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
186 :
187 : // Create a prototype module info structure.
188 E : ModuleInformation module_info;
189 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&module_info));
190 E : pe::PEFile::Signature signature(module_info);
191 :
192 : // Validate non existing file is reported.
193 E : IndexedFrequencyMap frequencies;
194 E : base::FilePath invalid_path(L"this_file_doesnt_exists");
195 : EXPECT_FALSE(
196 E : LoadBranchStatisticsFromFile(invalid_path, signature, &frequencies));
197 :
198 : // Validate invalid file format is reported.
199 E : base::FilePath empty_file;
200 : ASSERT_TRUE(
201 E : file_util::CreateTemporaryFileInDir(temp_dir.path(), &empty_file));
202 : EXPECT_FALSE(
203 E : LoadBranchStatisticsFromFile(empty_file, signature, &frequencies));
204 :
205 : // Serialize to a file without any module.
206 E : base::FilePath temp_file;
207 E : ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &temp_file));
208 E : ModuleIndexedFrequencyMap modules;
209 E : IndexedFrequencyDataSerializer serializer;
210 E : ASSERT_TRUE(serializer.SaveAsJson(modules, temp_file));
211 :
212 : // Expect to not find the module with the current signature.
213 : EXPECT_FALSE(
214 E : LoadBranchStatisticsFromFile(temp_file, signature, &frequencies));
215 E : }
216 :
217 E : TEST(GrinderBasicBlockUtilTest, LoadBranchStatisticsFromFile) {
218 : // A temporary directory into which temp files will be written.
219 E : base::ScopedTempDir temp_dir;
220 E : ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
221 :
222 : // Create a prototype module info structure.
223 E : ModuleInformation module_info;
224 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&module_info));
225 E : pe::PEFile::Signature signature(module_info);
226 :
227 : // Populate module information.
228 E : ModuleIndexedFrequencyMap modules;
229 E : IndexedFrequencyInformation information;
230 E : information.data_type = common::IndexedFrequencyData::BRANCH;
231 E : information.frequency_size = 4;
232 E : information.num_columns = 3;
233 E : information.num_entries = 0;
234 E : modules[module_info] = information;
235 :
236 : // Serialize to a file.
237 E : base::FilePath temp_file;
238 E : ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &temp_file));
239 E : IndexedFrequencyDataSerializer serializer;
240 E : ASSERT_TRUE(serializer.SaveAsJson(modules, temp_file));
241 :
242 : // Expect to find the module with the current signature.
243 E : IndexedFrequencyMap frequencies;
244 : EXPECT_TRUE(
245 E : LoadBranchStatisticsFromFile(temp_file, signature, &frequencies));
246 E : }
247 :
248 E : TEST(GrinderBasicBlockUtilTest, LoadBasicBlockRanges) {
249 E : RelativeAddressRangeVector bb_ranges;
250 :
251 : base::FilePath wrong_file_type(GetExeTestDataRelativePath(
252 E : testing::kCoverageTraceFiles[0]));
253 E : EXPECT_FALSE(LoadBasicBlockRanges(wrong_file_type, &bb_ranges));
254 :
255 : base::FilePath wrong_pdb(
256 E : GetExeTestDataRelativePath(testing::kTestDllPdbName));
257 E : EXPECT_FALSE(LoadBasicBlockRanges(wrong_pdb, &bb_ranges));
258 :
259 : base::FilePath right_pdb(GetExeTestDataRelativePath(
260 E : testing::kBBEntryInstrumentedTestDllPdbName));
261 E : EXPECT_TRUE(LoadBasicBlockRanges(right_pdb, &bb_ranges));
262 E : }
263 :
264 E : TEST(GrinderBasicBlockUtilTest, LoadPdbInfo) {
265 : // TODO(rogerm): Rewrite me! This test doesn't directly test LoadPdbInfo.
266 E : Parser parser;
267 E : TestGrinder grinder;
268 E : ASSERT_TRUE(parser.Init(&grinder));
269 E : ASSERT_NO_FATAL_FAILURE(grinder.SetParser(&parser));
270 E : ASSERT_TRUE(grinder.ParseCommandLine(NULL));
271 : ASSERT_TRUE(parser.OpenTraceFile(GetExeTestDataRelativePath(
272 E : testing::kCoverageTraceFiles[0])));
273 E : ASSERT_TRUE(parser.Consume());
274 E : ASSERT_TRUE(grinder.on_bb_freq_was_called_);
275 E : ASSERT_TRUE(grinder.Grind());
276 E : ASSERT_TRUE(grinder.OutputData(NULL));
277 E : }
278 :
279 E : TEST(GrinderBasicBlockUtilTest, IsValidFrequencySize) {
280 E : EXPECT_TRUE(IsValidFrequencySize(1));
281 E : EXPECT_TRUE(IsValidFrequencySize(2));
282 E : EXPECT_TRUE(IsValidFrequencySize(4));
283 :
284 E : EXPECT_FALSE(IsValidFrequencySize(0));
285 E : EXPECT_FALSE(IsValidFrequencySize(3));
286 E : EXPECT_FALSE(IsValidFrequencySize(8));
287 E : EXPECT_FALSE(IsValidFrequencySize(65536));
288 E : }
289 :
290 E : TEST(GrinderBasicBlockUtilTest, GetFrequency) {
291 : // Counter data we'll test against.
292 : static const uint8 kData[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
293 : 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB };
294 :
295 : // A buffer over which we'll overlay a TraceIndexedFrequencyData struct.
296 E : uint8 buffer[sizeof(TraceIndexedFrequencyData) + sizeof(kData) - 1] = {};
297 E : ::memset(buffer, 0, sizeof(buffer));
298 :
299 : // A TraceDataBlockFrequencyData structure with the frequency_data populated
300 : // with a copy of kData.
301 : TraceIndexedFrequencyData* data =
302 E : reinterpret_cast<TraceIndexedFrequencyData*>(buffer);
303 E : ::memcpy(data->frequency_data, kData, sizeof(kData));
304 :
305 : // Set 1 column of basic block entry count.
306 E : data->num_columns = 1;
307 E : data->data_type = common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
308 :
309 : // Validate 1-byte frequency data.
310 E : data->frequency_size = 1;
311 E : data->num_entries = sizeof(kData) / data->frequency_size;
312 E : EXPECT_EQ(0x44, GetFrequency(data, 0x4, 0));
313 E : EXPECT_EQ(0xAA, GetFrequency(data, 0xA, 0));
314 :
315 : // Validate 2-byte frequency data.
316 E : data->frequency_size = 2;
317 E : data->num_entries = sizeof(kData) / data->frequency_size;
318 E : EXPECT_EQ(0x5544, GetFrequency(data, 0x2, 0));
319 E : EXPECT_EQ(0x9988, GetFrequency(data, 0x4, 0));
320 :
321 : // Validate 4-byte frequency data.
322 E : data->frequency_size = 4;
323 E : data->num_entries = sizeof(kData) / data->frequency_size;
324 E : EXPECT_EQ(0x33221100, GetFrequency(data, 0x0, 0));
325 E : EXPECT_EQ(0xBBAA9988, GetFrequency(data, 0x2, 0));
326 E : }
327 :
328 E : TEST(GrinderBasicBlockUtilTest, GetFrequencyWithColumns) {
329 : // Counter data we'll test against.
330 : static const uint8 kData[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
331 : 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB };
332 :
333 : // A buffer over which we'll overlay a TraceIndexedFrequencyData struct.
334 E : uint8 buffer[sizeof(TraceIndexedFrequencyData) + sizeof(kData) - 1] = {};
335 E : ::memset(buffer, 0, sizeof(buffer));
336 :
337 : // A TraceDataBlockFrequencyData structure with the frequency_data populated
338 : // with a copy of kData.
339 : TraceIndexedFrequencyData* data =
340 E : reinterpret_cast<TraceIndexedFrequencyData*>(buffer);
341 E : ::memcpy(data->frequency_data, kData, sizeof(kData));
342 :
343 : // Set 2 columns of basic block entry count.
344 E : data->num_columns = 2;
345 E : data->data_type = common::IndexedFrequencyData::BASIC_BLOCK_ENTRY;
346 :
347 : // Validate 1-byte frequency data.
348 E : data->frequency_size = 1;
349 E : data->num_entries = sizeof(kData) / data->frequency_size;
350 E : EXPECT_EQ(0x88, GetFrequency(data, 0x4, 0));
351 E : EXPECT_EQ(0x99, GetFrequency(data, 0x4, 1));
352 :
353 : // Validate 2-byte frequency data.
354 E : data->frequency_size = 2;
355 E : data->num_entries = sizeof(kData) / data->frequency_size;
356 E : EXPECT_EQ(0x9988, GetFrequency(data, 0x2, 0));
357 E : EXPECT_EQ(0xBBAA, GetFrequency(data, 0x2, 1));
358 :
359 : // Validate 4-byte frequency data.
360 E : data->frequency_size = 4;
361 E : data->num_entries = sizeof(kData) / data->frequency_size;
362 E : EXPECT_EQ(0x33221100, GetFrequency(data, 0x0, 0));
363 E : EXPECT_EQ(0x77665544, GetFrequency(data, 0x0, 1));
364 E : }
365 :
366 : } // namespace basic_block_util
367 : } // namespace grinder
|