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
|