1 : // Copyright 2013 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/pe/pe_transform_policy.h"
16 :
17 : #include "gtest/gtest.h"
18 : #include "syzygy/block_graph/basic_block_decomposer.h"
19 : #include "syzygy/block_graph/block_graph.h"
20 : #include "syzygy/pe/unittest_util.h"
21 :
22 : namespace pe {
23 :
24 : namespace {
25 :
26 : using block_graph::BlockGraph;
27 :
28 : class TestPETransformPolicy : public PETransformPolicy {
29 : public:
30 : typedef PETransformPolicy::BlockResultCache BlockResultCache;
31 :
32 : using PETransformPolicy::block_result_cache_;
33 : using PETransformPolicy::allow_inline_assembly_;
34 : };
35 :
36 : class PETransformPolicyTest : public testing::PELibUnitTest {
37 : public:
38 : enum ReferenceSource {
39 : kSelfCode,
40 : kSelfData,
41 : kCodeBlock,
42 : kDataBlock,
43 : };
44 :
45 : enum ReferenceTarget {
46 : kTopOfBlock,
47 : kInCode,
48 : kDataLabel,
49 : kInData
50 : };
51 :
52 : struct ReferrerConfiguration {
53 E : bool operator<(const ReferrerConfiguration& rhs) const {
54 E : if (ref_source < rhs.ref_source)
55 E : return true;
56 E : if (ref_source > rhs.ref_source)
57 E : return false;
58 E : if (ref_target < rhs.ref_target)
59 E : return true;
60 E : if (ref_target > rhs.ref_target)
61 E : return false;
62 E : if (ref_type < rhs.ref_type)
63 E : return true;
64 E : if (ref_type > rhs.ref_type)
65 E : return false;
66 E : if (ref_size < rhs.ref_size)
67 E : return true;
68 E : if (ref_size > rhs.ref_size)
69 E : return false;
70 E : if (ref_is_direct < rhs.ref_is_direct)
71 E : return true;
72 E : return false;
73 E : }
74 :
75 : ReferenceSource ref_source;
76 : ReferenceTarget ref_target;
77 : BlockGraph::ReferenceType ref_type;
78 : size_t ref_size;
79 : bool ref_is_direct;
80 : };
81 :
82 : void TestCodeBlockReferrersAreClConsistent(
83 : const ReferrerConfiguration& config,
84 E : bool expect_valid) {
85 E : BlockGraph bg;
86 E : BlockGraph::Block* dst = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s");
87 :
88 E : BlockGraph::Offset src_offset = 0;
89 :
90 : // Get the source block and source offset.
91 E : BlockGraph::Block* src = NULL;
92 E : switch (config.ref_source) {
93 : case kSelfCode:
94 E : src = dst;
95 E : src_offset = 4;
96 E : break;
97 :
98 : case kSelfData:
99 E : src = dst;
100 E : src_offset = 24;
101 E : break;
102 :
103 : case kCodeBlock:
104 E : src = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
105 E : src_offset = 4;
106 E : break;
107 :
108 : case kDataBlock:
109 E : src = image_.AddBlock(BlockGraph::DATA_BLOCK, 40, "d");
110 E : src_offset = 4;
111 : break;
112 : }
113 :
114 : // Set up a data label in the destination block, which splits it in half.
115 E : ASSERT_TRUE(dst->SetLabel(20, BlockGraph::Label(
116 : "data", BlockGraph::DATA_LABEL)));
117 :
118 : // We need the data label to be self-referenced otherwise the referrers test
119 : // will always fail. This is from a different offset than what we would
120 : // ever use for src_offset (4 or 24).
121 E : ASSERT_TRUE(dst->SetReference(16,
122 : BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4, dst, 20, 20)));
123 :
124 : // These are reference offsets in dst as a function of ref_target.
125 E : const BlockGraph::Offset kRefOffsets[] = { 0, 10, 20, 30 };
126 :
127 : // Create the offset and the reference.
128 E : BlockGraph::Offset ref_offset = kRefOffsets[config.ref_target];
129 E : BlockGraph::Offset ref_base = ref_offset;
130 E : if (!config.ref_is_direct)
131 E : ref_base += 4;
132 :
133 : // Create the reference.
134 : BlockGraph::Reference ref(config.ref_type, config.ref_size, dst, ref_offset,
135 E : ref_base);
136 E : ASSERT_TRUE(ref.IsValid());
137 E : ASSERT_EQ(config.ref_is_direct, ref.IsDirect());
138 :
139 : // Hook it up.
140 E : ASSERT_TRUE(src->SetReference(src_offset, ref));
141 :
142 : // Test the validity.
143 E : TestPETransformPolicy policy;
144 E : ASSERT_EQ(expect_valid, policy.CodeBlockReferrersAreClConsistent(dst));
145 E : }
146 :
147 : void TestAttributes(BlockGraph::BlockAttributes attributes,
148 : bool allow_inline_assembly,
149 E : bool result) {
150 E : PETransformPolicy policy;
151 E : BlockGraph bg;
152 E : BlockGraph::Block* b = bg.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
153 E : ASSERT_NE(reinterpret_cast<BlockGraph::Block*>(NULL), b);
154 E : b->set_attributes(attributes);
155 E : ASSERT_EQ(result, policy.CodeBlockAttributesAreBasicBlockSafe(
156 : b, allow_inline_assembly));
157 E : }
158 :
159 E : void TestCodeBlockHasPrivateSymbols(bool old_decomposer) {
160 E : TestPETransformPolicy policy;
161 :
162 E : pe::PEFile pe_file;
163 E : block_graph::BlockGraph block_graph;
164 E : pe::ImageLayout image_layout(&block_graph);
165 E : ASSERT_NO_FATAL_FAILURE(DecomposeTestDll(
166 : old_decomposer, &pe_file, &image_layout));
167 :
168 E : size_t count = 0;
169 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
170 E : for (; it != block_graph.blocks().end(); ++it) {
171 E : if (it->second.type() != BlockGraph::CODE_BLOCK)
172 E : continue;
173 E : if (it->second.attributes() & BlockGraph::PADDING_BLOCK)
174 E : continue;
175 :
176 E : if (!policy.CodeBlockHasPrivateSymbols(&it->second)) {
177 E : ++count;
178 E : EXPECT_EQ(it->second.name(), "TestFunctionWithNoPrivateSymbols");
179 : }
180 E : }
181 E : EXPECT_EQ(1u, count);
182 E : }
183 :
184 E : void TestBasicBlockDisassemblyFilter(bool old_decomposer) {
185 E : TestPETransformPolicy policy;
186 :
187 E : pe::PEFile pe_file;
188 E : block_graph::BlockGraph block_graph;
189 E : pe::ImageLayout image_layout(&block_graph);
190 E : ASSERT_NO_FATAL_FAILURE(DecomposeTestDll(
191 : old_decomposer, &pe_file, &image_layout));
192 :
193 E : size_t count = 0;
194 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
195 E : for (; it != block_graph.blocks().end(); ++it) {
196 E : if (!policy.BlockIsSafeToBasicBlockDecompose(&it->second))
197 E : continue;
198 :
199 : // Basic-block decomposition should not fail.
200 E : block_graph::BasicBlockSubGraph bbsg;
201 E : block_graph::BasicBlockDecomposer bbdecomp(&it->second, &bbsg);
202 E : EXPECT_TRUE(bbdecomp.Decompose());
203 E : }
204 E : }
205 :
206 : BlockGraph image_;
207 : };
208 :
209 : } // namespace
210 :
211 E : TEST_F(PETransformPolicyTest, AccessorsAndMutators) {
212 E : TestPETransformPolicy policy;
213 E : EXPECT_FALSE(policy.allow_inline_assembly());
214 E : policy.set_allow_inline_assembly(true);
215 E : EXPECT_TRUE(policy.allow_inline_assembly());
216 E : policy.set_allow_inline_assembly(false);
217 E : EXPECT_FALSE(policy.allow_inline_assembly());
218 E : }
219 :
220 : TEST_F(PETransformPolicyTest,
221 E : CodeBlockAttributesAreBasicBlockSafeGapBlock) {
222 E : ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::GAP_BLOCK, false, false));
223 E : ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::GAP_BLOCK, true, false));
224 E : }
225 :
226 : TEST_F(PETransformPolicyTest,
227 E : CodeBlockAttributesAreBasicBlockSafePaddingBlock) {
228 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
229 E : BlockGraph::PADDING_BLOCK, false, false));
230 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
231 E : BlockGraph::PADDING_BLOCK, true, false));
232 E : }
233 :
234 : TEST_F(PETransformPolicyTest,
235 E : CodeBlockAttributesAreBasicBlockSafeHasInlineAssembly) {
236 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
237 E : BlockGraph::HAS_INLINE_ASSEMBLY, false, false));
238 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
239 E : BlockGraph::HAS_INLINE_ASSEMBLY, true, true));
240 E : }
241 :
242 : TEST_F(PETransformPolicyTest,
243 E : CodeBlockAttributesAreBasicBlockSafeUnsupportedCompiler) {
244 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
245 E : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER, false, false));
246 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
247 E : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER, true, false));
248 E : }
249 :
250 : TEST_F(PETransformPolicyTest,
251 E : CodeBlockAttributesAreBasicBlockSafeErroredDisassembly) {
252 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
253 E : BlockGraph::ERRORED_DISASSEMBLY, false, false));
254 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
255 E : BlockGraph::ERRORED_DISASSEMBLY, true, false));
256 E : }
257 :
258 : TEST_F(PETransformPolicyTest,
259 E : CodeBlockAttributesAreBasicBlockSafeExceptionHandling) {
260 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
261 E : BlockGraph::HAS_EXCEPTION_HANDLING, false, false));
262 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
263 E : BlockGraph::HAS_EXCEPTION_HANDLING, true, false));
264 E : }
265 :
266 : TEST_F(PETransformPolicyTest,
267 E : CodeBlockAttributesAreBasicBlockSafeDisassembledPastEnd) {
268 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
269 E : BlockGraph::DISASSEMBLED_PAST_END, false, false));
270 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
271 E : BlockGraph::DISASSEMBLED_PAST_END, true, false));
272 E : }
273 :
274 : TEST_F(PETransformPolicyTest,
275 E : CodeBlockAttributesAreBasicBlockSafeBuiltBySyzygy) {
276 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
277 : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER | BlockGraph::BUILT_BY_SYZYGY,
278 : false,
279 E : true));
280 : ASSERT_NO_FATAL_FAILURE(TestAttributes(
281 : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER | BlockGraph::BUILT_BY_SYZYGY,
282 : true,
283 E : true));
284 E : }
285 :
286 E : TEST_F(PETransformPolicyTest, CodeBlockHasPrivateSymbolsNewDecomposer) {
287 E : EXPECT_NO_FATAL_FAILURE(TestCodeBlockHasPrivateSymbols(false));
288 E : }
289 :
290 E : TEST_F(PETransformPolicyTest, CodeBlockHasPrivateSymbolsOldDecomposer) {
291 E : EXPECT_NO_FATAL_FAILURE(TestCodeBlockHasPrivateSymbols(true));
292 E : }
293 :
294 E : TEST_F(PETransformPolicyTest, NoLabelsHasInvalidLayout) {
295 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
296 E : TestPETransformPolicy policy;
297 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
298 E : }
299 :
300 E : TEST_F(PETransformPolicyTest, CodeLabelPastEndHasInvalidLayout) {
301 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
302 E : b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
303 E : b->SetLabel(2, "code", BlockGraph::CODE_LABEL);
304 E : TestPETransformPolicy policy;
305 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
306 E : }
307 :
308 E : TEST_F(PETransformPolicyTest, DataLabelPastEndHasInvalidLayout) {
309 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
310 E : b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
311 E : b->SetLabel(2, "data", BlockGraph::DATA_LABEL);
312 E : TestPETransformPolicy policy;
313 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
314 E : }
315 :
316 E : TEST_F(PETransformPolicyTest, DebugEndInBlockAfterDataHasInvalidLayout) {
317 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 3, "code");
318 E : b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
319 E : b->SetLabel(1, "data", BlockGraph::DATA_LABEL);
320 E : b->SetLabel(2, "debug-end", BlockGraph::DEBUG_END_LABEL);
321 E : TestPETransformPolicy policy;
322 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
323 E : }
324 :
325 E : TEST_F(PETransformPolicyTest, CodeAfterDataHasInvalidLayout) {
326 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
327 E : b->SetLabel(0, "data", BlockGraph::DATA_LABEL);
328 E : b->SetLabel(1, "code", BlockGraph::CODE_LABEL);
329 E : TestPETransformPolicy policy;
330 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
331 E : }
332 :
333 E : TEST_F(PETransformPolicyTest, DataSurroundedByCodeHasInvalidLayout) {
334 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 3, "code");
335 E : b->SetLabel(0, "data", BlockGraph::DATA_LABEL);
336 E : b->SetLabel(1, "code", BlockGraph::CODE_LABEL);
337 E : b->SetLabel(2, "data", BlockGraph::DATA_LABEL);
338 E : TestPETransformPolicy policy;
339 E : EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
340 E : }
341 :
342 E : TEST_F(PETransformPolicyTest, CodeOnlyHasValidLayout) {
343 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
344 E : b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
345 E : TestPETransformPolicy policy;
346 E : EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
347 :
348 : // This should still be true even with a debug-end label beyond the end.
349 E : b->SetLabel(1, "debug-end", BlockGraph::DEBUG_END_LABEL);
350 E : EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
351 E : }
352 :
353 E : TEST_F(PETransformPolicyTest, CodeFollowedByDataHasValidLayout) {
354 E : BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
355 E : b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
356 E : b->SetLabel(1, "data", BlockGraph::DATA_LABEL);
357 :
358 E : TestPETransformPolicy policy;
359 E : EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
360 :
361 : // This should still be true even with a debug-end label beyond the end.
362 E : b->SetLabel(2, "debug-end", BlockGraph::DEBUG_END_LABEL);
363 E : EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
364 E : }
365 :
366 E : TEST_F(PETransformPolicyTest, DirectReferencesFromCodeAreClConsistent) {
367 E : BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
368 E : BlockGraph::Block* code2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c2");
369 E : BlockGraph::Block* data1 = image_.AddBlock(BlockGraph::DATA_BLOCK, 40, "d1");
370 :
371 : // Direct code reference.
372 : EXPECT_TRUE(code1->SetReference(
373 E : 0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code2, 0, 0)));
374 :
375 : // Direct data reference.
376 : EXPECT_TRUE(code1->SetReference(
377 E : 4, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, data1, 0, 0)));
378 :
379 : // Direct self-reference.
380 : EXPECT_TRUE(code1->SetReference(
381 E : 8, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code1, 4, 4)));
382 :
383 E : TestPETransformPolicy policy;
384 E : EXPECT_TRUE(policy.CodeBlockReferencesAreClConsistent(code1));
385 E : }
386 :
387 : TEST_F(PETransformPolicyTest,
388 E : IndirectReferencesFromCodeToCodeAreNotClConsistent) {
389 E : BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
390 E : BlockGraph::Block* code2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c2");
391 :
392 : // Indirect code reference.
393 : EXPECT_TRUE(code1->SetReference(
394 E : 0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code2, 0, 4)));
395 :
396 E : TestPETransformPolicy policy;
397 E : EXPECT_FALSE(policy.CodeBlockReferencesAreClConsistent(code1));
398 E : }
399 :
400 E : TEST_F(PETransformPolicyTest, IndirectReferencesFromCodeToDataAreClConsistent) {
401 E : BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
402 E : BlockGraph::Block* data1 = image_.AddBlock(BlockGraph::DATA_BLOCK, 40, "d1");
403 :
404 : // Indirect data reference.
405 : EXPECT_TRUE(code1->SetReference(
406 E : 0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, data1, 0, 4)));
407 :
408 E : TestPETransformPolicy policy;
409 E : EXPECT_TRUE(policy.CodeBlockReferencesAreClConsistent(code1));
410 E : }
411 :
412 : TEST_F(PETransformPolicyTest,
413 E : IndirectSelfReferencesFromCodeAreNotClConsistent) {
414 E : BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
415 :
416 : // Indirect self reference.
417 : EXPECT_TRUE(code1->SetReference(
418 E : 0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code1, 4, 8)));
419 :
420 E : TestPETransformPolicy policy;
421 E : EXPECT_FALSE(policy.CodeBlockReferencesAreClConsistent(code1));
422 E : }
423 :
424 E : TEST_F(PETransformPolicyTest, CodeBlockReferrersAreClConsistent) {
425 : // These are all the possible input values to be explored.
426 : const ReferenceSource kRefSource[] = {
427 E : kSelfCode, kSelfData, kCodeBlock, kDataBlock };
428 : const ReferenceTarget kRefTarget[] = {
429 E : kTopOfBlock, kInCode, kDataLabel, kInData };
430 : const BlockGraph::ReferenceType kRefType[] = {
431 E : BlockGraph::PC_RELATIVE_REF, BlockGraph::ABSOLUTE_REF,
432 E : BlockGraph::RELATIVE_REF, BlockGraph::FILE_OFFSET_REF };
433 E : const size_t kRefSize[] = { 1, 4 };
434 E : const bool kRefIsDirect[] = { false, true };
435 :
436 : static size_t kNumberOfPermutations =
437 : arraysize(kRefSource) * arraysize(kRefTarget) * arraysize(kRefType) *
438 : arraysize(kRefSize) * arraysize(kRefIsDirect);
439 :
440 : // This is the short list of permutations that we expect to be valid. All
441 : // others should be false.
442 : const ReferrerConfiguration kValidConfigs[] = {
443 : // Self-references from code to code.
444 E : { kSelfCode, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 1, true },
445 E : { kSelfCode, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 4, true },
446 E : { kSelfCode, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
447 E : { kSelfCode, kInCode, BlockGraph::PC_RELATIVE_REF, 1, true },
448 E : { kSelfCode, kInCode, BlockGraph::PC_RELATIVE_REF, 4, true },
449 E : { kSelfCode, kInCode, BlockGraph::ABSOLUTE_REF, 4, true },
450 :
451 : // Self-references from code to data.
452 E : { kSelfCode, kDataLabel, BlockGraph::ABSOLUTE_REF, 4, true },
453 :
454 : // Self-references from data to code.
455 E : { kSelfData, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
456 E : { kSelfData, kInCode, BlockGraph::ABSOLUTE_REF, 4, true },
457 :
458 : // Self-references from data to data.
459 E : { kSelfData, kDataLabel, BlockGraph::ABSOLUTE_REF, 4, true },
460 E : { kSelfData, kInData, BlockGraph::ABSOLUTE_REF, 4, true },
461 :
462 : // External references from code to code.
463 E : { kCodeBlock, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 4, true },
464 E : { kCodeBlock, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
465 :
466 : // External references from data to code.
467 E : { kDataBlock, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
468 E : { kDataBlock, kTopOfBlock, BlockGraph::RELATIVE_REF, 4, true },
469 : };
470 E : std::set<ReferrerConfiguration> valid_configs;
471 E : for (size_t i = 0; i < arraysize(kValidConfigs); ++i) {
472 E : ASSERT_TRUE(valid_configs.insert(kValidConfigs[i]).second);
473 E : }
474 :
475 : // Walk through all possible permutations.
476 E : for (size_t i = 0; i < kNumberOfPermutations; ++i) {
477 E : size_t j = i;
478 :
479 E : ReferenceSource ref_source = kRefSource[j % arraysize(kRefSource)];
480 E : j /= arraysize(kRefSource);
481 :
482 E : ReferenceTarget ref_target = kRefTarget[j % arraysize(kRefTarget)];
483 E : j /= arraysize(kRefTarget);
484 :
485 E : BlockGraph::ReferenceType ref_type = kRefType[j % arraysize(kRefType)];
486 E : j /= arraysize(kRefType);
487 :
488 E : size_t ref_size = kRefSize[j % arraysize(kRefSize)];
489 E : j /= arraysize(kRefSize);
490 :
491 E : bool ref_is_direct = kRefIsDirect[j % arraysize(kRefIsDirect)];
492 :
493 : // If the reference type and size is not valid, skip this test.
494 E : if (!BlockGraph::Reference::IsValidTypeSize(ref_type, ref_size))
495 E : continue;
496 :
497 E : ReferrerConfiguration config = { ref_source, ref_target, ref_type,
498 E : ref_size, ref_is_direct };
499 :
500 E : bool expect_valid = valid_configs.count(config);
501 : ASSERT_NO_FATAL_FAILURE(TestCodeBlockReferrersAreClConsistent(
502 E : config, expect_valid));
503 E : }
504 E : }
505 :
506 : TEST_F(PETransformPolicyTest,
507 E : CodeBlockReferrersAreClConsistentUnreferencedLabels) {
508 E : BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
509 E : const BlockGraph::Offset kDataLabelOffset = 0x10;
510 : code->SetLabel(kDataLabelOffset,
511 E : BlockGraph::Label("data", BlockGraph::DATA_LABEL));
512 :
513 : // We have a single unreferenced data label.
514 E : TestPETransformPolicy policy;
515 E : ASSERT_FALSE(policy.CodeBlockReferrersAreClConsistent(code));
516 :
517 : BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF,
518 : sizeof(core::AbsoluteAddress),
519 : code,
520 : kDataLabelOffset,
521 E : kDataLabelOffset);
522 : // Add a reference from code to the data label.
523 E : code->SetReference(kDataLabelOffset - 0x8, ref);
524 :
525 : // We're now consistent.
526 E : ASSERT_TRUE(policy.CodeBlockReferrersAreClConsistent(code));
527 :
528 : // Remove the reference and move it into code.
529 E : code->RemoveReference(kDataLabelOffset - 0x8);
530 E : code->SetReference(kDataLabelOffset + 0x8, ref);
531 :
532 : // Consistent again.
533 E : ASSERT_TRUE(policy.CodeBlockReferrersAreClConsistent(code));
534 E : }
535 :
536 : TEST_F(PETransformPolicyTest,
537 E : CodeBlockReferrersAreClConsistentUnreferencedData) {
538 E : BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
539 : ASSERT_TRUE(code->SetLabel(20, BlockGraph::Label(
540 E : "data", BlockGraph::DATA_LABEL)));
541 E : TestPETransformPolicy policy;
542 E : ASSERT_FALSE(policy.CodeBlockReferrersAreClConsistent(code));
543 E : }
544 :
545 : TEST_F(PETransformPolicyTest,
546 E : CodeBlockIsSafeToBasicBlockDecomposeableSimpleBlock) {
547 E : BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
548 E : code->SetLabel(0, "code", BlockGraph::CODE_LABEL);
549 E : TestPETransformPolicy policy;
550 E : ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
551 E : }
552 :
553 : TEST_F(PETransformPolicyTest,
554 E : CodeBlockIsSafeToBasicBlockDecomposeBuiltBySyzygy) {
555 E : BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
556 E : code->set_attribute(BlockGraph::BUILT_BY_SYZYGY);
557 E : TestPETransformPolicy policy;
558 E : ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
559 :
560 : // Even if this block has unreferenced data, it should be fine.
561 : ASSERT_TRUE(code->SetLabel(20, BlockGraph::Label(
562 E : "data", BlockGraph::DATA_LABEL)));
563 E : ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
564 E : }
565 :
566 E : TEST_F(PETransformPolicyTest, DataBlockIsNotSafeToBasicBlockDecompose) {
567 E : TestPETransformPolicy policy;
568 :
569 E : BlockGraph::Block* data = image_.AddBlock(BlockGraph::DATA_BLOCK, 1, "d");
570 E : ASSERT_FALSE(policy.BlockIsSafeToBasicBlockDecompose(data));
571 E : }
572 :
573 E : TEST_F(PETransformPolicyTest, CodeBlockIsSafeToBasicBlockDecomposeCache) {
574 E : TestPETransformPolicy policy;
575 E : EXPECT_EQ(0u, policy.block_result_cache_->size());
576 :
577 E : BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "c");
578 E : code->SetLabel(0, "code", BlockGraph::CODE_LABEL);
579 E : ASSERT_TRUE(policy.BlockIsSafeToBasicBlockDecompose(code));
580 E : EXPECT_EQ(1u, policy.block_result_cache_->size());
581 :
582 : TestPETransformPolicy::BlockResultCache::const_iterator it =
583 E : policy.block_result_cache_->find(code->id());
584 E : ASSERT_NE(policy.block_result_cache_->end(), it);
585 E : EXPECT_EQ(code->id(), it->first);
586 E : EXPECT_TRUE(it->second);
587 :
588 : // Add an unreferenced data label. This should make the analysis fail.
589 : // However, it should be looked up in the cache and return true.
590 : ASSERT_TRUE(code->SetLabel(1, BlockGraph::Label(
591 E : "data", BlockGraph::DATA_LABEL)));
592 E : ASSERT_FALSE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
593 E : ASSERT_TRUE(policy.BlockIsSafeToBasicBlockDecompose(code));
594 E : EXPECT_EQ(1u, policy.block_result_cache_->size());
595 E : }
596 :
597 E : TEST_F(PETransformPolicyTest, ReferenceIsSafeToRedirect) {
598 E : TestPETransformPolicy policy;
599 E : BlockGraph bg;
600 E : BlockGraph::Block* b = bg.AddBlock(BlockGraph::CODE_BLOCK, 1, "");
601 E : BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF, 4, b, 0, 0);
602 E : EXPECT_TRUE(policy.ReferenceIsSafeToRedirect(b, ref));
603 E : }
604 :
605 E : TEST_F(PETransformPolicyTest, BasicBlockDisassemblyFilterOldDecomposer) {
606 E : ASSERT_NO_FATAL_FAILURE(TestBasicBlockDisassemblyFilter(true));
607 E : }
608 :
609 E : TEST_F(PETransformPolicyTest, BasicBlockDisassemblyFilterNewDecomposer) {
610 E : ASSERT_NO_FATAL_FAILURE(TestBasicBlockDisassemblyFilter(false));
611 E : }
612 :
613 : } // namespace pe
|