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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%2752750.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(const assm::Register32& reg) const;
  85    :    bool IsEmpty() const;
  86    :    bool Contains(const assm::Register32& 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_(NULL) {
 105  E :      bb_ = subgraph_.AddBasicCodeBlock("Dummy");
 106  E :    }
 107    :  
 108  E :    bool Intersect(const block_graph::BasicBlock* bb, const State& state) {
 109  E :      return memory_access_.Intersect(bb, state);
 110  E :    }
 111    :  
 112  E :    void GetStateAtEntryOf(const BasicBlock* bb, State* state) const {
 113  E :      return memory_access_.GetStateAtEntryOf(bb, state);
 114  E :    }
 115    :  
 116    :    template<size_t N>
 117    :    void PropagateForward(const uint8 (& data)[N]);
 118    :  
 119    :   protected:
 120    :    TestMemoryAccessAnalysis memory_access_;
 121    :    TestMemoryAccessAnalysisState state_;
 122    :    BasicBlockSubGraph subgraph_;
 123    :    BasicCodeBlock* bb_;
 124    :  };
 125    :  
 126    :  bool TestMemoryAccessAnalysisState::IsEmpty(
 127  E :      const assm::Register32& reg) const {
 128  E :    return active_memory_accesses_[reg.id() - assm::kRegister32Min].empty();
 129  E :  }
 130    :  
 131  E :  bool TestMemoryAccessAnalysisState::IsEmpty() const {
 132  E :    for (int r = 0; r < assm::kRegister32Count; ++r) {
 133  E :      if (!IsEmpty(assm::kRegisters32[r]))
 134  E :        return false;
 135  E :    }
 136  E :    return true;
 137  E :  }
 138    :  
 139    :  bool TestMemoryAccessAnalysisState::Contains(
 140  E :      const assm::Register32& reg, int32 displ) const {
 141    :    const std::set<int32>& offsets = active_memory_accesses_[
 142  E :        reg.id() - assm::kRegister32Min];
 143  E :    return offsets.find(displ) != offsets.end();
 144  E :  }
 145    :  
 146    :  template<size_t N>
 147    :  bool TestMemoryAccessAnalysisState::HasNonRedundantAccess(
 148  E :      const uint8 (& data)[N]) const {
 149    :    // Decode an instruction.
 150  E :    DCHECK_GT(assm::kMaxInstructionLength, N);
 151    :  
 152  E :    block_graph::Instruction temp;
 153  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 154  E :    DCHECK(decoded);
 155    :  
 156    :    // Expect to decode the entire buffer.
 157  E :    DCHECK_EQ(N, temp.size());
 158    :  
 159    :    // Execute the decoded instruction, and modify the current state.
 160  E :    return MemoryAccessAnalysis::State::HasNonRedundantAccess(temp);
 161  E :  }
 162    :  
 163    :  template<size_t N>
 164  E :  void TestMemoryAccessAnalysisState::Execute(const uint8 (& data)[N]) {
 165    :    // Decode an instruction.
 166  E :    DCHECK_GT(assm::kMaxInstructionLength, N);
 167    :  
 168  E :    block_graph::Instruction temp;
 169  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 170  E :    DCHECK(decoded);
 171    :  
 172    :    // Expect to decode the entire buffer.
 173  E :    DCHECK_EQ(N, temp.size());
 174    :  
 175    :    // Execute the decoded instruction, and modify the current state.
 176  E :    MemoryAccessAnalysis::State::Execute(temp);
 177  E :  }
 178    :  
 179    :  template<size_t N>
 180    :  void MemoryAccessAnalysisTest::PropagateForward(
 181  E :      const uint8 (& data)[N]) {
 182    :    // Decode an instruction.
 183  E :    DCHECK_GT(assm::kMaxInstructionLength, N);
 184    :  
 185  E :    block_graph::Instruction temp;
 186  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 187  E :    ASSERT_TRUE(decoded);
 188    :  
 189    :    // Expect to decode the entire buffer.
 190  E :    ASSERT_EQ(N, temp.size());
 191    :  
 192    :    // Execute the decoded instruction, and modify the current state.
 193  E :    MemoryAccessAnalysis::PropagateForward(temp, &state_);
 194  E :  }
 195    :  
 196  E :  TEST(MemoryAccessAnalysisStateTest, Constructor) {
 197    :    // Initial state is empty.
 198  E :    TestMemoryAccessAnalysisState state;
 199  E :    EXPECT_TRUE(state.IsEmpty());
 200  E :  }
 201    :  
 202  E :  TEST(MemoryAccessAnalysisStateTest, CopyConstructor) {
 203  E :    TestMemoryAccessAnalysisState state1;
 204    :  
 205  E :    state1.Execute(kReadEax);
 206  E :    state1.Execute(kWriteEax42);
 207    :  
 208  E :    EXPECT_TRUE(state1.Contains(assm::eax, 0));
 209  E :    EXPECT_TRUE(state1.Contains(assm::eax, 42));
 210    :  
 211    :    // Expect memory accesses to be copied into state2.
 212  E :    TestMemoryAccessAnalysisState state2(state1);
 213  E :    EXPECT_TRUE(state2.Contains(assm::eax, 0));
 214  E :    EXPECT_TRUE(state2.Contains(assm::eax, 42));
 215  E :  }
 216    :  
 217  E :  TEST(MemoryAccessAnalysisStateTest, Clear) {
 218  E :    TestMemoryAccessAnalysisState state;
 219    :  
 220  E :    state.Execute(kWriteEax42);
 221  E :    EXPECT_TRUE(!state.IsEmpty());
 222  E :    state.Clear();
 223  E :    EXPECT_TRUE(state.IsEmpty());
 224  E :  }
 225    :  
 226  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteOperandKind) {
 227  E :    TestMemoryAccessAnalysisState state;
 228    :  
 229  E :    state.Execute(kRegsOnly);
 230  E :    EXPECT_TRUE(state.IsEmpty());
 231    :  
 232  E :    state.Execute(kWriteWithScale);
 233  E :    EXPECT_TRUE(state.IsEmpty());
 234    :  
 235  E :    state.Execute(kWriteDispl);
 236  E :    EXPECT_TRUE(state.IsEmpty());
 237    :  
 238  E :    state.Execute(kReadEax);
 239  E :    EXPECT_TRUE(state.Contains(assm::eax, 0));
 240    :  
 241  E :    state.Execute(kReadEax42);
 242  E :    EXPECT_TRUE(state.Contains(assm::eax, 42));
 243  E :  }
 244    :  
 245  E :  TEST(MemoryAccessAnalysisStateTest, LeaOperand) {
 246  E :    TestMemoryAccessAnalysisState state;
 247    :  
 248    :    // LEA do not perform a memory access.
 249  E :    state.Execute(kLeaEax);
 250  E :    EXPECT_FALSE(state.Contains(assm::eax, 0));
 251  E :    state.Execute(kLeaEax42);
 252  E :    EXPECT_FALSE(state.Contains(assm::eax, 42));
 253  E :  }
 254    :  
 255  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteWithPrefix) {
 256  E :    TestMemoryAccessAnalysisState state;
 257    :  
 258  E :    state.Execute(kRepMovsb);
 259  E :    EXPECT_TRUE(state.IsEmpty());
 260  E :  }
 261    :  
 262  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccess) {
 263  E :    TestMemoryAccessAnalysisState state;
 264    :  
 265    :    // Initial state is empty, and accesses are not redundant.
 266  E :    bool redundant_read1 = state.HasNonRedundantAccess(kReadEax42);
 267  E :    bool redundant_write1 = state.HasNonRedundantAccess(kWriteEax42);
 268  E :    EXPECT_TRUE(redundant_read1);
 269  E :    EXPECT_TRUE(redundant_write1);
 270    :  
 271    :    // Perform a read of [eax + 42].
 272  E :    state.Execute(kReadEax42);
 273  E :    EXPECT_TRUE(state.Contains(assm::eax, 42));
 274    :  
 275    :    // After the read, accesses are redundant.
 276  E :    bool redundant_read2 = state.HasNonRedundantAccess(kReadEax42);
 277  E :    bool redundant_write2 = state.HasNonRedundantAccess(kWriteEax42);
 278  E :    EXPECT_FALSE(redundant_read2);
 279  E :    EXPECT_FALSE(redundant_write2);
 280  E :  }
 281    :  
 282  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessOperandKind) {
 283  E :    TestMemoryAccessAnalysisState state;
 284    :  
 285    :    // Instructions without memory access, on empty state.
 286  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kRegsOnly));
 287  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax));
 288  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax42));
 289    :  
 290    :    // Initial state is empty, and accesses are not redundant.
 291  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax));
 292  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax42));
 293  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteWithScale));
 294  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteDispl));
 295  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteEax42));
 296  E :  }
 297    :  
 298  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessWithPrefix) {
 299  E :    TestMemoryAccessAnalysisState state;
 300  E :    state.Execute(kRepMovsb);
 301  E :    bool redundant = state.HasNonRedundantAccess(kRepMovsb);
 302  E :    EXPECT_TRUE(redundant);
 303  E :  }
 304    :  
 305  E :  TEST_F(MemoryAccessAnalysisTest, GetStateOf) {
 306    :    // It is valid to get the state of a NULL block.
 307  E :    GetStateAtEntryOf(NULL, &state_);
 308  E :    EXPECT_TRUE(state_.IsEmpty());
 309    :  
 310    :    // Get an non-existing basic block.
 311  E :    GetStateAtEntryOf(bb_, &state_);
 312  E :    EXPECT_TRUE(state_.IsEmpty());
 313  E :  }
 314    :  
 315  E :  TEST_F(MemoryAccessAnalysisTest, IntersectEmpty) {
 316  E :    memory_access_.GetStateAtEntryOf(bb_, &state_);
 317  E :    EXPECT_TRUE(state_.IsEmpty());
 318    :  
 319    :    // Perform an initial intersection with an empty set.
 320  E :    TestMemoryAccessAnalysisState state;
 321  E :    Intersect(bb_, state);
 322    :  
 323  E :    state.Execute(kReadEax10);
 324  E :    state.Execute(kReadEax11);
 325    :  
 326    :    // Perform an second intersection with a non empty set.
 327  E :    Intersect(bb_, state_);
 328  E :    GetStateAtEntryOf(bb_, &state_);
 329    :  
 330    :    // The results must be empty.
 331  E :    EXPECT_TRUE(state_.IsEmpty());
 332  E :  }
 333    :  
 334  E :  TEST_F(MemoryAccessAnalysisTest, IntersectStates) {
 335    :    // Intersection with displacements [10, 11, 12, 13, 14, 15].
 336  E :    TestMemoryAccessAnalysisState state1;
 337  E :    state1.Execute(kReadEax10);
 338  E :    state1.Execute(kReadEax11);
 339  E :    state1.Execute(kReadEax12);
 340  E :    state1.Execute(kReadEax13);
 341  E :    state1.Execute(kReadEax14);
 342  E :    state1.Execute(kReadEax15);
 343  E :    Intersect(bb_, state1);
 344    :  
 345    :    // Intersection with displacements [10, 11, 12, 14].
 346  E :    TestMemoryAccessAnalysisState state2;
 347  E :    state2.Execute(kReadEax10);
 348  E :    state2.Execute(kReadEax11);
 349  E :    state2.Execute(kReadEax12);
 350  E :    state2.Execute(kReadEax14);
 351  E :    Intersect(bb_, state2);
 352    :  
 353    :    // Check current state [10, 11, 12, 14].
 354  E :    GetStateAtEntryOf(bb_, &state_);
 355  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 356  E :    EXPECT_TRUE(state_.Contains(assm::eax, 11));
 357  E :    EXPECT_TRUE(state_.Contains(assm::eax, 12));
 358  E :    EXPECT_FALSE(state_.Contains(assm::eax, 13));
 359  E :    EXPECT_TRUE(state_.Contains(assm::eax, 14));
 360  E :    EXPECT_FALSE(state_.Contains(assm::eax, 15));
 361    :  
 362    :    // Intersection with displacements [10, 11, 15].
 363  E :    TestMemoryAccessAnalysisState state3;
 364  E :    state3.Execute(kReadEax10);
 365  E :    state3.Execute(kReadEax11);
 366  E :    state3.Execute(kReadEax15);
 367  E :    Intersect(bb_, state3);
 368    :  
 369    :    // Check current state [10, 11].
 370  E :    GetStateAtEntryOf(bb_, &state_);
 371  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 372  E :    EXPECT_TRUE(state_.Contains(assm::eax, 11));
 373  E :    EXPECT_FALSE(state_.Contains(assm::eax, 12));
 374  E :    EXPECT_FALSE(state_.Contains(assm::eax, 13));
 375  E :    EXPECT_FALSE(state_.Contains(assm::eax, 14));
 376  E :    EXPECT_FALSE(state_.Contains(assm::eax, 15));
 377    :  
 378    :    // Intersection with displacements [15].
 379  E :    TestMemoryAccessAnalysisState state4;
 380  E :    state4.Execute(kReadEax15);
 381  E :    Intersect(bb_, state4);
 382    :  
 383    :    // The state must be empty.
 384  E :    GetStateAtEntryOf(bb_, &state_);
 385  E :    EXPECT_TRUE(state_.IsEmpty());
 386  E :  }
 387    :  
 388  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardSimple) {
 389  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 390  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 391    :  
 392  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax));
 393  E :    EXPECT_TRUE(state_.Contains(assm::eax, 0));
 394  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 395    :  
 396  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kClearEax));
 397  E :    EXPECT_TRUE(state_.IsEmpty());
 398    :  
 399  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kLeaEax));
 400  E :    EXPECT_TRUE(state_.IsEmpty());
 401  E :  }
 402    :  
 403  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardWithCallRet) {
 404  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 405  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 406  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kCall));
 407  E :    EXPECT_TRUE(state_.IsEmpty());
 408    :  
 409  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 410  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 411  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRet));
 412  E :    EXPECT_TRUE(state_.IsEmpty());
 413  E :  }
 414    :  
 415  E :  TEST_F(MemoryAccessAnalysisTest, UnknownInstruction) {
 416    :    // Ensure unknown instructions are processed correctly.
 417  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 418  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 419  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRdtsc));
 420  E :    EXPECT_TRUE(state_.IsEmpty());
 421  E :  }
 422    :  
 423  E :  TEST_F(MemoryAccessAnalysisTest, Analyze) {
 424  E :    BasicBlockSubGraph subgraph;
 425    :  
 426    :    BlockDescription* block = subgraph.AddBlockDescription(
 427  E :        "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
 428    :  
 429  E :    BasicCodeBlock* bb_if = subgraph.AddBasicCodeBlock("if");
 430  E :    BasicCodeBlock* bb_true = subgraph.AddBasicCodeBlock("true");
 431  E :    BasicCodeBlock* bb_false = subgraph.AddBasicCodeBlock("false");
 432  E :    BasicCodeBlock* bb_end = subgraph.AddBasicCodeBlock("end");
 433    :  
 434  E :    ASSERT_TRUE(bb_if != NULL);
 435  E :    ASSERT_TRUE(bb_true != NULL);
 436  E :    ASSERT_TRUE(bb_false != NULL);
 437  E :    ASSERT_TRUE(bb_end != NULL);
 438    :  
 439  E :    block->basic_block_order.push_back(bb_if);
 440  E :    block->basic_block_order.push_back(bb_true);
 441  E :    block->basic_block_order.push_back(bb_end);
 442  E :    block->basic_block_order.push_back(bb_false);
 443    :  
 444  E :    AddSuccessorBetween(Successor::kConditionEqual, bb_if, bb_true);
 445  E :    AddSuccessorBetween(Successor::kConditionNotEqual, bb_if, bb_false);
 446  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_true, bb_end);
 447  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_false, bb_end);
 448    :  
 449    :    BasicBlockAssembler asm_if(bb_if->instructions().end(),
 450  E :                               &bb_if->instructions());
 451  E :    asm_if.mov(assm::ecx, Operand(assm::eax, Displacement(1, assm::kSize32Bit)));
 452    :    asm_if.mov(assm::edx,
 453  E :               Operand(assm::ecx, Displacement(12, assm::kSize32Bit)));
 454    :    asm_if.mov(assm::edx,
 455  E :               Operand(assm::eax, Displacement(42, assm::kSize32Bit)));
 456    :  
 457    :    BasicBlockAssembler asm_true(bb_true->instructions().end(),
 458  E :                                 &bb_true->instructions());
 459    :    asm_true.mov(assm::ecx,
 460  E :                 Operand(assm::eax, Displacement(1, assm::kSize32Bit)));
 461    :    asm_true.mov(assm::edx,
 462  E :                 Operand(assm::eax, Displacement(12, assm::kSize32Bit)));
 463    :    asm_true.mov(assm::ecx,
 464  E :                 Operand(assm::eax, Displacement(24, assm::kSize32Bit)));
 465    :  
 466    :    BasicBlockAssembler asm_false(bb_false->instructions().end(),
 467  E :                                  &bb_false->instructions());
 468    :    asm_false.mov(assm::ecx,
 469  E :                  Operand(assm::eax, Displacement(24, assm::kSize32Bit)));
 470    :    asm_false.mov(assm::edx,
 471  E :                  Operand(assm::eax, Displacement(48, assm::kSize32Bit)));
 472    :  
 473    :    // Analyze the flow graph.
 474  E :    memory_access_.Analyze(&subgraph);
 475    :  
 476    :    // State of first basic block is empty.
 477  E :    GetStateAtEntryOf(bb_if, &state_);
 478  E :    EXPECT_TRUE(state_.IsEmpty());
 479    :  
 480    :    // Get entry state of bb_true.
 481  E :    GetStateAtEntryOf(bb_true, &state_);
 482  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 483  E :    EXPECT_TRUE(state_.Contains(assm::ecx, 12));
 484  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 485    :  
 486    :    // Get entry state of bb_false.
 487  E :    GetStateAtEntryOf(bb_false, &state_);
 488  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 489  E :    EXPECT_TRUE(state_.Contains(assm::ecx, 12));
 490  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 491    :  
 492    :    // Get entry state of bb_end. Intersection of bb_true and bb_false.
 493  E :    GetStateAtEntryOf(bb_end, &state_);
 494  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 495  E :    EXPECT_FALSE(state_.Contains(assm::eax, 12));
 496  E :    EXPECT_FALSE(state_.Contains(assm::ecx, 12));
 497  E :    EXPECT_TRUE(state_.Contains(assm::eax, 24));
 498  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 499  E :  }
 500    :  
 501  E :  TEST_F(MemoryAccessAnalysisTest, AnalyzeWithData) {
 502  E :    BasicBlockSubGraph subgraph;
 503  E :    const uint8 raw_data[] = { 0, 1, 2, 3, 4 };
 504  E :    const size_t raw_data_len = ARRAYSIZE(raw_data);
 505    :  
 506    :    BlockDescription* block = subgraph.AddBlockDescription(
 507  E :        "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
 508    :  
 509  E :    BasicCodeBlock* bb = subgraph.AddBasicCodeBlock("bb");
 510    :    BasicDataBlock* data =
 511  E :        subgraph.AddBasicDataBlock("data", raw_data_len, &raw_data[0]);
 512    :  
 513  E :    block->basic_block_order.push_back(bb);
 514  E :    block->basic_block_order.push_back(data);
 515    :  
 516  E :    BasicBlockAssembler asm_bb(bb->instructions().end(), &bb->instructions());
 517  E :    asm_bb.ret();
 518    :  
 519    :    // Analyze the flow graph.
 520  E :    memory_access_.Analyze(&subgraph);
 521    :  
 522    :    // Expect empty state.
 523  E :    GetStateAtEntryOf(bb, &state_);
 524  E :    EXPECT_TRUE(state_.IsEmpty());
 525    :  
 526  E :    GetStateAtEntryOf(data, &state_);
 527  E :    EXPECT_TRUE(state_.IsEmpty());
 528  E :  }
 529    :  
 530    :  }  // namespace analysis
 531    :  }  // namespace block_graph

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