Coverage for /Syzygy/block_graph/analysis/memory_access_analysis_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%2762760.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    :  // Unittests for memory access analysis.
  16    :  
  17    :  #include "syzygy/block_graph/analysis/memory_access_analysis.h"
  18    :  
  19    :  #include "gtest/gtest.h"
  20    :  #include "mnemonics.h"  // NOLINT
  21    :  
  22    :  namespace block_graph {
  23    :  namespace analysis {
  24    :  
  25    :  namespace {
  26    :  
  27    :  typedef block_graph::analysis::MemoryAccessAnalysis::State State;
  28    :  typedef block_graph::BasicBlockSubGraph::BasicBlock BasicBlock;
  29    :  typedef block_graph::BasicBlockSubGraph::BasicBlock::Instructions Instructions;
  30    :  typedef BasicBlockSubGraph::BlockDescription BlockDescription;
  31    :  
  32    :  // _asm add eax, ecx
  33    :  const uint8 kClearEax[] = { 0x03, 0xC1 };
  34    :  // _asm add ecx, [eax]
  35    :  const uint8 kReadEax[] = { 0x03, 0x08 };
  36    :  // _asm add ecx, [eax + 42]
  37    :  const uint8 kReadEax42[] = { 0x03, 0x48, 0x2A };
  38    :  // _asm add eax, ecx
  39    :  const uint8 kRegsOnly[] = { 0x03, 0xC1 };
  40    :  // _asm add [eax + ebx*2 + 42], ecx
  41    :  const uint8 kWriteWithScale[] = { 0x01, 0x4C, 0x58, 0x2A };
  42    :  // _asm add DWORD PTR [X], ecx
  43    :  const uint8 kWriteDispl[] = { 0x01, 0x0D, 0x80, 0x1E, 0xF2, 0x00 };
  44    :  // _asm add [eax + 42], ecx
  45    :  const uint8 kWriteEax42[] = { 0x01, 0x48, 0x2A };
  46    :  // _asm lea ecx, [eax]
  47    :  const uint8 kLeaEax[] = { 0x8D, 0x08 };
  48    :  // _asm lea ecx, [eax + 42]
  49    :  const uint8 kLeaEax42[] = { 0x8D, 0x48, 0x2A };
  50    :  
  51    :  // _asm repnz movsb
  52    :  const uint8 kRepMovsb[] = { 0xF2, 0xA4 };
  53    :  
  54    :  // _asm add ecx, [eax + C]
  55    :  const uint8 kReadEax10[] = { 0x03, 0x48, 0x0A };
  56    :  const uint8 kReadEax11[] = { 0x03, 0x48, 0x0B };
  57    :  const uint8 kReadEax12[] = { 0x03, 0x48, 0x0C };
  58    :  const uint8 kReadEax13[] = { 0x03, 0x48, 0x0D };
  59    :  const uint8 kReadEax14[] = { 0x03, 0x48, 0x0E };
  60    :  const uint8 kReadEax15[] = { 0x03, 0x48, 0x0F };
  61    :  
  62    :  // _asm ret
  63    :  const uint8 kRet[] = { 0xC3 };
  64    :  // _asm call <FFFFFFFF>
  65    :  const uint8 kCall[] = { 0xE8, 0xFF, 0xD7, 0xFF, 0xFF };
  66    :  // _asm rdtsc
  67    :  const uint8 kRdtsc[] = { 0x0F, 0x31 };
  68    :  
  69    :  void AddSuccessorBetween(Successor::Condition condition,
  70    :                           BasicCodeBlock* from,
  71  E :                           BasicCodeBlock* to) {
  72    :    from->successors().push_back(
  73    :        Successor(condition,
  74    :                  BasicBlockReference(BlockGraph::RELATIVE_REF,
  75    :                                      BlockGraph::Reference::kMaximumSize,
  76    :                                      to),
  77  E :                  0));
  78  E :  }
  79    :  
  80    :  }  // namespace
  81    :  
  82    :  class TestMemoryAccessAnalysisState: public MemoryAccessAnalysis::State {
  83    :   public:
  84    :    bool IsEmpty(core::Register reg) const;
  85    :    bool IsEmpty() const;
  86    :    bool Contains(core::Register reg, int32 displ) const;
  87    :  
  88    :    template<size_t N>
  89    :    bool HasNonRedundantAccess(const uint8 (& data)[N]) const;
  90    :  
  91    :    template<size_t N>
  92    :    void Execute(const uint8 (& data)[N]);
  93    :  
  94    :    using MemoryAccessAnalysis::State::Clear;
  95    :  };
  96    :  
  97    :  class TestMemoryAccessAnalysis: public MemoryAccessAnalysis {
  98    :   public:
  99    :    using MemoryAccessAnalysis::Intersect;
 100    :  };
 101    :  
 102    :  class MemoryAccessAnalysisTest : public testing::Test {
 103    :   public:
 104  E :    MemoryAccessAnalysisTest() : bb_("Dummy") {}
 105    :  
 106  E :    bool Intersect(const block_graph::BasicBlock* bb, const State& state) {
 107  E :      return memory_access_.Intersect(bb, state);
 108  E :    }
 109    :  
 110  E :    void GetStateAtEntryOf(const BasicBlock* bb, State* state) const {
 111  E :     return memory_access_.GetStateAtEntryOf(bb, state);
 112  E :    }
 113    :  
 114    :    template<size_t N>
 115    :    void PropagateForward(const uint8 (& data)[N]);
 116    :  
 117    :   protected:
 118    :    TestMemoryAccessAnalysis memory_access_;
 119    :    TestMemoryAccessAnalysisState state_;
 120    :    BasicCodeBlock bb_;
 121    :  };
 122    :  
 123  E :  bool TestMemoryAccessAnalysisState::IsEmpty(core::Register reg) const {
 124  E :    DCHECK_LT(reg.code(), core::kRegisterMax);
 125  E :    return active_memory_accesses_[reg.code()].empty();
 126  E :  }
 127    :  
 128  E :  bool TestMemoryAccessAnalysisState::IsEmpty() const {
 129  E :    for (int r = 0; r < core::kRegisterMax; ++r) {
 130  E :      core::RegisterCode reg = core::RegisterCode(r);
 131  E :      if (!IsEmpty(core::Register(reg)))
 132  E :        return false;
 133  E :    }
 134  E :    return true;
 135  E :  }
 136    :  
 137    :  bool TestMemoryAccessAnalysisState::Contains(
 138  E :      core::Register reg, int32 displ) const {
 139  E :    DCHECK_LT(reg.code(), core::kRegisterMax);
 140  E :    const std::set<int32>& offsets = active_memory_accesses_[reg.code()];
 141  E :    return offsets.find(displ) != offsets.end();
 142  E :  }
 143    :  
 144    :  template<size_t N>
 145    :  bool TestMemoryAccessAnalysisState::HasNonRedundantAccess(
 146  E :      const uint8 (& data)[N]) const {
 147    :    // Decode an instruction.
 148  E :    DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
 149    :  
 150  E :    block_graph::Instruction temp;
 151  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 152  E :    DCHECK(decoded);
 153    :  
 154    :    // Expect to decode the entire buffer.
 155  E :    DCHECK(temp.size() == N);
 156    :  
 157    :    // Execute the decoded instruction, and modify the current state.
 158  E :    return MemoryAccessAnalysis::State::HasNonRedundantAccess(temp);
 159  E :  }
 160    :  
 161    :  template<size_t N>
 162  E :  void TestMemoryAccessAnalysisState::Execute(const uint8 (& data)[N]) {
 163    :    // Decode an instruction.
 164  E :    DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
 165    :  
 166  E :    block_graph::Instruction temp;
 167  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 168  E :    DCHECK(decoded);
 169    :  
 170    :    // Expect to decode the entire buffer.
 171  E :    DCHECK(temp.size() == N);
 172    :  
 173    :    // Execute the decoded instruction, and modify the current state.
 174  E :    MemoryAccessAnalysis::State::Execute(temp);
 175  E :  }
 176    :  
 177    :  template<size_t N>
 178    :  void MemoryAccessAnalysisTest::PropagateForward(
 179  E :      const uint8 (& data)[N]) {
 180    :    // Decode an instruction.
 181  E :    DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
 182    :  
 183  E :    block_graph::Instruction temp;
 184  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 185  E :    ASSERT_TRUE(decoded);
 186    :  
 187    :    // Expect to decode the entire buffer.
 188  E :    ASSERT_EQ(N, temp.size());
 189    :  
 190    :    // Execute the decoded instruction, and modify the current state.
 191  E :    MemoryAccessAnalysis::PropagateForward(temp, &state_);
 192  E :  }
 193    :  
 194  E :  TEST(MemoryAccessAnalysisStateTest, Constructor) {
 195    :    // Initial state is empty.
 196  E :    TestMemoryAccessAnalysisState state;
 197  E :    EXPECT_TRUE(state.IsEmpty());
 198  E :  }
 199    :  
 200  E :  TEST(MemoryAccessAnalysisStateTest, CopyConstructor) {
 201  E :    TestMemoryAccessAnalysisState state1;
 202    :  
 203  E :    state1.Execute(kReadEax);
 204  E :    state1.Execute(kWriteEax42);
 205    :  
 206  E :    EXPECT_TRUE(state1.Contains(core::eax, 0));
 207  E :    EXPECT_TRUE(state1.Contains(core::eax, 42));
 208    :  
 209    :    // Expect memory accesses to be copied into state2.
 210  E :    TestMemoryAccessAnalysisState state2(state1);
 211  E :    EXPECT_TRUE(state2.Contains(core::eax, 0));
 212  E :    EXPECT_TRUE(state2.Contains(core::eax, 42));
 213  E :  }
 214    :  
 215  E :  TEST(MemoryAccessAnalysisStateTest, Clear) {
 216  E :    TestMemoryAccessAnalysisState state;
 217    :  
 218  E :    state.Execute(kWriteEax42);
 219  E :    EXPECT_TRUE(!state.IsEmpty());
 220  E :    state.Clear();
 221  E :    EXPECT_TRUE(state.IsEmpty());
 222  E :  }
 223    :  
 224  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteOperandKind) {
 225  E :    TestMemoryAccessAnalysisState state;
 226    :  
 227  E :    state.Execute(kRegsOnly);
 228  E :    EXPECT_TRUE(state.IsEmpty());
 229    :  
 230  E :    state.Execute(kWriteWithScale);
 231  E :    EXPECT_TRUE(state.IsEmpty());
 232    :  
 233  E :    state.Execute(kWriteDispl);
 234  E :    EXPECT_TRUE(state.IsEmpty());
 235    :  
 236  E :    state.Execute(kReadEax);
 237  E :    EXPECT_TRUE(state.Contains(core::eax, 0));
 238    :  
 239  E :    state.Execute(kReadEax42);
 240  E :    EXPECT_TRUE(state.Contains(core::eax, 42));
 241  E :  }
 242    :  
 243  E :  TEST(MemoryAccessAnalysisStateTest, LeaOperand) {
 244  E :    TestMemoryAccessAnalysisState state;
 245    :  
 246    :    // LEA do not perform a memory access.
 247  E :    state.Execute(kLeaEax);
 248  E :    EXPECT_FALSE(state.Contains(core::eax, 0));
 249  E :    state.Execute(kLeaEax42);
 250  E :    EXPECT_FALSE(state.Contains(core::eax, 42));
 251  E :  }
 252    :  
 253  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteWithPrefix) {
 254  E :    TestMemoryAccessAnalysisState state;
 255    :  
 256  E :    state.Execute(kRepMovsb);
 257  E :    EXPECT_TRUE(state.IsEmpty());
 258  E :  }
 259    :  
 260  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccess) {
 261  E :    TestMemoryAccessAnalysisState state;
 262    :  
 263    :    // Initial state is empty, and accesses are not redundant.
 264  E :    bool redundant_read1 = state.HasNonRedundantAccess(kReadEax42);
 265  E :    bool redundant_write1 = state.HasNonRedundantAccess(kWriteEax42);
 266  E :    EXPECT_TRUE(redundant_read1);
 267  E :    EXPECT_TRUE(redundant_write1);
 268    :  
 269    :    // Perform a read of [eax + 42].
 270  E :    state.Execute(kReadEax42);
 271  E :    EXPECT_TRUE(state.Contains(core::eax, 42));
 272    :  
 273    :    // After the read, accesses are redundant.
 274  E :    bool redundant_read2 = state.HasNonRedundantAccess(kReadEax42);
 275  E :    bool redundant_write2 = state.HasNonRedundantAccess(kWriteEax42);
 276  E :    EXPECT_FALSE(redundant_read2);
 277  E :    EXPECT_FALSE(redundant_write2);
 278  E :  }
 279    :  
 280  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessOperandKind) {
 281  E :    TestMemoryAccessAnalysisState state;
 282    :  
 283    :    // Instructions without memory access, on empty state.
 284  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kRegsOnly));
 285  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax));
 286  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax42));
 287    :  
 288    :    // Initial state is empty, and accesses are not redundant.
 289  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax));
 290  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax42));
 291  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteWithScale));
 292  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteDispl));
 293  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteEax42));
 294  E :  }
 295    :  
 296  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessWithPrefix) {
 297  E :    TestMemoryAccessAnalysisState state;
 298  E :    state.Execute(kRepMovsb);
 299  E :    bool redundant = state.HasNonRedundantAccess(kRepMovsb);
 300  E :    EXPECT_TRUE(redundant);
 301  E :  }
 302    :  
 303  E :  TEST_F(MemoryAccessAnalysisTest, GetStateOf) {
 304    :    // It is valid to get the state of a NULL block.
 305  E :    GetStateAtEntryOf(NULL, &state_);
 306  E :    EXPECT_TRUE(state_.IsEmpty());
 307    :  
 308    :    // Get an non-existing basic block.
 309  E :    GetStateAtEntryOf(&bb_, &state_);
 310  E :    EXPECT_TRUE(state_.IsEmpty());
 311  E :  }
 312    :  
 313  E :  TEST_F(MemoryAccessAnalysisTest, IntersectEmpty) {
 314  E :    memory_access_.GetStateAtEntryOf(&bb_, &state_);
 315  E :    EXPECT_TRUE(state_.IsEmpty());
 316    :  
 317    :    // Perform an initial intersection with an empty set.
 318  E :    TestMemoryAccessAnalysisState state;
 319  E :    Intersect(&bb_, state);
 320    :  
 321  E :    state.Execute(kReadEax10);
 322  E :    state.Execute(kReadEax11);
 323    :  
 324    :    // Perform an second intersection with a non empty set.
 325  E :    Intersect(&bb_, state_);
 326  E :    GetStateAtEntryOf(&bb_, &state_);
 327    :  
 328    :    // The results must be empty.
 329  E :    EXPECT_TRUE(state_.IsEmpty());
 330  E :  }
 331    :  
 332  E :  TEST_F(MemoryAccessAnalysisTest, IntersectStates) {
 333    :    // Intersection with displacements [10, 11, 12, 13, 14, 15].
 334  E :    TestMemoryAccessAnalysisState state1;
 335  E :    state1.Execute(kReadEax10);
 336  E :    state1.Execute(kReadEax11);
 337  E :    state1.Execute(kReadEax12);
 338  E :    state1.Execute(kReadEax13);
 339  E :    state1.Execute(kReadEax14);
 340  E :    state1.Execute(kReadEax15);
 341  E :    Intersect(&bb_, state1);
 342    :  
 343    :    // Intersection with displacements [10, 11, 12, 14].
 344  E :    TestMemoryAccessAnalysisState state2;
 345  E :    state2.Execute(kReadEax10);
 346  E :    state2.Execute(kReadEax11);
 347  E :    state2.Execute(kReadEax12);
 348  E :    state2.Execute(kReadEax14);
 349  E :    Intersect(&bb_, state2);
 350    :  
 351    :    // Check current state [10, 11, 12, 14].
 352  E :    GetStateAtEntryOf(&bb_, &state_);
 353  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 354  E :    EXPECT_TRUE(state_.Contains(core::eax, 11));
 355  E :    EXPECT_TRUE(state_.Contains(core::eax, 12));
 356  E :    EXPECT_FALSE(state_.Contains(core::eax, 13));
 357  E :    EXPECT_TRUE(state_.Contains(core::eax, 14));
 358  E :    EXPECT_FALSE(state_.Contains(core::eax, 15));
 359    :  
 360    :    // Intersection with displacements [10, 11, 15].
 361  E :    TestMemoryAccessAnalysisState state3;
 362  E :    state3.Execute(kReadEax10);
 363  E :    state3.Execute(kReadEax11);
 364  E :    state3.Execute(kReadEax15);
 365  E :    Intersect(&bb_, state3);
 366    :  
 367    :    // Check current state [10, 11].
 368  E :    GetStateAtEntryOf(&bb_, &state_);
 369  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 370  E :    EXPECT_TRUE(state_.Contains(core::eax, 11));
 371  E :    EXPECT_FALSE(state_.Contains(core::eax, 12));
 372  E :    EXPECT_FALSE(state_.Contains(core::eax, 13));
 373  E :    EXPECT_FALSE(state_.Contains(core::eax, 14));
 374  E :    EXPECT_FALSE(state_.Contains(core::eax, 15));
 375    :  
 376    :    // Intersection with displacements [15].
 377  E :    TestMemoryAccessAnalysisState state4;
 378  E :    state4.Execute(kReadEax15);
 379  E :    Intersect(&bb_, state4);
 380    :  
 381    :    // The state must be empty.
 382  E :    GetStateAtEntryOf(&bb_, &state_);
 383  E :    EXPECT_TRUE(state_.IsEmpty());
 384  E :  }
 385    :  
 386  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardSimple) {
 387  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 388  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 389    :  
 390  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax));
 391  E :    EXPECT_TRUE(state_.Contains(core::eax, 0));
 392  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 393    :  
 394  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kClearEax));
 395  E :    EXPECT_TRUE(state_.IsEmpty());
 396    :  
 397  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kLeaEax));
 398  E :    EXPECT_TRUE(state_.IsEmpty());
 399  E :  }
 400    :  
 401  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardWithCallRet) {
 402  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 403  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 404  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kCall));
 405  E :    EXPECT_TRUE(state_.IsEmpty());
 406    :  
 407  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 408  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 409  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRet));
 410  E :    EXPECT_TRUE(state_.IsEmpty());
 411  E :  }
 412    :  
 413  E :  TEST_F(MemoryAccessAnalysisTest, UnknownInstruction) {
 414    :    // Ensure unknown instructions are processed correctly.
 415  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 416  E :    EXPECT_TRUE(state_.Contains(core::eax, 10));
 417  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRdtsc));
 418  E :    EXPECT_TRUE(state_.IsEmpty());
 419  E :  }
 420    :  
 421  E :  TEST_F(MemoryAccessAnalysisTest, Analyze) {
 422  E :    BasicBlockSubGraph subgraph;
 423    :  
 424    :    BlockDescription* block = subgraph.AddBlockDescription(
 425  E :        "b1", BlockGraph::CODE_BLOCK, 7, 2, 42);
 426    :  
 427  E :    BasicCodeBlock* bb_if = subgraph.AddBasicCodeBlock("if");
 428  E :    BasicCodeBlock* bb_true = subgraph.AddBasicCodeBlock("true");
 429  E :    BasicCodeBlock* bb_false = subgraph.AddBasicCodeBlock("false");
 430  E :    BasicCodeBlock* bb_end = subgraph.AddBasicCodeBlock("end");
 431    :  
 432  E :    ASSERT_TRUE(bb_if != NULL);
 433  E :    ASSERT_TRUE(bb_true != NULL);
 434  E :    ASSERT_TRUE(bb_false != NULL);
 435  E :    ASSERT_TRUE(bb_end != NULL);
 436    :  
 437  E :    block->basic_block_order.push_back(bb_if);
 438  E :    block->basic_block_order.push_back(bb_true);
 439  E :    block->basic_block_order.push_back(bb_end);
 440  E :    block->basic_block_order.push_back(bb_false);
 441    :  
 442  E :    AddSuccessorBetween(Successor::kConditionEqual, bb_if, bb_true);
 443  E :    AddSuccessorBetween(Successor::kConditionNotEqual, bb_if, bb_false);
 444  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_true, bb_end);
 445  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_false, bb_end);
 446    :  
 447    :    BasicBlockAssembler asm_if(bb_if->instructions().end(),
 448  E :                               &bb_if->instructions());
 449  E :    asm_if.mov(core::ecx, Operand(core::eax, Immediate(1, core::kSize32Bit)));
 450  E :    asm_if.mov(core::edx, Operand(core::ecx, Immediate(12, core::kSize32Bit)));
 451  E :    asm_if.mov(core::edx, Operand(core::eax, Immediate(42, core::kSize32Bit)));
 452    :  
 453    :    BasicBlockAssembler asm_true(bb_true->instructions().end(),
 454  E :                                 &bb_true->instructions());
 455  E :    asm_true.mov(core::ecx, Operand(core::eax, Immediate(1, core::kSize32Bit)));
 456  E :    asm_true.mov(core::edx, Operand(core::eax, Immediate(12, core::kSize32Bit)));
 457  E :    asm_true.mov(core::ecx, Operand(core::eax, Immediate(24, core::kSize32Bit)));
 458    :  
 459    :    BasicBlockAssembler asm_false(bb_false->instructions().end(),
 460  E :                                  &bb_false->instructions());
 461  E :    asm_false.mov(core::ecx, Operand(core::eax, Immediate(24, core::kSize32Bit)));
 462  E :    asm_false.mov(core::edx, Operand(core::eax, Immediate(48, core::kSize32Bit)));
 463    :  
 464    :    // Analyze the flow graph.
 465  E :    memory_access_.Analyze(&subgraph);
 466    :  
 467    :    // State of first basic block is empty.
 468  E :    GetStateAtEntryOf(bb_if, &state_);
 469  E :    EXPECT_TRUE(state_.IsEmpty());
 470    :  
 471    :    // Get entry state of bb_true.
 472  E :    GetStateAtEntryOf(bb_true, &state_);
 473  E :    EXPECT_TRUE(state_.Contains(core::eax, 1));
 474  E :    EXPECT_TRUE(state_.Contains(core::ecx, 12));
 475  E :    EXPECT_TRUE(state_.Contains(core::eax, 42));
 476    :  
 477    :    // Get entry state of bb_false.
 478  E :    GetStateAtEntryOf(bb_false, &state_);
 479  E :    EXPECT_TRUE(state_.Contains(core::eax, 1));
 480  E :    EXPECT_TRUE(state_.Contains(core::ecx, 12));
 481  E :    EXPECT_TRUE(state_.Contains(core::eax, 42));
 482    :  
 483    :    // Get entry state of bb_end. Intersection of bb_true and bb_false.
 484  E :    GetStateAtEntryOf(bb_end, &state_);
 485  E :    EXPECT_TRUE(state_.Contains(core::eax, 1));
 486  E :    EXPECT_FALSE(state_.Contains(core::eax, 12));
 487  E :    EXPECT_FALSE(state_.Contains(core::ecx, 12));
 488  E :    EXPECT_TRUE(state_.Contains(core::eax, 24));
 489  E :    EXPECT_TRUE(state_.Contains(core::eax, 42));
 490  E :  }
 491    :  
 492  E :  TEST_F(MemoryAccessAnalysisTest, AnalyzeWithData) {
 493  E :    BasicBlockSubGraph subgraph;
 494  E :    const uint8 raw_data[] = { 0, 1, 2, 3, 4 };
 495  E :    const size_t raw_data_len = ARRAYSIZE(raw_data);
 496    :  
 497    :    BlockDescription* block = subgraph.AddBlockDescription(
 498  E :        "b1", BlockGraph::CODE_BLOCK, 7, 2, 42);
 499    :  
 500  E :    BasicCodeBlock* bb = subgraph.AddBasicCodeBlock("bb");
 501    :    BasicDataBlock* data =
 502  E :        subgraph.AddBasicDataBlock("data", raw_data_len, &raw_data[0]);
 503    :  
 504  E :    block->basic_block_order.push_back(bb);
 505  E :    block->basic_block_order.push_back(data);
 506    :  
 507  E :    BasicBlockAssembler asm_bb(bb->instructions().end(), &bb->instructions());
 508  E :    asm_bb.ret();
 509    :  
 510    :    // Analyze the flow graph.
 511  E :    memory_access_.Analyze(&subgraph);
 512    :  
 513    :    // Expect empty state.
 514  E :    GetStateAtEntryOf(bb, &state_);
 515  E :    EXPECT_TRUE(state_.IsEmpty());
 516    :  
 517  E :    GetStateAtEntryOf(data, &state_);
 518  E :    EXPECT_TRUE(state_.IsEmpty());
 519  E :  }
 520    :  
 521    :  }  // namespace analysis
 522    :  }  // namespace block_graph

Coverage information generated Thu Jul 04 09:34:53 2013.