Coverage for /Syzygy/block_graph/basic_block_decomposer_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
98.9%2612640.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/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 :      file_util::ScopedFILE file(file_util::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    :    for (BasicBlockSubGraph::BBCollection::const_iterator bb_it =
 128  E :             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    :          for (BasicCodeBlock::Successors::const_iterator succ_it =
 138  E :                   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(3u, 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  E :  }
 239    :  
 240    :  }  // namespace
 241    :  
 242  E :  TEST_F(BasicBlockDecomposerTest, DecomposeNoSubGraph) {
 243  E :    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 244  E :    BasicBlockDecomposer bbd(assembly_func_, NULL);
 245  E :    EXPECT_TRUE(bbd.Decompose());
 246  E :  }
 247    :  
 248  E :  TEST_F(BasicBlockDecomposerTest, DecomposeFailsInvalidCodeDataLayout) {
 249    :    // RET, 0x00, INT3.
 250    :    static const uint8 kData[] = { 0xC3, 0x00, 0xCC };
 251    :    BlockGraph::Block* b = block_graph_.AddBlock(BlockGraph::CODE_BLOCK,
 252  E :                                                 3, "BadCodeDataLayout");
 253  E :    b->SetData(kData, arraysize(kData));
 254  E :    b->SetLabel(0, "Code", BlockGraph::CODE_LABEL);
 255  E :    b->SetLabel(1, "Data", BlockGraph::DATA_LABEL);
 256  E :    b->SetLabel(2, "Code", BlockGraph::CODE_LABEL);
 257  E :    BasicBlockDecomposer bbd(b, NULL);
 258  E :    EXPECT_FALSE(bbd.Decompose());
 259  E :  }
 260    :  
 261  E :  TEST_F(BasicBlockDecomposerTest, Decompose) {
 262  E :    ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 263  E :    ASSERT_NO_FATAL_FAILURE(InitBasicBlockSubGraph());
 264    :  
 265    :    // Ensure we have the expected number and types of blocks.
 266  E :    ASSERT_EQ(kNumBasicBlocks, subgraph_.basic_blocks().size());
 267    :    ASSERT_EQ(kNumCodeBasicBlocks,
 268  E :              CountBasicBlocks(subgraph_, BasicBlock::BASIC_CODE_BLOCK));
 269    :    ASSERT_EQ(kNumDataBasicBlocks,
 270  E :              CountBasicBlocks(subgraph_, BasicBlock::BASIC_DATA_BLOCK));
 271    :    ASSERT_EQ(kNumCodePaddingBasicBlocks,
 272  E :              CountPaddingBasicBlocks(subgraph_, BasicBlock::BASIC_CODE_BLOCK));
 273    :    ASSERT_EQ(kNumDataPaddingBasicBlocks,
 274  E :              CountPaddingBasicBlocks(subgraph_, BasicBlock::BASIC_DATA_BLOCK));
 275    :  
 276    :    // There should be no gaps and all of the blocks should be used.
 277  E :    ASSERT_EQ(1U, subgraph_.block_descriptions().size());
 278    :    const BasicBlockSubGraph::BlockDescription& desc =
 279  E :        subgraph_.block_descriptions().back();
 280  E :    EXPECT_EQ(kNumBasicBlocks, desc.basic_block_order.size());
 281    :    EXPECT_TRUE(
 282    :        std::adjacent_find(
 283    :            desc.basic_block_order.begin(),
 284    :            desc.basic_block_order.end(),
 285  E :            &HasGapOrIsOutOfOrder) == desc.basic_block_order.end());
 286    :  
 287  E :    BasicBlockSubGraph::ReachabilityMap rm;
 288  E :    subgraph_.GetReachabilityMap(&rm);
 289    :  
 290    :    // Basic-block 0 - assembly_func.
 291  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[0]));
 292  E :    ASSERT_FALSE(bbs_[0]->is_padding());
 293  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[0]->type());
 294  E :    BasicCodeBlock* bb0 = BasicCodeBlock::Cast(bbs_[0]);
 295  E :    ASSERT_TRUE(bb0 != NULL);
 296  E :    ASSERT_EQ(4u, bb0->instructions().size());
 297  E :    ASSERT_EQ(0u, bb0->successors().size());
 298    :    BasicBlock::Instructions::const_iterator inst_iter =
 299  E :        bb0->instructions().begin();
 300  E :    std::advance(inst_iter, 2);
 301  E :    ASSERT_EQ(1u, inst_iter->references().size());
 302  E :    ASSERT_EQ(bbs_[9], inst_iter->references().begin()->second.basic_block());
 303  E :    std::advance(inst_iter, 1);
 304  E :    ASSERT_EQ(1u, inst_iter->references().size());
 305  E :    ASSERT_EQ(bbs_[8], inst_iter->references().begin()->second.basic_block());
 306  E :    ASSERT_EQ(1u, bbs_[0]->alignment());
 307    :  
 308    :    // Basic-block 1 - unreachable-label.
 309  E :    ASSERT_FALSE(BasicBlockSubGraph::IsReachable(rm, bbs_[1]));
 310  E :    ASSERT_TRUE(bbs_[1]->is_padding());
 311  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[1]->type());
 312  E :    BasicCodeBlock* bb1 = BasicCodeBlock::Cast(bbs_[1]);
 313  E :    ASSERT_EQ(1u, bb1->instructions().size());
 314  E :    ASSERT_EQ(1u, bb1->successors().size());
 315    :    ASSERT_EQ(bbs_[2],
 316  E :              bb1->successors().front().reference().basic_block());
 317  E :    ASSERT_EQ(1u, bb1->alignment());
 318    :  
 319    :    // Basic-block 2 - case_0.
 320  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[2]));
 321  E :    ASSERT_FALSE(bbs_[2]->is_padding());
 322  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[2]->type());
 323  E :    BasicCodeBlock* bb2 = BasicCodeBlock::Cast(bbs_[2]);
 324  E :    ASSERT_TRUE(bb2 != NULL);
 325  E :    ASSERT_EQ(2u, bb2->instructions().size());
 326  E :    ASSERT_EQ(1u, bb2->successors().size());
 327  E :    ASSERT_EQ(bbs_[3], bb2->successors().front().reference().basic_block());
 328  E :    ASSERT_EQ(1u, bbs_[2]->alignment());
 329    :  
 330    :    // Basic-block 3 - sub eax to jnz.
 331  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[3]));
 332  E :    ASSERT_FALSE(bbs_[3]->is_padding());
 333  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[3]->type());
 334  E :    BasicCodeBlock* bb3 = BasicCodeBlock::Cast(bbs_[3]);
 335  E :    ASSERT_TRUE(bb3 != NULL);
 336  E :    ASSERT_EQ(1u, bb3->instructions().size());
 337  E :    ASSERT_EQ(2u, bb3->successors().size());
 338  E :    ASSERT_EQ(bb3, bb3->successors().front().reference().basic_block());
 339  E :    ASSERT_EQ(bbs_[4], bb3->successors().back().reference().basic_block());
 340  E :    ASSERT_EQ(1u, bbs_[3]->alignment());
 341    :  
 342    :    // Basic-block 4 - ret.
 343  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[4]));
 344  E :    ASSERT_FALSE(bbs_[4]->is_padding());
 345  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[4]->type());
 346  E :    BasicCodeBlock* bb4 = BasicCodeBlock::Cast(bbs_[4]);
 347  E :    ASSERT_TRUE(bb4 != NULL);
 348  E :    ASSERT_EQ(1u, bb4->instructions().size());
 349  E :    ASSERT_EQ(0u, bb4->successors().size());
 350  E :    ASSERT_EQ(1u, bbs_[4]->alignment());
 351    :  
 352    :    // Basic-block 5 - case_1.
 353  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[5]));
 354  E :    ASSERT_FALSE(bbs_[5]->is_padding());
 355  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[5]->type());
 356  E :    BasicCodeBlock* bb5 = BasicCodeBlock::Cast(bbs_[5]);
 357  E :    ASSERT_TRUE(bb5 != NULL);
 358  E :    ASSERT_EQ(1u, bb5->instructions().size());
 359    :    ASSERT_EQ(
 360    :        func1_,
 361  E :        bb5->instructions().front().references().begin()->second.block());
 362  E :    ASSERT_EQ(1u, bb5->successors().size());
 363  E :    ASSERT_EQ(bbs_[6], bb5->successors().front().reference().basic_block());
 364  E :    ASSERT_EQ(1u, bbs_[5]->alignment());
 365    :  
 366    :    // Basic-block 6 - case_default.
 367  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[6]));
 368  E :    ASSERT_FALSE(bbs_[6]->is_padding());
 369  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[6]->type());
 370  E :    BasicCodeBlock* bb6 = BasicCodeBlock::Cast(bbs_[6]);
 371  E :    ASSERT_TRUE(bb6 != NULL);
 372  E :    ASSERT_EQ(2u, bb6->instructions().size());
 373    :    ASSERT_EQ(
 374    :        func2_,
 375  E :        bb6->instructions().back().references().begin()->second.block());
 376  E :    ASSERT_EQ(0u, bb6->successors().size());
 377  E :    ASSERT_EQ(1u, bbs_[6]->alignment());
 378    :  
 379    :    // Basic-block 7 - interrupt_label.
 380  E :    ASSERT_FALSE(BasicBlockSubGraph::IsReachable(rm, bbs_[7]));
 381  E :    ASSERT_TRUE(bbs_[7]->is_padding());
 382  E :    ASSERT_EQ(BasicBlock::BASIC_CODE_BLOCK, bbs_[7]->type());
 383  E :    BasicCodeBlock* bb7 = BasicCodeBlock::Cast(bbs_[7]);
 384  E :    ASSERT_TRUE(bb7 != NULL);
 385  E :    ASSERT_EQ(3u, bb7->instructions().size());
 386  E :    ASSERT_EQ(0u, bb7->successors().size());
 387  E :    ASSERT_EQ(1u, bbs_[7]->alignment());
 388    :  
 389    :    // Basic-block 8 - jump_table.
 390  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[8]));
 391  E :    ASSERT_FALSE(bbs_[8]->is_padding());
 392  E :    ASSERT_EQ(BasicBlock::BASIC_DATA_BLOCK, bbs_[8]->type());
 393  E :    BasicDataBlock* bb8 = BasicDataBlock::Cast(bbs_[8]);
 394  E :    ASSERT_TRUE(bb8 != NULL);
 395  E :    ASSERT_EQ(3 * Reference::kMaximumSize, bb8->size());
 396  E :    ASSERT_EQ(3u, bb8->references().size());
 397  E :    ASSERT_EQ(4u, bbs_[8]->alignment());
 398    :  
 399    :    // Basic-block 9 - case_table.
 400  E :    ASSERT_TRUE(BasicBlockSubGraph::IsReachable(rm, bbs_[9]));
 401  E :    ASSERT_FALSE(bbs_[9]->is_padding());
 402  E :    ASSERT_EQ(BasicBlock::BASIC_DATA_BLOCK, bbs_[9]->type());
 403  E :    BasicDataBlock* bb9 = BasicDataBlock::Cast(bbs_[9]);
 404  E :    ASSERT_TRUE(bb9 != NULL);
 405  E :    ASSERT_EQ(256, bb9->size());
 406  E :    ASSERT_EQ(0u, bb9->references().size());
 407  E :    ASSERT_EQ(4u, bbs_[9]->alignment());
 408    :  
 409    :    // Validate all source ranges.
 410  E :    core::RelativeAddress next_addr(start_addr_);
 411  E :    for (size_t i = 0; i < bbs_.size(); ++i) {
 412  E :      const BasicCodeBlock* code_block = BasicCodeBlock::Cast(bbs_[i]);
 413  E :      const BasicDataBlock* data_block = BasicDataBlock::Cast(bbs_[i]);
 414    :  
 415  E :      if (code_block != NULL) {
 416  E :        ASSERT_TRUE(data_block == NULL);
 417    :  
 418    :        BasicBlock::Instructions::const_iterator instr_it =
 419  E :            code_block->instructions().begin();
 420  E :        for (; instr_it != code_block->instructions().end(); ++instr_it) {
 421  E :          const Instruction& instr = *instr_it;
 422  E :          ASSERT_EQ(next_addr, instr.source_range().start());
 423  E :          ASSERT_EQ(instr.size(), instr.source_range().size());
 424    :  
 425  E :          next_addr += instr.size();
 426  E :        }
 427    :  
 428    :        BasicBlock::Successors::const_iterator succ_it =
 429  E :            code_block->successors().begin();
 430  E :        for (; succ_it != code_block->successors().end(); ++succ_it) {
 431  E :          const Successor& succ = *succ_it;
 432  E :          if (succ.source_range().size() != 0) {
 433  E :            ASSERT_EQ(next_addr, succ.source_range().start());
 434  E :            ASSERT_EQ(succ.instruction_size(), succ.source_range().size());
 435  E :          } else {
 436  E :            ASSERT_EQ(0, succ.instruction_size());
 437    :          }
 438    :  
 439  E :          next_addr += succ.instruction_size();
 440  E :        }
 441    :      }
 442    :  
 443  E :      if (data_block != NULL) {
 444  E :        ASSERT_TRUE(code_block == NULL);
 445  E :        ASSERT_TRUE(data_block->type() == BasicBlock::BASIC_DATA_BLOCK);
 446  E :        ASSERT_EQ(next_addr, data_block->source_range().start());
 447  E :        ASSERT_EQ(data_block->size(), data_block->source_range().size());
 448    :  
 449  E :        next_addr += data_block->size();
 450    :      }
 451  E :    }
 452  E :  }
 453    :  
 454  E :  TEST_F(BasicBlockDecomposerTest, DecomposeBlockWithLabelPastData) {
 455  E :    ASSERT_NO_FATAL_FAILURE(InitBasicBlockSubGraphWithLabelPastEnd());
 456  E :  }
 457    :  
 458  E :  TEST_F(BasicBlockDecomposerTest, HasInlineAssembly) {
 459    :    ASSERT_NO_FATAL_FAILURE(InitBlockGraphFromSerializedFile(
 460  E :        L"syzygy/block_graph/test_data/has_inline_assembly.bg"));
 461    :  
 462    :    BlockGraph::BlockMap::iterator block_it =
 463  E :        block_graph_.blocks_mutable().begin();
 464  E :    for (; block_it != block_graph_.blocks().end(); ++block_it) {
 465  E :      BlockGraph::Block* block = &(block_it->second);
 466    :  
 467    :      // We skip the 'master' blocks. These are simply dummy blocks that act as
 468    :      // sources and destinations for references, to keep the remaining blocks
 469    :      // intact.
 470  E :      if (block->name() == "CodeMaster" || block->name() == "DataMaster")
 471  E :        continue;
 472    :  
 473    :      // We remove the ERRORED_DISASSEMBLY bit from the block, as the BB
 474    :      // decomposer uses that to cache decomposition results and will fail
 475    :      // early if it is set.
 476    :      // TODO(chrisha): Remove me when caching happens in the policy object!
 477  E :      block->clear_attribute(BlockGraph::ERRORED_DISASSEMBLY);
 478    :  
 479  E :      BasicBlockSubGraph bbsg;
 480  E :      BasicBlockDecomposer bbd(block, &bbsg);
 481  E :      ASSERT_TRUE(bbd.Decompose());
 482  E :      EXPECT_EQ(block->size(), GetNetBBSize(bbsg));
 483    :  
 484    :      // Validate a block in detail.
 485  E :      if (block->id() == 5677)
 486  E :        ASSERT_NO_FATAL_FAILURE(ValidateHasInlineAssemblyBlock5677(bbsg));
 487  E :    }
 488  E :  }
 489    :  
 490    :  }  // namespace block_graph

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