Coverage for /Syzygy/pe/pe_transform_policy_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%3423420.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  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

Coverage information generated Wed Dec 11 11:34:16 2013.