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
|