Coverage for /Syzygy/block_graph/basic_block_decomposer_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.9%2692720.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Tests for basic block disassembler.
  16    :  
  17    :  #include "syzygy/block_graph/basic_block_decomposer.h"
  18    :  
  19    :  #include <algorithm>
  20    :  #include <vector>
  21    :  
  22    :  #include "base/bind.h"
  23    :  #include "base/command_line.h"
  24    :  #include "base/files/file_util.h"
  25    :  #include "base/memory/scoped_ptr.h"
  26    :  #include "gmock/gmock.h"
  27    :  #include "gtest/gtest.h"
  28    :  #include "syzygy/block_graph/basic_block_test_util.h"
  29    :  #include "syzygy/block_graph/block_graph_serializer.h"
  30    :  #include "syzygy/core/address.h"
  31    :  #include "syzygy/core/serialization.h"
  32    :  #include "syzygy/core/unittest_util.h"
  33    :  
  34    :  #include "mnemonics.h"  // NOLINT
  35    :  
  36    :  namespace block_graph {
  37    :  
  38    :  namespace {
  39    :  
  40    :  using block_graph::BasicBlock;
  41    :  using block_graph::BasicBlockSubGraph;
  42    :  using block_graph::BlockGraph;
  43    :  using block_graph::BlockGraphSerializer;
  44    :  using block_graph::Successor;
  45    :  using core::AbsoluteAddress;
  46    :  using core::Disassembler;
  47    :  using testing::_;
  48    :  using testing::Return;
  49    :  
  50    :  typedef BlockGraph::Block Block;
  51    :  typedef BlockGraph::Offset Offset;
  52    :  typedef BlockGraph::Reference Reference;
  53    :  typedef BlockGraph::Size Size;
  54    :  
  55    :  // A helper to count basic blocks of a given type.
  56    :  size_t CountBasicBlocks(const BasicBlockSubGraph& subgraph,
  57  E :                          BasicBlock::BasicBlockType type) {
  58  E :    size_t counter = 0;
  59    :    BasicBlockSubGraph::BBCollection::const_iterator bb_it =
  60  E :        subgraph.basic_blocks().begin();
  61  E :    for (; bb_it != subgraph.basic_blocks().end(); ++bb_it) {
  62  E :      if ((*bb_it)->type() == type)
  63  E :        ++counter;
  64  E :    }
  65    :  
  66  E :    return counter;
  67  E :  }
  68    :  
  69    :  // A helper to count padding basic blocks of a given type.
  70    :  size_t CountPaddingBasicBlocks(const BasicBlockSubGraph& subgraph,
  71  E :                                 BasicBlock::BasicBlockType type) {
  72  E :    size_t counter = 0;
  73    :    BasicBlockSubGraph::BBCollection::const_iterator bb_it =
  74  E :        subgraph.basic_blocks().begin();
  75  E :    for (; bb_it != subgraph.basic_blocks().end(); ++bb_it) {
  76  E :      if ((*bb_it)->type() == type && (*bb_it)->is_padding())
  77  E :        ++counter;
  78  E :    }
  79    :  
  80  E :    return counter;
  81  E :  }
  82    :  
  83    :  // A helper comparator to that returns true if lhs and rhs are not adjacent
  84    :  // and in order.
  85  E :  bool HasGapOrIsOutOfOrder(const BasicBlock* lhs, const BasicBlock* rhs) {
  86    :    typedef BasicBlock::Size Size;
  87    :  
  88  E :    Offset lhs_end = lhs->offset();
  89    :  
  90  E :    const BasicCodeBlock* lhs_code = BasicCodeBlock::Cast(lhs);
  91  E :    if (lhs_code != NULL) {
  92  E :      lhs_end += lhs_code->GetInstructionSize();
  93    :  
  94  E :      BasicBlock::Successors::const_iterator it(lhs_code->successors().begin());
  95  E :      for (; it != lhs_code->successors().end(); ++it) {
  96  E :        lhs_end += it->instruction_size();
  97  E :      }
  98    :    }
  99  E :    const BasicDataBlock* lhs_data = BasicDataBlock::Cast(lhs);
 100  E :    if (lhs_data != NULL)
 101  E :      lhs_end += lhs_data->size();
 102    :  
 103  E :    return lhs_end != rhs->offset();
 104  E :  }
 105    :  
 106    :  // A test fixture which generates a block-graph to use for basic-block
 107    :  // related testing.
 108    :  // See: basic_block_assembly_func.asm
 109    :  class BasicBlockDecomposerTest : public testing::BasicBlockTest {
 110    :   public:
 111  E :    void InitBlockGraphFromSerializedFile(const wchar_t* src_relative_path) {
 112  E :      base::FilePath path = testing::GetSrcRelativePath(src_relative_path);
 113  E :      base::ScopedFILE file(base::OpenFile(path, "rb"));
 114  E :      ASSERT_TRUE(file.get() != NULL);
 115  E :      core::FileInStream is(file.get());
 116  E :      core::InArchive ia(&is);
 117  E :      BlockGraphSerializer bgs;
 118  E :      ASSERT_TRUE(bgs.Load(&block_graph_, &ia));
 119  E :    }
 120    :  };
 121    :  
 122    :  // Calculates the net size of all bytes covered by the given basic-block
 123    :  // decomposition.
 124  E :  size_t GetNetBBSize(const BasicBlockSubGraph& bbsg) {
 125    :    // We expect the decomposition to cover the entire block.
 126  E :    size_t net_bb_size = 0;
 127  E :    for (BasicBlockSubGraph::BBCollection::const_iterator bb_it =
 128    :             bbsg.basic_blocks().begin();
 129  E :         bb_it != bbsg.basic_blocks().end();
 130  E :         ++bb_it) {
 131  E :      switch ((*bb_it)->type()) {
 132    :        case BasicBlock::BASIC_CODE_BLOCK: {
 133  E :          const BasicCodeBlock* bcb = BasicCodeBlock::Cast(*bb_it);
 134  E :          CHECK_NE(reinterpret_cast<const BasicCodeBlock*>(NULL), bcb);
 135  E :          net_bb_size += bcb->GetInstructionSize();
 136    :  
 137  E :          for (BasicCodeBlock::Successors::const_iterator succ_it =
 138    :                   bcb->successors().begin();
 139  E :               succ_it != bcb->successors().end();
 140  E :               ++succ_it) {
 141  E :            net_bb_size += succ_it->instruction_size();
 142  E :          }
 143    :  
 144  E :          break;
 145    :        }
 146    :  
 147    :        case BasicBlock::BASIC_DATA_BLOCK: {
 148  i :          const BasicDataBlock* bdb = BasicDataBlock::Cast(*bb_it);
 149  i :          CHECK_NE(reinterpret_cast<const BasicDataBlock*>(NULL), bdb);
 150  i :          net_bb_size += bdb->size();
 151    :          break;
 152    :        }
 153    :      }
 154  E :    }
 155  E :    return net_bb_size;
 156  E :  }
 157    :  
 158    :  struct BasicBlockOffsetComparator {
 159  E :    bool operator()(const BasicBlock* bb0, const BasicBlock* bb1) {
 160  E :      DCHECK_NE(reinterpret_cast<const BasicBlock*>(NULL), bb0);
 161  E :      DCHECK_NE(reinterpret_cast<const BasicBlock*>(NULL), bb1);
 162  E :      return bb0->offset() < bb1->offset();
 163  E :    }
 164    :  };
 165    :  
 166  E :  void ValidateHasInlineAssemblyBlock5677(const BasicBlockSubGraph& bbsg) {
 167  E :    ASSERT_EQ(4u, bbsg.basic_blocks().size());
 168    :  
 169    :    // Get the basic blocks sorted by their original offsets.
 170    :    std::vector<const BasicBlock*> bbs(bbsg.basic_blocks().begin(),
 171  E :                                       bbsg.basic_blocks().end());
 172  E :    std::sort(bbs.begin(), bbs.end(), BasicBlockOffsetComparator());
 173    :  
 174    :    // cachedHasSSE2
 175    :    // bb0:
 176    :    // 0044DA50  push        ebp
 177    :    // 0044DA51  mov         ebp,esp
 178    :    // 0044DA53  mov         eax,1
 179    :    // 0044DA58  sub         esp,14h
 180    :    // 0044DA5B  test        byte ptr ds:[41EA07Ch],al
 181    :    // 0044DA61  jne         bb2
 182  E :    EXPECT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs[0]->type());
 183  E :    const BasicCodeBlock* bcb0 = BasicCodeBlock::Cast(bbs[0]);
 184  E :    ASSERT_NE(reinterpret_cast<const BasicCodeBlock*>(NULL), bcb0);
 185  E :    EXPECT_EQ(0, bcb0->offset());
 186  E :    EXPECT_EQ(5u, bcb0->instructions().size());
 187  E :    EXPECT_EQ(17u, bcb0->GetInstructionSize());
 188  E :    EXPECT_EQ(2u, bcb0->successors().size());
 189    :  
 190    :    // bb1:
 191    :    // 0044DA63  or          dword ptr ds:[41EA07Ch],eax
 192    :    // 0044DA69  xor         eax,eax
 193    :    // 0044DA6B  mov         dword ptr [ebp-14h],eax
 194    :    // 0044DA6E  mov         dword ptr [ebp-10h],eax
 195    :    // 0044DA71  mov         dword ptr [ebp-0Ch],eax
 196    :    // 0044DA74  mov         dword ptr [ebp-8],eax
 197    :    // 0044DA77  push        ebx
 198    :    // 0044DA78  lea         eax,[ebp-14h]
 199    :    // 0044DA7B  push        edi
 200    :    // 0044DA7C  mov         dword ptr [ebp-4],eax
 201    :    // 0044DA7F  mov         eax,1
 202    :    // 0044DA84  cpuid
 203    :    // 0044DA86  mov         edi,dword ptr [ebp-4]
 204    :    // 0044DA89  mov         dword ptr [edi],eax
 205    :    // 0044DA8B  mov         dword ptr [edi+4],ebx
 206    :    // 0044DA8E  mov         dword ptr [edi+8],ecx
 207    :    // 0044DA91  mov         dword ptr [edi+0Ch],edx
 208    :    // 0044DA94  mov         eax,dword ptr [ebp-8]
 209    :    // 0044DA97  shr         eax,1Ah
 210    :    // 0044DA9A  and         al,1
 211    :    // 0044DA9C  pop         edi
 212    :    // 0044DA9D  mov         byte ptr ds:[041EA078h],al
 213    :    // 0044DAA2  pop         ebx
 214    :    // 0044DAA3  mov         esp,ebp
 215    :    // 0044DAA5  pop         ebp
 216    :    // 0044DAA6  ret
 217  E :    EXPECT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs[1]->type());
 218  E :    const BasicCodeBlock* bcb1 = BasicCodeBlock::Cast(bbs[1]);
 219  E :    ASSERT_NE(reinterpret_cast<const BasicCodeBlock*>(NULL), bcb1);
 220  E :    EXPECT_EQ(19, bcb1->offset());
 221  E :    EXPECT_EQ(26u, bcb1->instructions().size());
 222  E :    EXPECT_EQ(68u, bcb1->GetInstructionSize());
 223  E :    EXPECT_EQ(0u, bcb1->successors().size());
 224    :  
 225    :    // bb2:
 226    :    // 0044DAA7  mov         al,byte ptr ds:[041EA078h]
 227    :    // 0044DAAC  mov         esp,ebp
 228    :    // 0044DAAE  pop         ebp
 229    :    // 0044DAAF  ret
 230    :    // 0044DAB0
 231  E :    EXPECT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs[2]->type());
 232  E :    const BasicCodeBlock* bcb2 = BasicCodeBlock::Cast(bbs[2]);
 233  E :    ASSERT_NE(reinterpret_cast<const BasicCodeBlock*>(NULL), bcb2);
 234  E :    EXPECT_EQ(87, bcb2->offset());
 235  E :    EXPECT_EQ(4u, bcb2->instructions().size());
 236  E :    EXPECT_EQ(9u, bcb2->GetInstructionSize());
 237  E :    EXPECT_EQ(0u, bcb2->successors().size());
 238    :  
 239  E :    EXPECT_EQ(BasicBlock::BASIC_END_BLOCK, bbs[3]->type());
 240  E :  }
 241    :  
 242    :  }  // namespace
 243    :  
 244  E :  TEST_F(BasicBlockDecomposerTest, DecomposeNoSubGraph) {
 245  E :    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 246  E :    BasicBlockDecomposer bbd(assembly_func_, NULL);
 247  E :    EXPECT_TRUE(bbd.Decompose());
 248  E :    EXPECT_FALSE(bbd.contains_unsupported_instructions());
 249  E :  }
 250    :  
 251  E :  TEST_F(BasicBlockDecomposerTest, Decompose) {
 252  E :    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 253  E :    ASSERT_NO_FATAL_FAILURE(InitBasicBlockSubGraph());
 254    :  
 255    :    // Ensure we have the expected number and types of blocks.
 256  E :    ASSERT_EQ(kNumBasicBlocks, subgraph_.basic_blocks().size());
 257    :    ASSERT_EQ(kNumCodeBasicBlocks,
 258  E :              CountBasicBlocks(subgraph_, BasicBlock::BASIC_CODE_BLOCK));
 259    :    ASSERT_EQ(kNumDataBasicBlocks,
 260  E :              CountBasicBlocks(subgraph_, BasicBlock::BASIC_DATA_BLOCK));
 261    :    ASSERT_EQ(kNumEndBasicBlocks,
 262  E :              CountBasicBlocks(subgraph_, BasicBlock::BASIC_END_BLOCK));
 263    :    ASSERT_EQ(kNumCodePaddingBasicBlocks,
 264  E :              CountPaddingBasicBlocks(subgraph_, BasicBlock::BASIC_CODE_BLOCK));
 265    :    ASSERT_EQ(kNumDataPaddingBasicBlocks,
 266  E :              CountPaddingBasicBlocks(subgraph_, BasicBlock::BASIC_DATA_BLOCK));
 267    :  
 268    :    // There should be no gaps and all of the blocks should be used.
 269  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 270    :    const BasicBlockSubGraph::BlockDescription& desc =
 271  E :        subgraph_.block_descriptions().back();
 272  E :    EXPECT_EQ(kNumBasicBlocks, desc.basic_block_order.size());
 273    :    EXPECT_TRUE(
 274    :        std::adjacent_find(
 275    :            desc.basic_block_order.begin(),
 276    :            desc.basic_block_order.end(),
 277  E :            &HasGapOrIsOutOfOrder) == desc.basic_block_order.end());
 278    :  
 279  E :    BasicBlockSubGraph::ReachabilityMap rm;
 280  E :    subgraph_.GetReachabilityMap(&rm);
 281    :  
 282    :    // Basic-block 0 - assembly_func.
 283  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[0]));
 284  E :    ASSERT_FALSE(bbs_[0]->is_padding());
 285  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[0]->type());
 286  E :    BasicCodeBlock* bb0 = BasicCodeBlock::Cast(bbs_[0]);
 287  E :    ASSERT_TRUE(bb0 != NULL);
 288  E :    ASSERT_EQ(4u, bb0->instructions().size());
 289  E :    ASSERT_EQ(0u, bb0->successors().size());
 290    :    BasicBlock::Instructions::const_iterator inst_iter =
 291  E :        bb0->instructions().begin();
 292  E :    std::advance(inst_iter, 2);
 293  E :    ASSERT_EQ(1u, inst_iter->references().size());
 294  E :    ASSERT_EQ(bbs_[9], inst_iter->references().begin()->second.basic_block());
 295  E :    std::advance(inst_iter, 1);
 296  E :    ASSERT_EQ(1u, inst_iter->references().size());
 297  E :    ASSERT_EQ(bbs_[8], inst_iter->references().begin()->second.basic_block());
 298  E :    ASSERT_EQ(1u, bbs_[0]->alignment());
 299    :  
 300    :    // Basic-block 1 - unreachable-label.
 301  E :    ASSERT_FALSE(BasicBlockSubGraph::IsReachable(rm, bbs_[1]));
 302  E :    ASSERT_TRUE(bbs_[1]->is_padding());
 303  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[1]->type());
 304  E :    BasicCodeBlock* bb1 = BasicCodeBlock::Cast(bbs_[1]);
 305  E :    ASSERT_EQ(1u, bb1->instructions().size());
 306  E :    ASSERT_EQ(1u, bb1->successors().size());
 307    :    ASSERT_EQ(bbs_[2],
 308  E :              bb1->successors().front().reference().basic_block());
 309  E :    ASSERT_EQ(1u, bb1->alignment());
 310    :  
 311    :    // Basic-block 2 - case_0.
 312  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[2]));
 313  E :    ASSERT_FALSE(bbs_[2]->is_padding());
 314  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[2]->type());
 315  E :    BasicCodeBlock* bb2 = BasicCodeBlock::Cast(bbs_[2]);
 316  E :    ASSERT_TRUE(bb2 != NULL);
 317  E :    ASSERT_EQ(2u, bb2->instructions().size());
 318  E :    ASSERT_EQ(1u, bb2->successors().size());
 319  E :    ASSERT_EQ(bbs_[3], bb2->successors().front().reference().basic_block());
 320  E :    ASSERT_EQ(1u, bbs_[2]->alignment());
 321    :  
 322    :    // Basic-block 3 - sub eax to jnz.
 323  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[3]));
 324  E :    ASSERT_FALSE(bbs_[3]->is_padding());
 325  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[3]->type());
 326  E :    BasicCodeBlock* bb3 = BasicCodeBlock::Cast(bbs_[3]);
 327  E :    ASSERT_TRUE(bb3 != NULL);
 328  E :    ASSERT_EQ(1u, bb3->instructions().size());
 329  E :    ASSERT_EQ(2u, bb3->successors().size());
 330  E :    ASSERT_EQ(bb3, bb3->successors().front().reference().basic_block());
 331  E :    ASSERT_EQ(bbs_[4], bb3->successors().back().reference().basic_block());
 332  E :    ASSERT_EQ(1u, bbs_[3]->alignment());
 333    :  
 334    :    // Basic-block 4 - ret.
 335  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[4]));
 336  E :    ASSERT_FALSE(bbs_[4]->is_padding());
 337  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[4]->type());
 338  E :    BasicCodeBlock* bb4 = BasicCodeBlock::Cast(bbs_[4]);
 339  E :    ASSERT_TRUE(bb4 != NULL);
 340  E :    ASSERT_EQ(1u, bb4->instructions().size());
 341  E :    ASSERT_EQ(0u, bb4->successors().size());
 342  E :    ASSERT_EQ(1u, bbs_[4]->alignment());
 343    :  
 344    :    // Basic-block 5 - case_1.
 345  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[5]));
 346  E :    ASSERT_FALSE(bbs_[5]->is_padding());
 347  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[5]->type());
 348  E :    BasicCodeBlock* bb5 = BasicCodeBlock::Cast(bbs_[5]);
 349  E :    ASSERT_TRUE(bb5 != NULL);
 350  E :    ASSERT_EQ(1u, bb5->instructions().size());
 351    :    ASSERT_EQ(
 352    :        func1_,
 353  E :        bb5->instructions().front().references().begin()->second.block());
 354  E :    ASSERT_EQ(1u, bb5->successors().size());
 355  E :    ASSERT_EQ(bbs_[6], bb5->successors().front().reference().basic_block());
 356  E :    ASSERT_EQ(1u, bbs_[5]->alignment());
 357    :  
 358    :    // Basic-block 6 - case_default.
 359  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[6]));
 360  E :    ASSERT_FALSE(bbs_[6]->is_padding());
 361  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[6]->type());
 362  E :    BasicCodeBlock* bb6 = BasicCodeBlock::Cast(bbs_[6]);
 363  E :    ASSERT_TRUE(bb6 != NULL);
 364  E :    ASSERT_EQ(2u, bb6->instructions().size());
 365    :    ASSERT_EQ(
 366    :        func2_,
 367  E :        bb6->instructions().back().references().begin()->second.block());
 368  E :    ASSERT_EQ(0u, bb6->successors().size());
 369  E :    ASSERT_EQ(1u, bbs_[6]->alignment());
 370    :  
 371    :    // Basic-block 7 - interrupt_label.
 372  E :    ASSERT_FALSE(BasicBlockSubGraph::IsReachable(rm, bbs_[7]));
 373  E :    ASSERT_TRUE(bbs_[7]->is_padding());
 374  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[7]->type());
 375  E :    BasicCodeBlock* bb7 = BasicCodeBlock::Cast(bbs_[7]);
 376  E :    ASSERT_TRUE(bb7 != NULL);
 377  E :    ASSERT_EQ(3u, bb7->instructions().size());
 378  E :    ASSERT_EQ(0u, bb7->successors().size());
 379  E :    ASSERT_EQ(1u, bbs_[7]->alignment());
 380    :  
 381    :    // Basic-block 8 - jump_table.
 382  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[8]));
 383  E :    ASSERT_FALSE(bbs_[8]->is_padding());
 384  E :    ASSERT_EQ(BasicBlock::BASIC_DATA_BLOCK, bbs_[8]->type());
 385  E :    BasicDataBlock* bb8 = BasicDataBlock::Cast(bbs_[8]);
 386  E :    ASSERT_TRUE(bb8 != NULL);
 387  E :    ASSERT_EQ(3 * Reference::kMaximumSize, bb8->size());
 388  E :    ASSERT_EQ(3u, bb8->references().size());
 389  E :    ASSERT_EQ(4u, bbs_[8]->alignment());
 390    :  
 391    :    // Basic-block 9 - case_table.
 392  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[9]));
 393  E :    ASSERT_FALSE(bbs_[9]->is_padding());
 394  E :    ASSERT_EQ(BasicBlock::BASIC_DATA_BLOCK, bbs_[9]->type());
 395  E :    BasicDataBlock* bb9 = BasicDataBlock::Cast(bbs_[9]);
 396  E :    ASSERT_TRUE(bb9 != NULL);
 397  E :    ASSERT_EQ(256, bb9->size());
 398  E :    ASSERT_EQ(0u, bb9->references().size());
 399  E :    ASSERT_EQ(4u, bbs_[9]->alignment());
 400    :  
 401  E :    ASSERT_EQ(BasicBlock::BASIC_END_BLOCK, bbs_[10]->type());
 402    :  
 403    :    // Validate all source ranges.
 404  E :    core::RelativeAddress next_addr(start_addr_);
 405  E :    for (size_t i = 0; i < bbs_.size(); ++i) {
 406  E :      const BasicCodeBlock* code_block = BasicCodeBlock::Cast(bbs_[i]);
 407  E :      const BasicDataBlock* data_block = BasicDataBlock::Cast(bbs_[i]);
 408    :  
 409  E :      if (code_block != NULL) {
 410  E :        ASSERT_TRUE(data_block == NULL);
 411    :  
 412    :        BasicBlock::Instructions::const_iterator instr_it =
 413  E :            code_block->instructions().begin();
 414  E :        for (; instr_it != code_block->instructions().end(); ++instr_it) {
 415  E :          const Instruction& instr = *instr_it;
 416  E :          ASSERT_EQ(next_addr, instr.source_range().start());
 417  E :          ASSERT_EQ(instr.size(), instr.source_range().size());
 418    :  
 419  E :          next_addr += instr.size();
 420  E :        }
 421    :  
 422    :        BasicBlock::Successors::const_iterator succ_it =
 423  E :            code_block->successors().begin();
 424  E :        for (; succ_it != code_block->successors().end(); ++succ_it) {
 425  E :          const Successor& succ = *succ_it;
 426  E :          if (succ.source_range().size() != 0) {
 427  E :            ASSERT_EQ(next_addr, succ.source_range().start());
 428  E :            ASSERT_EQ(succ.instruction_size(), succ.source_range().size());
 429  E :          } else {
 430  E :            ASSERT_EQ(0, succ.instruction_size());
 431    :          }
 432    :  
 433  E :          next_addr += succ.instruction_size();
 434  E :        }
 435    :      }
 436    :  
 437  E :      if (data_block != NULL) {
 438  E :        ASSERT_TRUE(code_block == NULL);
 439  E :        ASSERT_TRUE(data_block->type() == BasicBlock::BASIC_DATA_BLOCK);
 440  E :        ASSERT_EQ(next_addr, data_block->source_range().start());
 441  E :        ASSERT_EQ(data_block->size(), data_block->source_range().size());
 442    :  
 443  E :        next_addr += data_block->size();
 444    :      }
 445  E :    }
 446  E :  }
 447    :  
 448  E :  TEST_F(BasicBlockDecomposerTest, DecomposeBlockWithLabelPastData) {
 449  E :    ASSERT_NO_FATAL_FAILURE(InitBasicBlockSubGraphWithLabelPastEnd());
 450  E :  }
 451    :  
 452  E :  TEST_F(BasicBlockDecomposerTest, HasInlineAssembly) {
 453    :    ASSERT_NO_FATAL_FAILURE(InitBlockGraphFromSerializedFile(
 454  E :        L"syzygy/block_graph/test_data/has_inline_assembly.bg"));
 455    :  
 456    :    BlockGraph::BlockMap::iterator block_it =
 457  E :        block_graph_.blocks_mutable().begin();
 458  E :    for (; block_it != block_graph_.blocks().end(); ++block_it) {
 459  E :      BlockGraph::Block* block = &(block_it->second);
 460    :  
 461    :      // We skip the 'master' blocks. These are simply dummy blocks that act as
 462    :      // sources and destinations for references, to keep the remaining blocks
 463    :      // intact.
 464  E :      if (block->name() == "CodeMaster" || block->name() == "DataMaster")
 465  E :        continue;
 466    :  
 467  E :      BasicBlockSubGraph bbsg;
 468  E :      BasicBlockDecomposer bbd(block, &bbsg);
 469  E :      ASSERT_TRUE(bbd.Decompose());
 470  E :      EXPECT_FALSE(bbd.contains_unsupported_instructions());
 471  E :      EXPECT_EQ(block->size(), GetNetBBSize(bbsg));
 472    :  
 473    :      // Validate a block in detail.
 474  E :      if (block->id() == 5677)
 475  E :        ASSERT_NO_FATAL_FAILURE(ValidateHasInlineAssemblyBlock5677(bbsg));
 476  E :    }
 477  E :  }
 478    :  
 479  E :  TEST_F(BasicBlockDecomposerTest, ContainsJECXZ) {
 480  E :    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 481    :    BlockGraph::Block* jecxz = block_graph_.AddBlock(
 482  E :        BlockGraph::CODE_BLOCK, 4, "jecxz");
 483  E :    ASSERT_TRUE(jecxz != NULL);
 484  E :    jecxz->set_section(text_section_->id());
 485    :  
 486    :    // The following bytes are the assembly of the following code:
 487    :    //   JECXZ done
 488    :    //   DEC ecx
 489    :    //   done:
 490    :    //   RET
 491    :    // The JECXZ instruction has a PC-relative reference at byte 1 to
 492    :    // byte 3.
 493  E :    const uint8 kAssembly[] = { 0xE3, 0x01, 0x49, 0xC3 };
 494  E :    jecxz->CopyData(arraysize(kAssembly), kAssembly);
 495    :    jecxz->SetReference(1,
 496  E :        BlockGraph::Reference(BlockGraph::PC_RELATIVE_REF, 1, jecxz, 3, 3));
 497    :  
 498  E :    BasicBlockSubGraph bbsg;
 499  E :    BasicBlockDecomposer bbd(jecxz, &bbsg);
 500  E :    EXPECT_FALSE(bbd.Decompose());
 501  E :    EXPECT_TRUE(bbd.contains_unsupported_instructions());
 502  E :  }
 503    :  
 504    :  }  // namespace block_graph

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