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_t kClearEax[] = {0x03, 0xC1};
  34    :  // _asm add ecx, [eax]
  35    :  const uint8_t kReadEax[] = {0x03, 0x08};
  36    :  // _asm add ecx, [eax + 42]
  37    :  const uint8_t kReadEax42[] = {0x03, 0x48, 0x2A};
  38    :  // _asm add eax, ecx
  39    :  const uint8_t kRegsOnly[] = {0x03, 0xC1};
  40    :  // _asm add [eax + ebx*2 + 42], ecx
  41    :  const uint8_t kWriteWithScale[] = {0x01, 0x4C, 0x58, 0x2A};
  42    :  // _asm add DWORD PTR [X], ecx
  43    :  const uint8_t kWriteDispl[] = {0x01, 0x0D, 0x80, 0x1E, 0xF2, 0x00};
  44    :  // _asm add [eax + 42], ecx
  45    :  const uint8_t kWriteEax42[] = {0x01, 0x48, 0x2A};
  46    :  // _asm lea ecx, [eax]
  47    :  const uint8_t kLeaEax[] = {0x8D, 0x08};
  48    :  // _asm lea ecx, [eax + 42]
  49    :  const uint8_t kLeaEax42[] = {0x8D, 0x48, 0x2A};
  50    :  
  51    :  // _asm repnz movsb
  52    :  const uint8_t kRepMovsb[] = {0xF2, 0xA4};
  53    :  
  54    :  // _asm add ecx, [eax + C]
  55    :  const uint8_t kReadEax10[] = {0x03, 0x48, 0x0A};
  56    :  const uint8_t kReadEax11[] = {0x03, 0x48, 0x0B};
  57    :  const uint8_t kReadEax12[] = {0x03, 0x48, 0x0C};
  58    :  const uint8_t kReadEax13[] = {0x03, 0x48, 0x0D};
  59    :  const uint8_t kReadEax14[] = {0x03, 0x48, 0x0E};
  60    :  const uint8_t kReadEax15[] = {0x03, 0x48, 0x0F};
  61    :  
  62    :  // _asm ret
  63    :  const uint8_t kRet[] = {0xC3};
  64    :  // _asm call <FFFFFFFF>
  65    :  const uint8_t kCall[] = {0xE8, 0xFF, 0xD7, 0xFF, 0xFF};
  66    :  // _asm rdtsc
  67    :  const uint8_t kRdtsc[] = {0x0F, 0x31};
  68    :  
  69    :  void AddSuccessorBetween(Successor::Condition condition,
  70    :                           BasicCodeBlock* from,
  71  E :                           BasicCodeBlock* to) {
  72  E :    from->successors().push_back(
  73    :        Successor(condition,
  74    :                  BasicBlockReference(BlockGraph::RELATIVE_REF,
  75    :                                      BlockGraph::Reference::kMaximumSize,
  76    :                                      to),
  77    :                  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_t displ) const;
  87    :  
  88    :    template <size_t N>
  89    :    bool HasNonRedundantAccess(const uint8_t(&data)[N]) const;
  90    :  
  91    :    template <size_t N>
  92    :    void Execute(const uint8_t(&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_t(&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(const assm::Register32& reg,
 140  E :                                               int32_t displ) const {
 141  E :    const std::set<int32_t>& offsets =
 142    :        active_memory_accesses_[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_t(&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_t(&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  E :  void MemoryAccessAnalysisTest::PropagateForward(const uint8_t(&data)[N]) {
 181    :    // Decode an instruction.
 182  E :    DCHECK_GT(assm::kMaxInstructionLength, N);
 183    :  
 184  E :    block_graph::Instruction temp;
 185  E :    bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
 186  E :    ASSERT_TRUE(decoded);
 187    :  
 188    :    // Expect to decode the entire buffer.
 189  E :    ASSERT_EQ(N, temp.size());
 190    :  
 191    :    // Execute the decoded instruction, and modify the current state.
 192  E :    MemoryAccessAnalysis::PropagateForward(temp, &state_);
 193  E :  }
 194    :  
 195  E :  TEST(MemoryAccessAnalysisStateTest, Constructor) {
 196    :    // Initial state is empty.
 197  E :    TestMemoryAccessAnalysisState state;
 198  E :    EXPECT_TRUE(state.IsEmpty());
 199  E :  }
 200    :  
 201  E :  TEST(MemoryAccessAnalysisStateTest, CopyConstructor) {
 202  E :    TestMemoryAccessAnalysisState state1;
 203    :  
 204  E :    state1.Execute(kReadEax);
 205  E :    state1.Execute(kWriteEax42);
 206    :  
 207  E :    EXPECT_TRUE(state1.Contains(assm::eax, 0));
 208  E :    EXPECT_TRUE(state1.Contains(assm::eax, 42));
 209    :  
 210    :    // Expect memory accesses to be copied into state2.
 211  E :    TestMemoryAccessAnalysisState state2(state1);
 212  E :    EXPECT_TRUE(state2.Contains(assm::eax, 0));
 213  E :    EXPECT_TRUE(state2.Contains(assm::eax, 42));
 214  E :  }
 215    :  
 216  E :  TEST(MemoryAccessAnalysisStateTest, Clear) {
 217  E :    TestMemoryAccessAnalysisState state;
 218    :  
 219  E :    state.Execute(kWriteEax42);
 220  E :    EXPECT_TRUE(!state.IsEmpty());
 221  E :    state.Clear();
 222  E :    EXPECT_TRUE(state.IsEmpty());
 223  E :  }
 224    :  
 225  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteOperandKind) {
 226  E :    TestMemoryAccessAnalysisState state;
 227    :  
 228  E :    state.Execute(kRegsOnly);
 229  E :    EXPECT_TRUE(state.IsEmpty());
 230    :  
 231  E :    state.Execute(kWriteWithScale);
 232  E :    EXPECT_TRUE(state.IsEmpty());
 233    :  
 234  E :    state.Execute(kWriteDispl);
 235  E :    EXPECT_TRUE(state.IsEmpty());
 236    :  
 237  E :    state.Execute(kReadEax);
 238  E :    EXPECT_TRUE(state.Contains(assm::eax, 0));
 239    :  
 240  E :    state.Execute(kReadEax42);
 241  E :    EXPECT_TRUE(state.Contains(assm::eax, 42));
 242  E :  }
 243    :  
 244  E :  TEST(MemoryAccessAnalysisStateTest, LeaOperand) {
 245  E :    TestMemoryAccessAnalysisState state;
 246    :  
 247    :    // LEA do not perform a memory access.
 248  E :    state.Execute(kLeaEax);
 249  E :    EXPECT_FALSE(state.Contains(assm::eax, 0));
 250  E :    state.Execute(kLeaEax42);
 251  E :    EXPECT_FALSE(state.Contains(assm::eax, 42));
 252  E :  }
 253    :  
 254  E :  TEST(MemoryAccessAnalysisStateTest, ExecuteWithPrefix) {
 255  E :    TestMemoryAccessAnalysisState state;
 256    :  
 257  E :    state.Execute(kRepMovsb);
 258  E :    EXPECT_TRUE(state.IsEmpty());
 259  E :  }
 260    :  
 261  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccess) {
 262  E :    TestMemoryAccessAnalysisState state;
 263    :  
 264    :    // Initial state is empty, and accesses are not redundant.
 265  E :    bool redundant_read1 = state.HasNonRedundantAccess(kReadEax42);
 266  E :    bool redundant_write1 = state.HasNonRedundantAccess(kWriteEax42);
 267  E :    EXPECT_TRUE(redundant_read1);
 268  E :    EXPECT_TRUE(redundant_write1);
 269    :  
 270    :    // Perform a read of [eax + 42].
 271  E :    state.Execute(kReadEax42);
 272  E :    EXPECT_TRUE(state.Contains(assm::eax, 42));
 273    :  
 274    :    // After the read, accesses are redundant.
 275  E :    bool redundant_read2 = state.HasNonRedundantAccess(kReadEax42);
 276  E :    bool redundant_write2 = state.HasNonRedundantAccess(kWriteEax42);
 277  E :    EXPECT_FALSE(redundant_read2);
 278  E :    EXPECT_FALSE(redundant_write2);
 279  E :  }
 280    :  
 281  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessOperandKind) {
 282  E :    TestMemoryAccessAnalysisState state;
 283    :  
 284    :    // Instructions without memory access, on empty state.
 285  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kRegsOnly));
 286  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax));
 287  E :    EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax42));
 288    :  
 289    :    // Initial state is empty, and accesses are not redundant.
 290  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax));
 291  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax42));
 292  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteWithScale));
 293  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteDispl));
 294  E :    EXPECT_TRUE(state.HasNonRedundantAccess(kWriteEax42));
 295  E :  }
 296    :  
 297  E :  TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessWithPrefix) {
 298  E :    TestMemoryAccessAnalysisState state;
 299  E :    state.Execute(kRepMovsb);
 300  E :    bool redundant = state.HasNonRedundantAccess(kRepMovsb);
 301  E :    EXPECT_TRUE(redundant);
 302  E :  }
 303    :  
 304  E :  TEST_F(MemoryAccessAnalysisTest, GetStateOf) {
 305    :    // It is valid to get the state of a NULL block.
 306  E :    GetStateAtEntryOf(NULL, &state_);
 307  E :    EXPECT_TRUE(state_.IsEmpty());
 308    :  
 309    :    // Get an non-existing basic block.
 310  E :    GetStateAtEntryOf(bb_, &state_);
 311  E :    EXPECT_TRUE(state_.IsEmpty());
 312  E :  }
 313    :  
 314  E :  TEST_F(MemoryAccessAnalysisTest, IntersectEmpty) {
 315  E :    memory_access_.GetStateAtEntryOf(bb_, &state_);
 316  E :    EXPECT_TRUE(state_.IsEmpty());
 317    :  
 318    :    // Perform an initial intersection with an empty set.
 319  E :    TestMemoryAccessAnalysisState state;
 320  E :    Intersect(bb_, state);
 321    :  
 322  E :    state.Execute(kReadEax10);
 323  E :    state.Execute(kReadEax11);
 324    :  
 325    :    // Perform an second intersection with a non empty set.
 326  E :    Intersect(bb_, state_);
 327  E :    GetStateAtEntryOf(bb_, &state_);
 328    :  
 329    :    // The results must be empty.
 330  E :    EXPECT_TRUE(state_.IsEmpty());
 331  E :  }
 332    :  
 333  E :  TEST_F(MemoryAccessAnalysisTest, IntersectStates) {
 334    :    // Intersection with displacements [10, 11, 12, 13, 14, 15].
 335  E :    TestMemoryAccessAnalysisState state1;
 336  E :    state1.Execute(kReadEax10);
 337  E :    state1.Execute(kReadEax11);
 338  E :    state1.Execute(kReadEax12);
 339  E :    state1.Execute(kReadEax13);
 340  E :    state1.Execute(kReadEax14);
 341  E :    state1.Execute(kReadEax15);
 342  E :    Intersect(bb_, state1);
 343    :  
 344    :    // Intersection with displacements [10, 11, 12, 14].
 345  E :    TestMemoryAccessAnalysisState state2;
 346  E :    state2.Execute(kReadEax10);
 347  E :    state2.Execute(kReadEax11);
 348  E :    state2.Execute(kReadEax12);
 349  E :    state2.Execute(kReadEax14);
 350  E :    Intersect(bb_, state2);
 351    :  
 352    :    // Check current state [10, 11, 12, 14].
 353  E :    GetStateAtEntryOf(bb_, &state_);
 354  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 355  E :    EXPECT_TRUE(state_.Contains(assm::eax, 11));
 356  E :    EXPECT_TRUE(state_.Contains(assm::eax, 12));
 357  E :    EXPECT_FALSE(state_.Contains(assm::eax, 13));
 358  E :    EXPECT_TRUE(state_.Contains(assm::eax, 14));
 359  E :    EXPECT_FALSE(state_.Contains(assm::eax, 15));
 360    :  
 361    :    // Intersection with displacements [10, 11, 15].
 362  E :    TestMemoryAccessAnalysisState state3;
 363  E :    state3.Execute(kReadEax10);
 364  E :    state3.Execute(kReadEax11);
 365  E :    state3.Execute(kReadEax15);
 366  E :    Intersect(bb_, state3);
 367    :  
 368    :    // Check current state [10, 11].
 369  E :    GetStateAtEntryOf(bb_, &state_);
 370  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 371  E :    EXPECT_TRUE(state_.Contains(assm::eax, 11));
 372  E :    EXPECT_FALSE(state_.Contains(assm::eax, 12));
 373  E :    EXPECT_FALSE(state_.Contains(assm::eax, 13));
 374  E :    EXPECT_FALSE(state_.Contains(assm::eax, 14));
 375  E :    EXPECT_FALSE(state_.Contains(assm::eax, 15));
 376    :  
 377    :    // Intersection with displacements [15].
 378  E :    TestMemoryAccessAnalysisState state4;
 379  E :    state4.Execute(kReadEax15);
 380  E :    Intersect(bb_, state4);
 381    :  
 382    :    // The state must be empty.
 383  E :    GetStateAtEntryOf(bb_, &state_);
 384  E :    EXPECT_TRUE(state_.IsEmpty());
 385  E :  }
 386    :  
 387  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardSimple) {
 388  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 389  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 390    :  
 391  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax));
 392  E :    EXPECT_TRUE(state_.Contains(assm::eax, 0));
 393  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 394    :  
 395  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kClearEax));
 396  E :    EXPECT_TRUE(state_.IsEmpty());
 397    :  
 398  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kLeaEax));
 399  E :    EXPECT_TRUE(state_.IsEmpty());
 400  E :  }
 401    :  
 402  E :  TEST_F(MemoryAccessAnalysisTest, PropagateForwardWithCallRet) {
 403  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 404  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 405  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kCall));
 406  E :    EXPECT_TRUE(state_.IsEmpty());
 407    :  
 408  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 409  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 410  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRet));
 411  E :    EXPECT_TRUE(state_.IsEmpty());
 412  E :  }
 413    :  
 414  E :  TEST_F(MemoryAccessAnalysisTest, UnknownInstruction) {
 415    :    // Ensure unknown instructions are processed correctly.
 416  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
 417  E :    EXPECT_TRUE(state_.Contains(assm::eax, 10));
 418  E :    ASSERT_NO_FATAL_FAILURE(PropagateForward(kRdtsc));
 419  E :    EXPECT_TRUE(state_.IsEmpty());
 420  E :  }
 421    :  
 422  E :  TEST_F(MemoryAccessAnalysisTest, Analyze) {
 423  E :    BasicBlockSubGraph subgraph;
 424    :  
 425  E :    BlockDescription* block = subgraph.AddBlockDescription(
 426    :        "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
 427    :  
 428  E :    BasicCodeBlock* bb_if = subgraph.AddBasicCodeBlock("if");
 429  E :    BasicCodeBlock* bb_true = subgraph.AddBasicCodeBlock("true");
 430  E :    BasicCodeBlock* bb_false = subgraph.AddBasicCodeBlock("false");
 431  E :    BasicCodeBlock* bb_end = subgraph.AddBasicCodeBlock("end");
 432    :  
 433  E :    ASSERT_TRUE(bb_if != NULL);
 434  E :    ASSERT_TRUE(bb_true != NULL);
 435  E :    ASSERT_TRUE(bb_false != NULL);
 436  E :    ASSERT_TRUE(bb_end != NULL);
 437    :  
 438  E :    block->basic_block_order.push_back(bb_if);
 439  E :    block->basic_block_order.push_back(bb_true);
 440  E :    block->basic_block_order.push_back(bb_end);
 441  E :    block->basic_block_order.push_back(bb_false);
 442    :  
 443  E :    AddSuccessorBetween(Successor::kConditionEqual, bb_if, bb_true);
 444  E :    AddSuccessorBetween(Successor::kConditionNotEqual, bb_if, bb_false);
 445  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_true, bb_end);
 446  E :    AddSuccessorBetween(Successor::kConditionTrue, bb_false, bb_end);
 447    :  
 448  E :    BasicBlockAssembler asm_if(bb_if->instructions().end(),
 449    :                               &bb_if->instructions());
 450  E :    asm_if.mov(assm::ecx, Operand(assm::eax, Displacement(1, assm::kSize32Bit)));
 451  E :    asm_if.mov(assm::edx,
 452    :               Operand(assm::ecx, Displacement(12, assm::kSize32Bit)));
 453  E :    asm_if.mov(assm::edx,
 454    :               Operand(assm::eax, Displacement(42, assm::kSize32Bit)));
 455    :  
 456  E :    BasicBlockAssembler asm_true(bb_true->instructions().end(),
 457    :                                 &bb_true->instructions());
 458  E :    asm_true.mov(assm::ecx,
 459    :                 Operand(assm::eax, Displacement(1, assm::kSize32Bit)));
 460  E :    asm_true.mov(assm::edx,
 461    :                 Operand(assm::eax, Displacement(12, assm::kSize32Bit)));
 462  E :    asm_true.mov(assm::ecx,
 463    :                 Operand(assm::eax, Displacement(24, assm::kSize32Bit)));
 464    :  
 465  E :    BasicBlockAssembler asm_false(bb_false->instructions().end(),
 466    :                                  &bb_false->instructions());
 467  E :    asm_false.mov(assm::ecx,
 468    :                  Operand(assm::eax, Displacement(24, assm::kSize32Bit)));
 469  E :    asm_false.mov(assm::edx,
 470    :                  Operand(assm::eax, Displacement(48, assm::kSize32Bit)));
 471    :  
 472    :    // Analyze the flow graph.
 473  E :    memory_access_.Analyze(&subgraph);
 474    :  
 475    :    // State of first basic block is empty.
 476  E :    GetStateAtEntryOf(bb_if, &state_);
 477  E :    EXPECT_TRUE(state_.IsEmpty());
 478    :  
 479    :    // Get entry state of bb_true.
 480  E :    GetStateAtEntryOf(bb_true, &state_);
 481  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 482  E :    EXPECT_TRUE(state_.Contains(assm::ecx, 12));
 483  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 484    :  
 485    :    // Get entry state of bb_false.
 486  E :    GetStateAtEntryOf(bb_false, &state_);
 487  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 488  E :    EXPECT_TRUE(state_.Contains(assm::ecx, 12));
 489  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 490    :  
 491    :    // Get entry state of bb_end. Intersection of bb_true and bb_false.
 492  E :    GetStateAtEntryOf(bb_end, &state_);
 493  E :    EXPECT_TRUE(state_.Contains(assm::eax, 1));
 494  E :    EXPECT_FALSE(state_.Contains(assm::eax, 12));
 495  E :    EXPECT_FALSE(state_.Contains(assm::ecx, 12));
 496  E :    EXPECT_TRUE(state_.Contains(assm::eax, 24));
 497  E :    EXPECT_TRUE(state_.Contains(assm::eax, 42));
 498  E :  }
 499    :  
 500  E :  TEST_F(MemoryAccessAnalysisTest, AnalyzeWithData) {
 501  E :    BasicBlockSubGraph subgraph;
 502  E :    const uint8_t raw_data[] = {0, 1, 2, 3, 4};
 503  E :    const size_t raw_data_len = ARRAYSIZE(raw_data);
 504    :  
 505  E :    BlockDescription* block = subgraph.AddBlockDescription(
 506    :        "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
 507    :  
 508  E :    BasicCodeBlock* bb = subgraph.AddBasicCodeBlock("bb");
 509    :    BasicDataBlock* data =
 510  E :        subgraph.AddBasicDataBlock("data", raw_data_len, &raw_data[0]);
 511    :  
 512  E :    block->basic_block_order.push_back(bb);
 513  E :    block->basic_block_order.push_back(data);
 514    :  
 515  E :    BasicBlockAssembler asm_bb(bb->instructions().end(), &bb->instructions());
 516  E :    asm_bb.ret();
 517    :  
 518    :    // Analyze the flow graph.
 519  E :    memory_access_.Analyze(&subgraph);
 520    :  
 521    :    // Expect empty state.
 522  E :    GetStateAtEntryOf(bb, &state_);
 523  E :    EXPECT_TRUE(state_.IsEmpty());
 524    :  
 525  E :    GetStateAtEntryOf(data, &state_);
 526  E :    EXPECT_TRUE(state_.IsEmpty());
 527  E :  }
 528    :  
 529    :  }  // namespace analysis
 530    :  }  // namespace block_graph

Coverage information generated Fri Jul 29 11:00:21 2016.