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 "gmock/gmock.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/core/unittest_util.h"
20 : #include "syzygy/grinder/grinder.h"
21 : #include "syzygy/pe/pe_file.h"
22 : #include "syzygy/pe/unittest_util.h"
23 :
24 : namespace grinder {
25 : namespace basic_block_util {
26 :
27 : namespace {
28 :
29 : using testing::GetExeTestDataRelativePath;
30 : using trace::parser::AbsoluteAddress64;
31 : using trace::parser::Parser;
32 :
33 : class TestGrinder : public GrinderInterface {
34 : public:
35 E : TestGrinder() : parser_(NULL), on_bb_freq_was_called_(false) {
36 : // Nothing else to initialize.
37 E : }
38 :
39 : // @name GrinderInterface implementation.
40 : // @{
41 E : virtual bool ParseCommandLine(const CommandLine*) OVERRIDE { return true; }
42 E : virtual void SetParser(Parser* parser) OVERRIDE {
43 E : ASSERT_TRUE(parser != NULL);
44 E : parser_ = parser;
45 E : }
46 E : virtual bool Grind() OVERRIDE { return true; };
47 E : virtual bool OutputData(FILE*) OVERRIDE { return true; }
48 : // @}
49 :
50 : // @name ParseEventHandler overrides.
51 : // @{
52 : virtual void OnIndexedFrequency(
53 : base::Time time,
54 : DWORD process_id,
55 : DWORD thread_id,
56 E : const TraceIndexedFrequencyData* data) OVERRIDE {
57 E : on_bb_freq_was_called_ = true;
58 E : ASSERT_TRUE(data != NULL);
59 :
60 E : ASSERT_EQ(TraceIndexedFrequencyData::BASIC_BLOCK, data->data_type);
61 :
62 : // Lookup the module information.
63 : const ModuleInformation* module_info = parser_->GetModuleInformation(
64 E : process_id, AbsoluteAddress64(data->module_base_addr));
65 E : ASSERT_TRUE(module_info != NULL);
66 :
67 : // Load the PDB information.
68 E : PdbInfo* pdb_info = NULL;
69 E : ASSERT_TRUE(LoadPdbInfo(&pdb_info_cache_, *module_info, &pdb_info));
70 E : ASSERT_TRUE(pdb_info != NULL);
71 :
72 : // Validate that the cache works.
73 E : PdbInfo* dup_pdb_info = NULL;
74 E : ASSERT_TRUE(LoadPdbInfo(&pdb_info_cache_, *module_info, &dup_pdb_info));
75 E : ASSERT_EQ(pdb_info, dup_pdb_info);
76 E : }
77 :
78 : Parser* parser_;
79 : PdbInfoMap pdb_info_cache_;
80 : bool on_bb_freq_was_called_;
81 : };
82 :
83 E : void PopulateModuleInformation(ModuleInformation* module_info) {
84 E : ASSERT_TRUE(module_info != NULL);
85 E : module_info->base_address = 0xDEADBEEF;
86 E : module_info->image_checksum = 0xCAFEBABE;
87 E : module_info->image_file_name = L"image_file_name";
88 E : module_info->module_size = 0x12345678;
89 E : module_info->time_date_stamp = 0x87654321;
90 E : }
91 :
92 : } // namespace
93 :
94 E : TEST(GrinderBasicBlockUtilTest, ModuleIdentityComparator) {
95 E : ModuleInformation a;
96 E : PopulateModuleInformation(&a);
97 :
98 E : ModuleInformation b = a;
99 : ModuleIdentityComparator comp;
100 : // The two should compare equal.
101 E : EXPECT_FALSE(comp(a, b));
102 E : EXPECT_FALSE(comp(b, a));
103 :
104 : // Jiggle b's base address and checksum.
105 E : b.base_address -= 10;
106 E : b.image_checksum += 100;
107 : // The two should still compare equal.
108 E : EXPECT_FALSE(comp(a, b));
109 E : EXPECT_FALSE(comp(b, a));
110 :
111 E : b = a;
112 E : b.module_size -= 1;
113 E : EXPECT_FALSE(comp(a, b));
114 E : EXPECT_TRUE(comp(b, a));
115 :
116 E : b = a;
117 E : b.time_date_stamp += 1;
118 E : EXPECT_TRUE(comp(a, b));
119 E : EXPECT_FALSE(comp(b, a));
120 :
121 E : b = a;
122 E : b.image_file_name = L"foo";
123 E : EXPECT_FALSE(comp(a, b));
124 E : EXPECT_TRUE(comp(b, a));
125 E : }
126 :
127 E : TEST(GrinderBasicBlockUtilTest, InitModuleInfo) {
128 : // Create a prototype module info structure.
129 E : ModuleInformation orig_module_info;
130 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&orig_module_info));
131 :
132 : // Initialize a signature matching the prototype.
133 E : pe::PEFile::Signature signature(orig_module_info);
134 :
135 : // Extract the module information from the signature. It should match the
136 : // prototype.
137 E : ModuleInformation new_module_info;
138 E : InitModuleInfo(signature, &new_module_info);
139 E : EXPECT_EQ(orig_module_info, new_module_info);
140 E : }
141 :
142 E : TEST(GrinderBasicBlockUtilTest, FindEntryCountVector) {
143 : // Create a prototype module info structure.
144 E : ModuleInformation module_info;
145 E : EXPECT_NO_FATAL_FAILURE(PopulateModuleInformation(&module_info));
146 :
147 : // Initialize a signature matching the module_info.
148 E : pe::PEFile::Signature signature(module_info);
149 :
150 : // Create an empty entry count map.
151 E : ModuleEntryCountMap module_entry_count_map;
152 E : EXPECT_TRUE(module_entry_count_map.empty());
153 :
154 : // Search the empty map for the module..
155 E : const EntryCountMap* entry_count_map = NULL;
156 : EXPECT_FALSE(
157 E : FindEntryCountMap(signature, module_entry_count_map, &entry_count_map));
158 E : EXPECT_EQ(NULL, entry_count_map);
159 :
160 : // Insert a matching module and search again.
161 E : const EntryCountMap* entry_count_map_1 = &module_entry_count_map[module_info];
162 : EXPECT_TRUE(
163 E : FindEntryCountMap(signature, module_entry_count_map, &entry_count_map));
164 E : EXPECT_EQ(entry_count_map_1, entry_count_map);
165 :
166 : // Insert a second matching module and search again. This should fail.
167 E : module_info.image_file_name = L"Some other file name";
168 E : const EntryCountMap* entry_count_map_2 = &module_entry_count_map[module_info];
169 E : ASSERT_NE(entry_count_map_1, entry_count_map_2);
170 : EXPECT_FALSE(
171 E : FindEntryCountMap(signature, module_entry_count_map, &entry_count_map));
172 E : EXPECT_EQ(NULL, entry_count_map);
173 E : }
174 :
175 E : TEST(GrinderBasicBlockUtilTest, LoadBasicBlockRanges) {
176 E : RelativeAddressRangeVector bb_ranges;
177 :
178 : base::FilePath wrong_file_type(GetExeTestDataRelativePath(
179 E : testing::kCoverageTraceFiles[0]));
180 E : EXPECT_FALSE(LoadBasicBlockRanges(wrong_file_type, &bb_ranges));
181 :
182 : base::FilePath wrong_pdb(
183 E : GetExeTestDataRelativePath(testing::kTestDllPdbName));
184 E : EXPECT_FALSE(LoadBasicBlockRanges(wrong_pdb, &bb_ranges));
185 :
186 : base::FilePath right_pdb(GetExeTestDataRelativePath(
187 E : testing::kBBEntryInstrumentedTestDllPdbName));
188 E : EXPECT_TRUE(LoadBasicBlockRanges(right_pdb, &bb_ranges));
189 E : }
190 :
191 E : TEST(GrinderBasicBlockUtilTest, LoadPdbInfo) {
192 : // TODO(rogerm): Rewrite me! This test doesn't directly test LoadPdbInfo.
193 E : Parser parser;
194 E : TestGrinder grinder;
195 E : ASSERT_TRUE(parser.Init(&grinder));
196 E : ASSERT_NO_FATAL_FAILURE(grinder.SetParser(&parser));
197 E : ASSERT_TRUE(grinder.ParseCommandLine(NULL));
198 : ASSERT_TRUE(parser.OpenTraceFile(GetExeTestDataRelativePath(
199 E : testing::kCoverageTraceFiles[0])));
200 E : ASSERT_TRUE(parser.Consume());
201 E : ASSERT_TRUE(grinder.on_bb_freq_was_called_);
202 E : ASSERT_TRUE(grinder.Grind());
203 E : ASSERT_TRUE(grinder.OutputData(NULL));
204 E : }
205 :
206 E : TEST(GrinderBasicBlockUtilTest, IsValidFrequencySize) {
207 E : EXPECT_TRUE(IsValidFrequencySize(1));
208 E : EXPECT_TRUE(IsValidFrequencySize(2));
209 E : EXPECT_TRUE(IsValidFrequencySize(4));
210 :
211 E : EXPECT_FALSE(IsValidFrequencySize(0));
212 E : EXPECT_FALSE(IsValidFrequencySize(3));
213 E : EXPECT_FALSE(IsValidFrequencySize(8));
214 E : EXPECT_FALSE(IsValidFrequencySize(65536));
215 E : }
216 :
217 E : TEST(GrinderBasicBlockUtilTest, GetFrequency) {
218 : // Counter data we'll test against.
219 : static const uint8 kData[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
220 : 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB };
221 :
222 : // A buffer over which we'll overlay a TraceIndexedFrequencyData struct.
223 E : uint8 buffer[sizeof(TraceIndexedFrequencyData) + sizeof(kData) - 1] = {};
224 E : ::memset(buffer, 0, sizeof(buffer));
225 :
226 : // A TraceDataBlockFrequencyData structure with the frequency_data populated
227 : // with a copy of kData.
228 : TraceIndexedFrequencyData* data =
229 E : reinterpret_cast<TraceIndexedFrequencyData*>(buffer);
230 E : ::memcpy(data->frequency_data, kData, sizeof(kData));
231 :
232 : // Validate 1-byte frequency data.
233 E : data->frequency_size = 1;
234 E : data->num_entries = sizeof(kData) / data->frequency_size;
235 E : EXPECT_EQ(0x44, GetFrequency(data, 0x4));
236 E : EXPECT_EQ(0xAA, GetFrequency(data, 0xA));
237 :
238 : // Validate 2-byte frequency data.
239 E : data->frequency_size = 2;
240 E : data->num_entries = sizeof(kData) / data->frequency_size;
241 E : EXPECT_EQ(0x5544, GetFrequency(data, 0x2));
242 E : EXPECT_EQ(0x9988, GetFrequency(data, 0x4));
243 :
244 : // Validate 4-byte frequency data.
245 E : data->frequency_size = 4;
246 E : data->num_entries = sizeof(kData) / data->frequency_size;
247 E : EXPECT_EQ(0x33221100, GetFrequency(data, 0x0));
248 E : EXPECT_EQ(0xBBAA9988, GetFrequency(data, 0x2));
249 E : }
250 :
251 : } // namespace basic_block_util
252 : } // namespace grinder
|