Coverage for /Syzygy/pe/pe_transform_policy_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%3253250.C++test

Line-by-line coverage:

   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    :    BlockGraph image_;
 160    :  };
 161    :  
 162    :  }  // namespace
 163    :  
 164  E :  TEST_F(PETransformPolicyTest, AccessorsAndMutators) {
 165  E :    TestPETransformPolicy policy;
 166  E :    EXPECT_FALSE(policy.allow_inline_assembly());
 167  E :    policy.set_allow_inline_assembly(true);
 168  E :    EXPECT_TRUE(policy.allow_inline_assembly());
 169  E :    policy.set_allow_inline_assembly(false);
 170  E :    EXPECT_FALSE(policy.allow_inline_assembly());
 171  E :  }
 172    :  
 173    :  TEST_F(PETransformPolicyTest,
 174  E :         CodeBlockAttributesAreBasicBlockSafeGapBlock) {
 175  E :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::GAP_BLOCK, false, false));
 176  E :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::GAP_BLOCK, true, false));
 177  E :  }
 178    :  
 179    :  TEST_F(PETransformPolicyTest,
 180  E :         CodeBlockAttributesAreBasicBlockSafePaddingBlock) {
 181    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 182  E :        BlockGraph::PADDING_BLOCK, false, false));
 183    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 184  E :        BlockGraph::PADDING_BLOCK, true, false));
 185  E :  }
 186    :  
 187    :  TEST_F(PETransformPolicyTest,
 188  E :         CodeBlockAttributesAreBasicBlockSafeHasInlineAssembly) {
 189    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 190  E :        BlockGraph::HAS_INLINE_ASSEMBLY, false, false));
 191    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 192  E :        BlockGraph::HAS_INLINE_ASSEMBLY, true, true));
 193  E :  }
 194    :  
 195    :  TEST_F(PETransformPolicyTest,
 196  E :         CodeBlockAttributesAreBasicBlockSafeUnsupportedCompiler) {
 197    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 198  E :        BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER, false, false));
 199    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 200  E :        BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER, true, false));
 201  E :  }
 202    :  
 203    :  TEST_F(PETransformPolicyTest,
 204  E :         CodeBlockAttributesAreBasicBlockSafeUnsupportedInstructions) {
 205    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 206  E :        BlockGraph::UNSUPPORTED_INSTRUCTIONS, false, false));
 207    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 208  E :        BlockGraph::UNSUPPORTED_INSTRUCTIONS, true, false));
 209  E :  }
 210    :  
 211    :  TEST_F(PETransformPolicyTest,
 212  E :         CodeBlockAttributesAreBasicBlockSafeExceptionHandling) {
 213    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 214  E :        BlockGraph::HAS_EXCEPTION_HANDLING, false, false));
 215    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 216  E :        BlockGraph::HAS_EXCEPTION_HANDLING, true, false));
 217  E :  }
 218    :  
 219    :  TEST_F(PETransformPolicyTest,
 220  E :         CodeBlockAttributesAreBasicBlockSafeBuiltBySyzygy) {
 221    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 222    :        BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER | BlockGraph::BUILT_BY_SYZYGY,
 223    :        false,
 224  E :        true));
 225    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 226    :        BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER | BlockGraph::BUILT_BY_SYZYGY,
 227    :        true,
 228  E :        true));
 229  E :  }
 230    :  
 231  E :  TEST_F(PETransformPolicyTest, CodeBlockHasPrivateSymbols) {
 232  E :    TestPETransformPolicy policy;
 233    :  
 234  E :    pe::PEFile pe_file;
 235  E :    block_graph::BlockGraph block_graph;
 236  E :    pe::ImageLayout image_layout(&block_graph);
 237  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll(&pe_file, &image_layout));
 238    :  
 239  E :    size_t count = 0;
 240  E :    BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
 241  E :    for (; it != block_graph.blocks().end(); ++it) {
 242  E :      if (it->second.type() != BlockGraph::CODE_BLOCK)
 243  E :        continue;
 244  E :      if (it->second.attributes() & BlockGraph::PADDING_BLOCK)
 245  E :        continue;
 246    :  
 247  E :      if (!policy.CodeBlockHasPrivateSymbols(&it->second)) {
 248  E :        ++count;
 249  E :        EXPECT_EQ(it->second.name(), "TestFunctionWithNoPrivateSymbols");
 250    :      }
 251  E :    }
 252  E :    EXPECT_EQ(1u, count);
 253  E :  }
 254    :  
 255  E :  TEST_F(PETransformPolicyTest, NoLabelsHasInvalidLayout) {
 256  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
 257  E :    TestPETransformPolicy policy;
 258  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 259  E :  }
 260    :  
 261  E :  TEST_F(PETransformPolicyTest, CodeLabelPastEndHasInvalidLayout) {
 262  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
 263  E :    b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 264  E :    b->SetLabel(2, "code", BlockGraph::CODE_LABEL);
 265  E :    TestPETransformPolicy policy;
 266  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 267  E :  }
 268    :  
 269  E :  TEST_F(PETransformPolicyTest, DataLabelPastEndHasInvalidLayout) {
 270  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
 271  E :    b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 272  E :    b->SetLabel(2, "data", BlockGraph::DATA_LABEL);
 273  E :    TestPETransformPolicy policy;
 274  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 275  E :  }
 276    :  
 277  E :  TEST_F(PETransformPolicyTest, DebugEndInBlockAfterDataHasInvalidLayout) {
 278  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 3, "code");
 279  E :    b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 280  E :    b->SetLabel(1, "data", BlockGraph::DATA_LABEL);
 281  E :    b->SetLabel(2, "debug-end", BlockGraph::DEBUG_END_LABEL);
 282  E :    TestPETransformPolicy policy;
 283  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 284  E :  }
 285    :  
 286  E :  TEST_F(PETransformPolicyTest, CodeAfterDataHasInvalidLayout) {
 287  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
 288  E :    b->SetLabel(0, "data", BlockGraph::DATA_LABEL);
 289  E :    b->SetLabel(1, "code", BlockGraph::CODE_LABEL);
 290  E :    TestPETransformPolicy policy;
 291  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 292  E :  }
 293    :  
 294  E :  TEST_F(PETransformPolicyTest, DataSurroundedByCodeHasInvalidLayout) {
 295  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 3, "code");
 296  E :    b->SetLabel(0, "data", BlockGraph::DATA_LABEL);
 297  E :    b->SetLabel(1, "code", BlockGraph::CODE_LABEL);
 298  E :    b->SetLabel(2, "data", BlockGraph::DATA_LABEL);
 299  E :    TestPETransformPolicy policy;
 300  E :    EXPECT_FALSE(policy.CodeBlockLayoutIsClConsistent(b));
 301  E :  }
 302    :  
 303  E :  TEST_F(PETransformPolicyTest, CodeOnlyHasValidLayout) {
 304  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
 305  E :    b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 306  E :    TestPETransformPolicy policy;
 307  E :    EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
 308    :  
 309    :    // This should still be true even with a debug-end label beyond the end.
 310  E :    b->SetLabel(1, "debug-end", BlockGraph::DEBUG_END_LABEL);
 311  E :    EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
 312  E :  }
 313    :  
 314  E :  TEST_F(PETransformPolicyTest, CodeFollowedByDataHasValidLayout) {
 315  E :    BlockGraph::Block* b = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "code");
 316  E :    b->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 317  E :    b->SetLabel(1, "data", BlockGraph::DATA_LABEL);
 318    :  
 319  E :    TestPETransformPolicy policy;
 320  E :    EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
 321    :  
 322    :    // This should still be true even with a debug-end label beyond the end.
 323  E :    b->SetLabel(2, "debug-end", BlockGraph::DEBUG_END_LABEL);
 324  E :    EXPECT_TRUE(policy.CodeBlockLayoutIsClConsistent(b));
 325  E :  }
 326    :  
 327  E :  TEST_F(PETransformPolicyTest, DirectReferencesFromCodeAreClConsistent) {
 328  E :    BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
 329  E :    BlockGraph::Block* code2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c2");
 330  E :    BlockGraph::Block* data1 = image_.AddBlock(BlockGraph::DATA_BLOCK, 40, "d1");
 331    :  
 332    :    // Direct code reference.
 333    :    EXPECT_TRUE(code1->SetReference(
 334  E :        0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code2, 0, 0)));
 335    :  
 336    :    // Direct data reference.
 337    :    EXPECT_TRUE(code1->SetReference(
 338  E :        4, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, data1, 0, 0)));
 339    :  
 340    :    // Direct self-reference.
 341    :    EXPECT_TRUE(code1->SetReference(
 342  E :        8, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code1, 4, 4)));
 343    :  
 344  E :    TestPETransformPolicy policy;
 345  E :    EXPECT_TRUE(policy.CodeBlockReferencesAreClConsistent(code1));
 346  E :  }
 347    :  
 348    :  TEST_F(PETransformPolicyTest,
 349  E :         IndirectReferencesFromCodeToCodeAreNotClConsistent) {
 350  E :    BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
 351  E :    BlockGraph::Block* code2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c2");
 352    :  
 353    :    // Indirect code reference.
 354    :    EXPECT_TRUE(code1->SetReference(
 355  E :        0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code2, 0, 4)));
 356    :  
 357  E :    TestPETransformPolicy policy;
 358  E :    EXPECT_FALSE(policy.CodeBlockReferencesAreClConsistent(code1));
 359  E :  }
 360    :  
 361  E :  TEST_F(PETransformPolicyTest, IndirectReferencesFromCodeToDataAreClConsistent) {
 362  E :    BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
 363  E :    BlockGraph::Block* data1 = image_.AddBlock(BlockGraph::DATA_BLOCK, 40, "d1");
 364    :  
 365    :    // Indirect data reference.
 366    :    EXPECT_TRUE(code1->SetReference(
 367  E :        0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, data1, 0, 4)));
 368    :  
 369  E :    TestPETransformPolicy policy;
 370  E :    EXPECT_TRUE(policy.CodeBlockReferencesAreClConsistent(code1));
 371  E :  }
 372    :  
 373    :  TEST_F(PETransformPolicyTest,
 374  E :         IndirectSelfReferencesFromCodeAreNotClConsistent) {
 375  E :    BlockGraph::Block* code1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c1");
 376    :  
 377    :    // Indirect self reference.
 378    :    EXPECT_TRUE(code1->SetReference(
 379  E :        0, BlockGraph::Reference(BlockGraph::RELATIVE_REF, 4, code1, 4, 8)));
 380    :  
 381  E :    TestPETransformPolicy policy;
 382  E :    EXPECT_FALSE(policy.CodeBlockReferencesAreClConsistent(code1));
 383  E :  }
 384    :  
 385  E :  TEST_F(PETransformPolicyTest, CodeBlockReferrersAreClConsistent) {
 386    :    // These are all the possible input values to be explored.
 387    :    const ReferenceSource kRefSource[] = {
 388  E :        kSelfCode, kSelfData, kCodeBlock, kDataBlock };
 389    :    const ReferenceTarget kRefTarget[] = {
 390  E :        kTopOfBlock, kInCode, kDataLabel, kInData };
 391    :    const BlockGraph::ReferenceType kRefType[] = {
 392    :        BlockGraph::PC_RELATIVE_REF, BlockGraph::ABSOLUTE_REF,
 393  E :        BlockGraph::RELATIVE_REF, BlockGraph::FILE_OFFSET_REF };
 394  E :    const size_t kRefSize[] = { 1, 4 };
 395  E :    const bool kRefIsDirect[] = { false, true };
 396    :  
 397    :    static size_t kNumberOfPermutations =
 398    :        arraysize(kRefSource) * arraysize(kRefTarget) * arraysize(kRefType) *
 399    :        arraysize(kRefSize) * arraysize(kRefIsDirect);
 400    :  
 401    :    // This is the short list of permutations that we expect to be valid. All
 402    :    // others should be false.
 403    :    const ReferrerConfiguration kValidConfigs[] = {
 404    :        // Self-references from code to code.
 405    :        { kSelfCode, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 1, true },
 406    :        { kSelfCode, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 4, true },
 407    :        { kSelfCode, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
 408    :        { kSelfCode, kInCode, BlockGraph::PC_RELATIVE_REF, 1, true },
 409    :        { kSelfCode, kInCode, BlockGraph::PC_RELATIVE_REF, 4, true },
 410    :        { kSelfCode, kInCode, BlockGraph::ABSOLUTE_REF, 4, true },
 411    :  
 412    :        // Self-references from code to data.
 413    :        { kSelfCode, kDataLabel, BlockGraph::ABSOLUTE_REF, 4, true },
 414    :  
 415    :        // Self-references from data to code.
 416    :        { kSelfData, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
 417    :        { kSelfData, kInCode, BlockGraph::ABSOLUTE_REF, 4, true },
 418    :  
 419    :        // Self-references from data to data.
 420    :        { kSelfData, kDataLabel, BlockGraph::ABSOLUTE_REF, 4, true },
 421    :        { kSelfData, kInData, BlockGraph::ABSOLUTE_REF, 4, true },
 422    :  
 423    :        // External references from code to code.
 424    :        { kCodeBlock, kTopOfBlock, BlockGraph::PC_RELATIVE_REF, 4, true },
 425    :        { kCodeBlock, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
 426    :  
 427    :        // External references from data to code.
 428    :        { kDataBlock, kTopOfBlock, BlockGraph::ABSOLUTE_REF, 4, true },
 429    :        { kDataBlock, kTopOfBlock, BlockGraph::RELATIVE_REF, 4, true },
 430  E :    };
 431  E :    std::set<ReferrerConfiguration> valid_configs;
 432  E :    for (size_t i = 0; i < arraysize(kValidConfigs); ++i) {
 433  E :      ASSERT_TRUE(valid_configs.insert(kValidConfigs[i]).second);
 434  E :    }
 435    :  
 436    :    // Walk through all possible permutations.
 437  E :    for (size_t i = 0; i < kNumberOfPermutations; ++i) {
 438  E :      size_t j = i;
 439    :  
 440  E :      ReferenceSource ref_source = kRefSource[j % arraysize(kRefSource)];
 441  E :      j /= arraysize(kRefSource);
 442    :  
 443  E :      ReferenceTarget ref_target = kRefTarget[j % arraysize(kRefTarget)];
 444  E :      j /= arraysize(kRefTarget);
 445    :  
 446  E :      BlockGraph::ReferenceType ref_type = kRefType[j % arraysize(kRefType)];
 447  E :      j /= arraysize(kRefType);
 448    :  
 449  E :      size_t ref_size = kRefSize[j % arraysize(kRefSize)];
 450  E :      j /= arraysize(kRefSize);
 451    :  
 452  E :      bool ref_is_direct = kRefIsDirect[j % arraysize(kRefIsDirect)];
 453    :  
 454    :      // If the reference type and size is not valid, skip this test.
 455  E :      if (!BlockGraph::Reference::IsValidTypeSize(ref_type, ref_size))
 456  E :        continue;
 457    :  
 458    :      ReferrerConfiguration config = { ref_source, ref_target, ref_type,
 459  E :          ref_size, ref_is_direct };
 460    :  
 461  E :      bool expect_valid = valid_configs.count(config);
 462    :      ASSERT_NO_FATAL_FAILURE(TestCodeBlockReferrersAreClConsistent(
 463  E :          config, expect_valid));
 464  E :    }
 465  E :  }
 466    :  
 467    :  TEST_F(PETransformPolicyTest,
 468  E :         CodeBlockReferrersAreClConsistentUnreferencedLabels) {
 469  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
 470  E :    const BlockGraph::Offset kDataLabelOffset = 0x10;
 471    :    code->SetLabel(kDataLabelOffset,
 472  E :                   BlockGraph::Label("data", BlockGraph::DATA_LABEL));
 473    :  
 474    :    // We have a single unreferenced data label.
 475  E :    TestPETransformPolicy policy;
 476  E :    ASSERT_FALSE(policy.CodeBlockReferrersAreClConsistent(code));
 477    :  
 478    :    BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF,
 479    :                              sizeof(core::AbsoluteAddress),
 480    :                              code,
 481    :                              kDataLabelOffset,
 482  E :                              kDataLabelOffset);
 483    :    // Add a reference from code to the data label.
 484  E :    code->SetReference(kDataLabelOffset - 0x8, ref);
 485    :  
 486    :    // We're now consistent.
 487  E :    ASSERT_TRUE(policy.CodeBlockReferrersAreClConsistent(code));
 488    :  
 489    :    // Remove the reference and move it into code.
 490  E :    code->RemoveReference(kDataLabelOffset - 0x8);
 491  E :    code->SetReference(kDataLabelOffset + 0x8, ref);
 492    :  
 493    :    // Consistent again.
 494  E :    ASSERT_TRUE(policy.CodeBlockReferrersAreClConsistent(code));
 495  E :  }
 496    :  
 497    :  TEST_F(PETransformPolicyTest,
 498  E :         CodeBlockReferrersAreClConsistentUnreferencedData) {
 499  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
 500    :    ASSERT_TRUE(code->SetLabel(20, BlockGraph::Label(
 501  E :        "data", BlockGraph::DATA_LABEL)));
 502  E :    TestPETransformPolicy policy;
 503  E :    ASSERT_FALSE(policy.CodeBlockReferrersAreClConsistent(code));
 504  E :  }
 505    :  
 506    :  TEST_F(PETransformPolicyTest,
 507  E :         CodeBlockIsSafeToBasicBlockDecomposeableSimpleBlock) {
 508  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 1, "code");
 509  E :    code->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 510  E :    TestPETransformPolicy policy;
 511  E :    ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
 512  E :  }
 513    :  
 514    :  TEST_F(PETransformPolicyTest,
 515  E :         CodeBlockIsSafeToBasicBlockDecomposeBuiltBySyzygy) {
 516  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
 517  E :    code->set_attribute(BlockGraph::BUILT_BY_SYZYGY);
 518  E :    TestPETransformPolicy policy;
 519  E :    ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
 520    :  
 521    :    // Even if this block has unreferenced data, it should be fine.
 522    :    ASSERT_TRUE(code->SetLabel(20, BlockGraph::Label(
 523  E :        "data", BlockGraph::DATA_LABEL)));
 524  E :    ASSERT_TRUE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
 525  E :  }
 526    :  
 527  E :  TEST_F(PETransformPolicyTest, DataBlockIsNotSafeToBasicBlockDecompose) {
 528  E :    TestPETransformPolicy policy;
 529    :  
 530  E :    BlockGraph::Block* data = image_.AddBlock(BlockGraph::DATA_BLOCK, 1, "d");
 531  E :    ASSERT_FALSE(policy.BlockIsSafeToBasicBlockDecompose(data));
 532  E :  }
 533    :  
 534  E :  TEST_F(PETransformPolicyTest, CodeBlockIsSafeToBasicBlockDecomposeCache) {
 535  E :    TestPETransformPolicy policy;
 536  E :    EXPECT_EQ(0u, policy.block_result_cache_->size());
 537    :  
 538  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "c");
 539  E :    code->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 540  E :    ASSERT_TRUE(policy.BlockIsSafeToBasicBlockDecompose(code));
 541  E :    EXPECT_EQ(1u, policy.block_result_cache_->size());
 542    :  
 543    :    TestPETransformPolicy::BlockResultCache::const_iterator it =
 544  E :        policy.block_result_cache_->find(code->id());
 545  E :    ASSERT_NE(policy.block_result_cache_->end(), it);
 546  E :    EXPECT_EQ(code->id(), it->first);
 547  E :    EXPECT_TRUE(it->second);
 548    :  
 549    :    // Add an unreferenced data label. This should make the analysis fail.
 550    :    // However, it should be looked up in the cache and return true.
 551    :    ASSERT_TRUE(code->SetLabel(1, BlockGraph::Label(
 552  E :        "data", BlockGraph::DATA_LABEL)));
 553  E :    ASSERT_FALSE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
 554  E :    ASSERT_TRUE(policy.BlockIsSafeToBasicBlockDecompose(code));
 555  E :    EXPECT_EQ(1u, policy.block_result_cache_->size());
 556  E :  }
 557    :  
 558    :  TEST_F(PETransformPolicyTest,
 559  E :         CodeBlockIsSafeToBasicBlockDecomposeAttributesNotCached) {
 560  E :    TestPETransformPolicy policy;
 561  E :    EXPECT_EQ(0u, policy.block_result_cache_->size());
 562    :  
 563  E :    BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 2, "c");
 564  E :    code->SetLabel(0, "code", BlockGraph::CODE_LABEL);
 565  E :    ASSERT_TRUE(policy.BlockIsSafeToBasicBlockDecompose(code));
 566  E :    EXPECT_EQ(1u, policy.block_result_cache_->size());
 567    :  
 568    :    TestPETransformPolicy::BlockResultCache::const_iterator it =
 569  E :        policy.block_result_cache_->find(code->id());
 570  E :    ASSERT_NE(policy.block_result_cache_->end(), it);
 571  E :    EXPECT_EQ(code->id(), it->first);
 572  E :    EXPECT_TRUE(it->second);
 573    :  
 574    :    // Set an attribute that disqualifies decomposition. This should return false
 575    :    // from both functions, ignoring the cached result.
 576  E :    code->set_attribute(BlockGraph::UNSUPPORTED_INSTRUCTIONS);
 577  E :    ASSERT_FALSE(policy.CodeBlockIsSafeToBasicBlockDecompose(code));
 578  E :    ASSERT_FALSE(policy.BlockIsSafeToBasicBlockDecompose(code));
 579  E :    EXPECT_EQ(1u, policy.block_result_cache_->size());
 580  E :  }
 581    :  
 582  E :  TEST_F(PETransformPolicyTest, ReferenceIsSafeToRedirect) {
 583  E :    TestPETransformPolicy policy;
 584  E :    BlockGraph bg;
 585  E :    BlockGraph::Block* b = bg.AddBlock(BlockGraph::CODE_BLOCK, 1, "");
 586  E :    BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF, 4, b, 0, 0);
 587  E :    EXPECT_TRUE(policy.ReferenceIsSafeToRedirect(b, ref));
 588  E :  }
 589    :  
 590  E :  TEST_F(PETransformPolicyTest, BasicBlockDisassemblyFilter) {
 591  E :    TestPETransformPolicy policy;
 592    :  
 593  E :    pe::PEFile pe_file;
 594  E :    block_graph::BlockGraph block_graph;
 595  E :    pe::ImageLayout image_layout(&block_graph);
 596  E :    ASSERT_NO_FATAL_FAILURE(DecomposeTestDll(&pe_file, &image_layout));
 597    :  
 598  E :    BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
 599  E :    for (; it != block_graph.blocks().end(); ++it) {
 600  E :      if (!policy.BlockIsSafeToBasicBlockDecompose(&it->second))
 601  E :        continue;
 602    :  
 603    :      // Basic-block decomposition should not fail.
 604  E :      block_graph::BasicBlockSubGraph bbsg;
 605  E :      block_graph::BasicBlockDecomposer bbdecomp(&it->second, &bbsg);
 606  E :      EXPECT_TRUE(bbdecomp.Decompose());
 607  E :    }
 608  E :  }
 609    :  
 610    :  }  // namespace pe

Coverage information generated Thu Jan 14 17:40:38 2016.