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/block_graph/basic_block_assembler.h"
16 :
17 : #include "gtest/gtest.h"
18 :
19 : namespace block_graph {
20 :
21 : namespace {
22 :
23 : class BasicBlockAssemblerTest : public testing::Test {
24 : public:
25 : typedef BlockGraph::RelativeAddress RelativeAddress;
26 : typedef BlockGraph::Block::SourceRange SourceRange;
27 :
28 : BasicBlockAssemblerTest();
29 :
30 E : void SetUp() OVERRIDE {
31 E : }
32 :
33 E : void TearDown() OVERRIDE {
34 E : }
35 :
36 : protected:
37 : struct Ref {
38 : size_t offset;
39 : BasicBlockReference::ReferredType type;
40 : const void* reference;
41 : };
42 :
43 : template <size_t N>
44 E : void AssertRefs(const Ref(& refs)[N]) {
45 E : ASSERT_EQ(1, instructions_.size());
46 E : const Instruction& instr = instructions_.front();
47 :
48 E : for (size_t i = 0; i < N; ++i) {
49 : BasicBlock::BasicBlockReferenceMap::const_iterator it =
50 E : instr.references().find(refs[i].offset);
51 E : ASSERT_NE(instr.references().end(), it);
52 E : ASSERT_EQ(refs[i].type, it->second.referred_type());
53 E : switch (refs[i].type) {
54 : case BasicBlockReference::REFERRED_TYPE_BLOCK:
55 E : ASSERT_EQ(refs[i].reference, it->second.block());
56 E : break;
57 : case BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK:
58 E : ASSERT_EQ(refs[i].reference, it->second.basic_block());
59 E : break;
60 : default:
61 i : ASSERT_TRUE(false);
62 : }
63 :
64 E : ASSERT_EQ(refs[i].type, it->second.referred_type());
65 E : }
66 :
67 E : instructions_.clear();
68 E : }
69 :
70 E : void AssertNoRefs() {
71 E : ASSERT_EQ(1, instructions_.size());
72 E : ASSERT_EQ(0, instructions_.front().references().size());
73 E : instructions_.clear();
74 E : }
75 :
76 : BlockGraph::Block test_block_;
77 : BasicCodeBlock test_bb_;
78 : BasicBlock::Instructions instructions_;
79 : BasicBlockAssembler asm_;
80 : };
81 :
82 : #define ASSERT_REFS(...) \
83 : do { \
84 : const Ref refs[] = { __VA_ARGS__ }; \
85 : ASSERT_NO_FATAL_FAILURE(AssertRefs(refs)); \
86 : } while (0)
87 :
88 : #define ASSERT_NO_REFS() ASSERT_NO_FATAL_FAILURE(AssertNoRefs())
89 :
90 : BasicBlockAssemblerTest::BasicBlockAssemblerTest()
91 : : test_block_(99, BlockGraph::CODE_BLOCK, 10, "test block"),
92 : test_bb_("foo"),
93 E : asm_(instructions_.end(), &instructions_) {
94 E : }
95 :
96 : void TestValue(const Value& value,
97 : uint32 expected_value,
98 E : core::ValueSize expected_size) {
99 E : EXPECT_EQ(expected_size, value.size());
100 E : EXPECT_EQ(expected_value, value.value());
101 : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
102 E : value.reference().referred_type());
103 :
104 E : Value value_copy(value);
105 E : EXPECT_EQ(expected_size, value_copy.size());
106 E : EXPECT_EQ(expected_value, value_copy.value());
107 : EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
108 E : value_copy.reference().referred_type());
109 :
110 E : EXPECT_TRUE(value == value_copy);
111 :
112 E : Value value_diff(expected_value - 1);
113 E : EXPECT_FALSE(value == value_diff);
114 E : }
115 :
116 E : void Test8BitValue(uint32 input_value, uint32 expected_value) {
117 E : TestValue(Value(input_value), expected_value, core::kSize8Bit);
118 : TestValue(
119 E : Value(input_value, core::kSize8Bit), expected_value, core::kSize8Bit);
120 E : }
121 :
122 E : void Test32BitValue(uint32 input_value, uint32 expected_value) {
123 E : TestValue(Value(input_value), expected_value, core::kSize32Bit);
124 : TestValue(
125 E : Value(input_value, core::kSize32Bit), expected_value, core::kSize32Bit);
126 E : }
127 :
128 : } // namespace
129 :
130 : typedef BasicBlockAssemblerTest ValueTest;
131 :
132 E : void TestValueCopy(const Value& input) {
133 : // Make sure copy-constructing the value works.
134 E : Value copy(input);
135 :
136 E : ASSERT_EQ(input.value(), copy.value());
137 E : ASSERT_EQ(input.size(), copy.size());
138 : ASSERT_EQ(input.reference().referred_type(),
139 E : copy.reference().referred_type());
140 E : ASSERT_EQ(input.reference().block(), copy.reference().block());
141 E : ASSERT_EQ(input.reference().basic_block(), copy.reference().basic_block());
142 E : ASSERT_EQ(input.reference().offset(), copy.reference().offset());
143 E : ASSERT_EQ(input.reference().base(), copy.reference().base());
144 :
145 : // Make sure assignment operator works.
146 E : Value copy2;
147 E : copy2 = input;
148 E : ASSERT_EQ(input.value(), copy2.value());
149 E : ASSERT_EQ(input.size(), copy2.size());
150 : ASSERT_EQ(input.reference().referred_type(),
151 E : copy2.reference().referred_type());
152 E : ASSERT_EQ(input.reference().block(), copy2.reference().block());
153 E : ASSERT_EQ(input.reference().basic_block(), copy2.reference().basic_block());
154 E : ASSERT_EQ(input.reference().offset(), copy2.reference().offset());
155 E : ASSERT_EQ(input.reference().base(), copy2.reference().base());
156 E : }
157 :
158 E : TEST_F(ValueTest, Construction) {
159 : {
160 E : Value value_empty;
161 E : ASSERT_EQ(0, value_empty.value());
162 E : ASSERT_EQ(core::kSizeNone, value_empty.size());
163 : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
164 E : value_empty.reference().referred_type());
165 :
166 E : TestValueCopy(value_empty);
167 E : }
168 :
169 E : Test8BitValue(0, 0);
170 E : Test8BitValue(127, 127);
171 :
172 E : Test8BitValue(-128, 0xFFFFFF80);
173 E : Test8BitValue(0, 0);
174 E : Test8BitValue(127, 0x0000007F);
175 :
176 E : Test32BitValue(128, 0x00000080);
177 E : Test32BitValue(0xCAFEBABE, 0xCAFEBABE);
178 :
179 E : Test32BitValue(-129, 0xFFFFFF7F);
180 E : Test32BitValue(128, 0x000000080);
181 E : Test32BitValue(0xBABE, 0xBABE);
182 :
183 : {
184 E : const BlockGraph::Offset kOffs = 10;
185 E : Value value_block_ref(&test_block_, kOffs);
186 :
187 E : ASSERT_EQ(0, value_block_ref.value());
188 E : ASSERT_EQ(core::kSize32Bit, value_block_ref.size());
189 : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
190 E : value_block_ref.reference().referred_type());
191 E : ASSERT_EQ(&test_block_, value_block_ref.reference().block());
192 E : ASSERT_EQ(kOffs, value_block_ref.reference().offset());
193 E : ASSERT_EQ(0, value_block_ref.reference().base());
194 :
195 E : TestValueCopy(value_block_ref);
196 E : }
197 :
198 : {
199 E : Value value_bb_ref(&test_bb_);
200 :
201 E : ASSERT_EQ(0, value_bb_ref.value());
202 E : ASSERT_EQ(core::kSize32Bit, value_bb_ref.size());
203 : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK,
204 E : value_bb_ref.reference().referred_type());
205 E : ASSERT_EQ(&test_bb_, value_bb_ref.reference().basic_block());
206 E : ASSERT_EQ(0, value_bb_ref.reference().offset());
207 E : ASSERT_EQ(0, value_bb_ref.reference().base());
208 :
209 E : TestValueCopy(value_bb_ref);
210 E : }
211 :
212 : {
213 : // Explicitly specified size and reference info.
214 E : BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 1, &test_block_, 1, 2);
215 E : Value value_expl_ref(0xBE, core::kSize8Bit, ref);
216 :
217 E : ASSERT_EQ(0xBE, value_expl_ref.value());
218 E : ASSERT_EQ(core::kSize8Bit, value_expl_ref.size());
219 : ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
220 E : value_expl_ref.reference().referred_type());
221 E : ASSERT_EQ(&test_block_, value_expl_ref.reference().block());
222 E : ASSERT_EQ(1, value_expl_ref.reference().offset());
223 E : ASSERT_EQ(2, value_expl_ref.reference().base());
224 :
225 E : TestValueCopy(value_expl_ref);
226 E : }
227 E : }
228 :
229 : typedef BasicBlockAssemblerTest OperandTest;
230 :
231 E : void TestOperandCopy(const Operand& input) {
232 E : Operand copy(input);
233 :
234 E : ASSERT_EQ(input.base(), copy.base());
235 E : ASSERT_EQ(input.index(), copy.index());
236 E : ASSERT_EQ(input.scale(), copy.scale());
237 E : ASSERT_EQ(input.displacement().value(), copy.displacement().value());
238 E : ASSERT_EQ(input.displacement().size(), copy.displacement().size());
239 E : ASSERT_EQ(input.displacement().reference(), copy.displacement().reference());
240 :
241 E : Operand copy2(core::eax);
242 :
243 E : copy2 = input;
244 E : ASSERT_EQ(input.base(), copy2.base());
245 E : ASSERT_EQ(input.index(), copy2.index());
246 E : ASSERT_EQ(input.scale(), copy2.scale());
247 E : ASSERT_EQ(input.displacement().value(), copy2.displacement().value());
248 E : ASSERT_EQ(input.displacement().size(), copy2.displacement().size());
249 E : ASSERT_EQ(input.displacement().reference(), copy2.displacement().reference());
250 E : }
251 :
252 E : TEST_F(OperandTest, Construction) {
253 : // A register-indirect.
254 E : TestOperandCopy(Operand(core::eax));
255 :
256 : // Register-indirect with displacement.
257 E : TestOperandCopy(Operand(core::eax, Displacement(100)));
258 E : TestOperandCopy(Operand(core::eax, Displacement(&test_block_, 2)));
259 E : TestOperandCopy(Operand(core::eax, Displacement(&test_bb_)));
260 :
261 : // Displacement-only mode.
262 E : TestOperandCopy(Operand(Displacement(100)));
263 E : TestOperandCopy(Operand(Displacement(&test_block_, 2)));
264 E : TestOperandCopy(Operand(Displacement(&test_bb_)));
265 :
266 : TestOperandCopy(Operand(core::eax,
267 : core::ebp,
268 : core::kTimes2,
269 E : Displacement(100)));
270 : TestOperandCopy(Operand(core::eax,
271 : core::ebp,
272 : core::kTimes2,
273 E : Displacement(&test_block_, 2)));
274 : TestOperandCopy(Operand(core::eax,
275 : core::ebp,
276 : core::kTimes2,
277 E : Displacement(&test_bb_)));
278 :
279 : // The [base + index * scale] mode - no displ.
280 E : TestOperandCopy(Operand(core::eax, core::ebp, core::kTimes2));
281 :
282 : // The [index * scale + displ32] mode - no base.
283 : TestOperandCopy(Operand(core::ebp,
284 : core::kTimes2,
285 E : Displacement(100)));
286 : TestOperandCopy(Operand(core::ebp,
287 : core::kTimes2,
288 E : Displacement(&test_block_, 2)));
289 : TestOperandCopy(Operand(core::ebp,
290 : core::kTimes2,
291 E : Displacement(&test_bb_)));
292 E : }
293 :
294 E : TEST_F(BasicBlockAssemblerTest, call) {
295 E : asm_.call(Immediate(0xCAFEBABE));
296 E : ASSERT_NO_REFS();
297 :
298 E : asm_.call(Immediate(&test_block_, 0));
299 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
300 :
301 E : asm_.call(Operand(Displacement(&test_bb_)));
302 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
303 E : }
304 :
305 E : TEST_F(BasicBlockAssemblerTest, jmp) {
306 E : asm_.jmp(Immediate(0xCAFEBABE));
307 E : ASSERT_NO_REFS();
308 :
309 E : asm_.jmp(Immediate(&test_block_, 0));
310 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
311 :
312 E : asm_.jmp(Operand(Displacement(&test_bb_)));
313 E : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
314 E : }
315 :
316 E : TEST_F(BasicBlockAssemblerTest, mov_b) {
317 : // mov [base + index * scale + displ], immediate
318 : asm_.mov(Operand(core::eax, core::ebx, core::kTimes4,
319 : Displacement(&test_block_, 0)),
320 E : Immediate(10));
321 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
322 E : }
323 :
324 E : TEST_F(BasicBlockAssemblerTest, mov) {
325 : // Simple register-register move.
326 E : asm_.mov(core::eax, core::ebx);
327 E : ASSERT_NO_REFS();
328 :
329 : // Simple immediate-register move.
330 E : asm_.mov(core::eax, Immediate(10));
331 E : ASSERT_NO_REFS();
332 :
333 : // Immediate-with reference to register.
334 E : asm_.mov(core::eax, Immediate(&test_block_, 0));
335 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
336 :
337 : // Torture test; mov [displ], immediate,
338 : // both src and dst contain references.
339 E : asm_.mov(Operand(Displacement(&test_block_, 0)), Immediate(&test_bb_));
340 : ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_,
341 E : 6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
342 :
343 : // Torture test; mov [base + index * scale + displ], immediate,
344 : // both src and dst contain references.
345 : asm_.mov(Operand(core::eax, core::ebx, core::kTimes4,
346 : Displacement(&test_block_, 0)),
347 E : Immediate(&test_bb_));
348 : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_,
349 E : 7, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
350 E : }
351 :
352 E : TEST_F(BasicBlockAssemblerTest, lea) {
353 E : asm_.lea(core::eax, Operand(core::eax));
354 E : ASSERT_NO_REFS();
355 :
356 : asm_.lea(core::eax,
357 : Operand(core::eax, core::ebx, core::kTimes4,
358 E : Displacement(&test_bb_)));
359 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
360 E : }
361 :
362 E : TEST_F(BasicBlockAssemblerTest, push) {
363 E : asm_.push(core::esp);
364 E : ASSERT_NO_REFS();
365 :
366 E : asm_.push(Immediate(&test_block_, 0));
367 E : ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
368 :
369 : asm_.push(Operand(core::eax, core::ebx, core::kTimes4,
370 E : Displacement(&test_bb_)));
371 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
372 E : }
373 :
374 E : TEST_F(BasicBlockAssemblerTest, pop) {
375 E : asm_.pop(core::ebp);
376 E : ASSERT_NO_REFS();
377 :
378 : asm_.pop(Operand(core::eax, core::ebx, core::kTimes4,
379 E : Displacement(&test_bb_)));
380 E : ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
381 E : }
382 :
383 E : TEST_F(BasicBlockAssemblerTest, ret) {
384 E : asm_.ret();
385 E : ASSERT_NO_REFS();
386 :
387 E : asm_.ret(4);
388 E : ASSERT_NO_REFS();
389 E : }
390 :
391 E : TEST_F(BasicBlockAssemblerTest, UndefinedSourceRange) {
392 E : ASSERT_EQ(asm_.source_range(), SourceRange());
393 E : asm_.call(Immediate(0xCAFEBABE));
394 E : ASSERT_EQ(instructions_.back().source_range(), SourceRange());
395 E : }
396 :
397 E : TEST_F(BasicBlockAssemblerTest, SetSourceRange) {
398 E : SourceRange range(RelativeAddress(10), 10);
399 E : asm_.set_source_range(range);
400 E : asm_.call(Immediate(0xCAFEBABE));
401 E : ASSERT_EQ(instructions_.back().source_range(), range);
402 E : }
403 :
404 E : TEST_F(BasicBlockAssemblerTest, SetMultipleSourceRange) {
405 E : SourceRange range1(RelativeAddress(10), 10);
406 E : SourceRange range2(RelativeAddress(20), 20);
407 :
408 E : asm_.set_source_range(range1);
409 E : asm_.call(Immediate(0xCAFEBABE));
410 E : ASSERT_EQ(instructions_.back().source_range(), range1);
411 :
412 E : asm_.set_source_range(range2);
413 E : asm_.pop(core::ebp);
414 E : ASSERT_EQ(instructions_.back().source_range(), range2);
415 :
416 E : asm_.ret(4);
417 E : ASSERT_EQ(instructions_.back().source_range(), range2);
418 E : }
419 :
420 : } // namespace basic_block
|