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