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