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