Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: sandbox/linux/seccomp-bpf/codegen_unittest.cc

Issue 703533002: CodeGen: refactor API [1/3] (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: s/Addr/Node/ and tweak comments Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/linux/seccomp-bpf/codegen.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/linux/seccomp-bpf/codegen.h" 5 #include "sandbox/linux/seccomp-bpf/codegen.h"
6 6
7 #include <linux/filter.h> 7 #include <linux/filter.h>
8 8
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 16 matching lines...) Expand all
27 }; 27 };
28 28
29 namespace { 29 namespace {
30 30
31 enum { 31 enum {
32 NO_FLAGS = 0x0000, 32 NO_FLAGS = 0x0000,
33 HAS_MERGEABLE_TAILS = 0x0001, 33 HAS_MERGEABLE_TAILS = 0x0001,
34 }; 34 };
35 35
36 using ProgramTestFunc = void (*)(CodeGenUnittestHelper* gen, 36 using ProgramTestFunc = void (*)(CodeGenUnittestHelper* gen,
37 Instruction* head, 37 CodeGen::Node head,
38 int flags); 38 int flags);
39 39
40 class ProgramTest : public ::testing::TestWithParam<ProgramTestFunc> { 40 class ProgramTest : public ::testing::TestWithParam<ProgramTestFunc> {
41 protected: 41 protected:
42 ProgramTest() : gen_() {} 42 ProgramTest() : gen_() {}
43 43
44 // RunTest runs the test function argument. It should be called at 44 // RunTest runs the test function argument. It should be called at
45 // the end of each program test case. 45 // the end of each program test case.
46 void RunTest(Instruction* head, int flags) { GetParam()(&gen_, head, flags); } 46 void RunTest(CodeGen::Node head, int flags) {
47 GetParam()(&gen_, head, flags);
48 }
47 49
48 Instruction* MakeInstruction(uint16_t code, 50 CodeGen::Node MakeInstruction(uint16_t code,
49 uint32_t k, 51 uint32_t k,
50 Instruction* next = nullptr) { 52 CodeGen::Node jt = nullptr,
51 Instruction* ret = gen_.MakeInstruction(code, k, next); 53 CodeGen::Node jf = nullptr) {
54 CodeGen::Node ret = gen_.MakeInstruction(code, k, jt, jf);
52 EXPECT_NE(nullptr, ret); 55 EXPECT_NE(nullptr, ret);
53 EXPECT_EQ(code, ret->code); 56 EXPECT_EQ(code, ret->code);
54 EXPECT_EQ(k, ret->k); 57 EXPECT_EQ(k, ret->k);
55 if (code == BPF_JMP + BPF_JA) { 58 if (BPF_CLASS(code) == BPF_JMP) {
56 // Annoying inconsistency.
57 EXPECT_EQ(nullptr, ret->next); 59 EXPECT_EQ(nullptr, ret->next);
58 EXPECT_EQ(next, ret->jt_ptr); 60 EXPECT_EQ(jt, ret->jt_ptr);
61 EXPECT_EQ(jf, ret->jf_ptr);
59 } else { 62 } else {
60 EXPECT_EQ(next, ret->next); 63 EXPECT_EQ(jt, ret->next);
61 EXPECT_EQ(nullptr, ret->jt_ptr); 64 EXPECT_EQ(nullptr, ret->jt_ptr);
65 EXPECT_EQ(nullptr, ret->jf_ptr);
62 } 66 }
63 EXPECT_EQ(nullptr, ret->jf_ptr);
64 return ret; 67 return ret;
65 } 68 }
66 69
67 Instruction* MakeInstruction(uint16_t code,
68 uint32_t k,
69 Instruction* jt,
70 Instruction* jf) {
71 Instruction* ret = gen_.MakeInstruction(code, k, jt, jf);
72 EXPECT_NE(nullptr, ret);
73 EXPECT_EQ(code, ret->code);
74 EXPECT_EQ(k, ret->k);
75 EXPECT_EQ(nullptr, ret->next);
76 EXPECT_EQ(jt, ret->jt_ptr);
77 EXPECT_EQ(jf, ret->jf_ptr);
78 return ret;
79 }
80
81 private: 70 private:
82 CodeGenUnittestHelper gen_; 71 CodeGenUnittestHelper gen_;
83 }; 72 };
84 73
85 TEST_P(ProgramTest, OneInstruction) { 74 TEST_P(ProgramTest, OneInstruction) {
86 // Create the most basic valid BPF program: 75 // Create the most basic valid BPF program:
87 // RET 0 76 // RET 0
88 Instruction* head = MakeInstruction(BPF_RET + BPF_K, 0); 77 CodeGen::Node head = MakeInstruction(BPF_RET + BPF_K, 0);
89 RunTest(head, NO_FLAGS); 78 RunTest(head, NO_FLAGS);
90 } 79 }
91 80
92 TEST_P(ProgramTest, SimpleBranch) { 81 TEST_P(ProgramTest, SimpleBranch) {
93 // Create a program with a single branch: 82 // Create a program with a single branch:
94 // JUMP if eq 42 then $0 else $1 83 // JUMP if eq 42 then $0 else $1
95 // 0: RET 1 84 // 0: RET 1
96 // 1: RET 0 85 // 1: RET 0
97 Instruction* head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 86 CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42,
98 42, 87 MakeInstruction(BPF_RET + BPF_K, 1),
99 MakeInstruction(BPF_RET + BPF_K, 1), 88 MakeInstruction(BPF_RET + BPF_K, 0));
100 MakeInstruction(BPF_RET + BPF_K, 0));
101 RunTest(head, NO_FLAGS); 89 RunTest(head, NO_FLAGS);
102 } 90 }
103 91
104 TEST_P(ProgramTest, AtypicalBranch) { 92 TEST_P(ProgramTest, AtypicalBranch) {
105 // Create a program with a single branch: 93 // Create a program with a single branch:
106 // JUMP if eq 42 then $0 else $0 94 // JUMP if eq 42 then $0 else $0
107 // 0: RET 0 95 // 0: RET 0
108 96
109 Instruction* ret = MakeInstruction(BPF_RET + BPF_K, 0); 97 CodeGen::Node ret = MakeInstruction(BPF_RET + BPF_K, 0);
110 Instruction* head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret); 98 CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
111 99
112 // N.B.: As the instructions in both sides of the branch are already 100 // N.B.: As the instructions in both sides of the branch are already
113 // the same object, we do not actually have any "mergeable" branches. 101 // the same object, we do not actually have any "mergeable" branches.
114 // This needs to be reflected in our choice of "flags". 102 // This needs to be reflected in our choice of "flags".
115 RunTest(head, NO_FLAGS); 103 RunTest(head, NO_FLAGS);
116 } 104 }
117 105
118 TEST_P(ProgramTest, Complex) { 106 TEST_P(ProgramTest, Complex) {
119 // Creates a basic BPF program that we'll use to test some of the code: 107 // Creates a basic BPF program that we'll use to test some of the code:
120 // JUMP if eq 42 the $0 else $1 (insn6) 108 // JUMP if eq 42 the $0 else $1 (insn6)
121 // 0: LD 23 (insn5) 109 // 0: LD 23 (insn5)
122 // 1: JUMP if eq 42 then $2 else $4 (insn4) 110 // 1: JUMP if eq 42 then $2 else $4 (insn4)
123 // 2: JUMP to $3 (insn2) 111 // 2: JUMP to $3 (insn2)
124 // 3: LD 42 (insn1) 112 // 3: LD 42 (insn1)
125 // RET 42 (insn0) 113 // RET 42 (insn0)
126 // 4: LD 42 (insn3) 114 // 4: LD 42 (insn3)
127 // RET 42 (insn3+) 115 // RET 42 (insn3+)
128 Instruction* insn0 = MakeInstruction(BPF_RET + BPF_K, 42); 116 CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
129 Instruction* insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); 117 CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
130 Instruction* insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1); 118 CodeGen::Node insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1);
131 119
132 // We explicitly duplicate instructions so that MergeTails() can coalesce 120 // We explicitly duplicate instructions so that MergeTails() can coalesce
133 // them later. 121 // them later.
134 Instruction* insn3 = MakeInstruction( 122 CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42,
135 BPF_LD + BPF_W + BPF_ABS, 42, MakeInstruction(BPF_RET + BPF_K, 42)); 123 MakeInstruction(BPF_RET + BPF_K, 42));
136 124
137 Instruction* insn4 = 125 CodeGen::Node insn4 =
138 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); 126 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3);
139 Instruction* insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4); 127 CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
140 128
141 // Force a basic block that ends in neither a jump instruction nor a return 129 // Force a basic block that ends in neither a jump instruction nor a return
142 // instruction. It only contains "insn5". This exercises one of the less 130 // instruction. It only contains "insn5". This exercises one of the less
143 // common code paths in the topo-sort algorithm. 131 // common code paths in the topo-sort algorithm.
144 // This also gives us a diamond-shaped pattern in our graph, which stresses 132 // This also gives us a diamond-shaped pattern in our graph, which stresses
145 // another aspect of the topo-sort algorithm (namely, the ability to 133 // another aspect of the topo-sort algorithm (namely, the ability to
146 // correctly count the incoming branches for subtrees that are not disjunct). 134 // correctly count the incoming branches for subtrees that are not disjunct).
147 Instruction* insn6 = 135 CodeGen::Node insn6 =
148 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4); 136 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
149 137
150 RunTest(insn6, HAS_MERGEABLE_TAILS); 138 RunTest(insn6, HAS_MERGEABLE_TAILS);
151 } 139 }
152 140
153 TEST_P(ProgramTest, ConfusingTails) { 141 TEST_P(ProgramTest, ConfusingTails) {
154 // This simple program demonstrates https://crbug.com/351103/ 142 // This simple program demonstrates https://crbug.com/351103/
155 // The two "LOAD 0" instructions are blocks of their own. MergeTails() could 143 // The two "LOAD 0" instructions are blocks of their own. MergeTails() could
156 // be tempted to merge them since they are the same. However, they are 144 // be tempted to merge them since they are the same. However, they are
157 // not mergeable because they fall-through to non semantically equivalent 145 // not mergeable because they fall-through to non semantically equivalent
158 // blocks. 146 // blocks.
159 // Without the fix for this bug, this program should trigger the check in 147 // Without the fix for this bug, this program should trigger the check in
160 // CompileAndCompare: the serialized graphs from the program and its compiled 148 // CompileAndCompare: the serialized graphs from the program and its compiled
161 // version will differ. 149 // version will differ.
162 // 150 //
163 // 0) LOAD 1 // ??? 151 // 0) LOAD 1 // ???
164 // 1) if A == 0x1; then JMP 2 else JMP 3 152 // 1) if A == 0x1; then JMP 2 else JMP 3
165 // 2) LOAD 0 // System call number 153 // 2) LOAD 0 // System call number
166 // 3) if A == 0x2; then JMP 4 else JMP 5 154 // 3) if A == 0x2; then JMP 4 else JMP 5
167 // 4) LOAD 0 // System call number 155 // 4) LOAD 0 // System call number
168 // 5) if A == 0x1; then JMP 6 else JMP 7 156 // 5) if A == 0x1; then JMP 6 else JMP 7
169 // 6) RET 0 157 // 6) RET 0
170 // 7) RET 1 158 // 7) RET 1
171 159
172 Instruction* i7 = MakeInstruction(BPF_RET + BPF_K, 1); 160 CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
173 Instruction* i6 = MakeInstruction(BPF_RET + BPF_K, 0); 161 CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
174 Instruction* i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); 162 CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
175 Instruction* i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5); 163 CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
176 Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); 164 CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
177 Instruction* i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3); 165 CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
178 Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); 166 CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
179 Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); 167 CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
180 168
181 RunTest(i0, NO_FLAGS); 169 RunTest(i0, NO_FLAGS);
182 } 170 }
183 171
184 TEST_P(ProgramTest, ConfusingTailsBasic) { 172 TEST_P(ProgramTest, ConfusingTailsBasic) {
185 // Without the fix for https://crbug.com/351103/, (see 173 // Without the fix for https://crbug.com/351103/, (see
186 // SampleProgramConfusingTails()), this would generate a cyclic graph and 174 // SampleProgramConfusingTails()), this would generate a cyclic graph and
187 // crash as the two "LOAD 0" instructions would get merged. 175 // crash as the two "LOAD 0" instructions would get merged.
188 // 176 //
189 // 0) LOAD 1 // ??? 177 // 0) LOAD 1 // ???
190 // 1) if A == 0x1; then JMP 2 else JMP 3 178 // 1) if A == 0x1; then JMP 2 else JMP 3
191 // 2) LOAD 0 // System call number 179 // 2) LOAD 0 // System call number
192 // 3) if A == 0x2; then JMP 4 else JMP 5 180 // 3) if A == 0x2; then JMP 4 else JMP 5
193 // 4) LOAD 0 // System call number 181 // 4) LOAD 0 // System call number
194 // 5) RET 1 182 // 5) RET 1
195 183
196 Instruction* i5 = MakeInstruction(BPF_RET + BPF_K, 1); 184 CodeGen::Node i5 = MakeInstruction(BPF_RET + BPF_K, 1);
197 Instruction* i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5); 185 CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
198 Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); 186 CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
199 Instruction* i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3); 187 CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
200 Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); 188 CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
201 Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); 189 CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
202 190
203 RunTest(i0, NO_FLAGS); 191 RunTest(i0, NO_FLAGS);
204 } 192 }
205 193
206 TEST_P(ProgramTest, ConfusingTailsMergeable) { 194 TEST_P(ProgramTest, ConfusingTailsMergeable) {
207 // This is similar to SampleProgramConfusingTails(), except that 195 // This is similar to SampleProgramConfusingTails(), except that
208 // instructions 2 and 4 are now RET instructions. 196 // instructions 2 and 4 are now RET instructions.
209 // In PointerCompare(), this exercises the path where two blocks are of the 197 // In PointerCompare(), this exercises the path where two blocks are of the
210 // same length and identical and the last instruction is a JMP or RET, so the 198 // same length and identical and the last instruction is a JMP or RET, so the
211 // following blocks don't need to be looked at and the blocks are mergeable. 199 // following blocks don't need to be looked at and the blocks are mergeable.
212 // 200 //
213 // 0) LOAD 1 // ??? 201 // 0) LOAD 1 // ???
214 // 1) if A == 0x1; then JMP 2 else JMP 3 202 // 1) if A == 0x1; then JMP 2 else JMP 3
215 // 2) RET 42 203 // 2) RET 42
216 // 3) if A == 0x2; then JMP 4 else JMP 5 204 // 3) if A == 0x2; then JMP 4 else JMP 5
217 // 4) RET 42 205 // 4) RET 42
218 // 5) if A == 0x1; then JMP 6 else JMP 7 206 // 5) if A == 0x1; then JMP 6 else JMP 7
219 // 6) RET 0 207 // 6) RET 0
220 // 7) RET 1 208 // 7) RET 1
221 209
222 Instruction* i7 = MakeInstruction(BPF_RET + BPF_K, 1); 210 CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
223 Instruction* i6 = MakeInstruction(BPF_RET + BPF_K, 0); 211 CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
224 Instruction* i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); 212 CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
225 Instruction* i4 = MakeInstruction(BPF_RET + BPF_K, 42); 213 CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42);
226 Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); 214 CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
227 Instruction* i2 = MakeInstruction(BPF_RET + BPF_K, 42); 215 CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42);
228 Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); 216 CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
229 Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); 217 CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
230 218
231 RunTest(i0, HAS_MERGEABLE_TAILS); 219 RunTest(i0, HAS_MERGEABLE_TAILS);
232 } 220 }
233 221
234 void MakeInstruction(CodeGenUnittestHelper* codegen, 222 void MakeInstruction(CodeGenUnittestHelper* codegen,
235 Instruction* program, int) { 223 CodeGen::Node program,
224 int) {
236 // Nothing to do here 225 // Nothing to do here
237 } 226 }
238 227
239 void FindBranchTargets(CodeGenUnittestHelper* codegen, Instruction* prg, int) { 228 void FindBranchTargets(CodeGenUnittestHelper* codegen, CodeGen::Node prg, int) {
240 BranchTargets branch_targets; 229 BranchTargets branch_targets;
241 codegen->FindBranchTargets(*prg, &branch_targets); 230 codegen->FindBranchTargets(*prg, &branch_targets);
242 231
243 // Verifying the general properties that should be true for every 232 // Verifying the general properties that should be true for every
244 // well-formed BPF program. 233 // well-formed BPF program.
245 // Perform a depth-first traversal of the BPF program an verify that all 234 // Perform a depth-first traversal of the BPF program an verify that all
246 // targets of BPF_JMP instructions are represented in the "branch_targets". 235 // targets of BPF_JMP instructions are represented in the "branch_targets".
247 // At the same time, compute a set of both the branch targets and all the 236 // At the same time, compute a set of both the branch targets and all the
248 // instructions in the program. 237 // instructions in the program.
249 std::vector<Instruction*> stack; 238 std::vector<CodeGen::Node> stack;
250 std::set<Instruction*> all_instructions; 239 std::set<CodeGen::Node> all_instructions;
251 std::set<Instruction*> target_instructions; 240 std::set<CodeGen::Node> target_instructions;
252 BranchTargets::const_iterator end = branch_targets.end(); 241 BranchTargets::const_iterator end = branch_targets.end();
253 for (Instruction* insn = prg;;) { 242 for (CodeGen::Node insn = prg;;) {
254 all_instructions.insert(insn); 243 all_instructions.insert(insn);
255 if (BPF_CLASS(insn->code) == BPF_JMP) { 244 if (BPF_CLASS(insn->code) == BPF_JMP) {
256 target_instructions.insert(insn->jt_ptr); 245 target_instructions.insert(insn->jt_ptr);
257 ASSERT_TRUE(insn->jt_ptr != NULL); 246 ASSERT_TRUE(insn->jt_ptr != NULL);
258 ASSERT_TRUE(branch_targets.find(insn->jt_ptr) != end); 247 ASSERT_TRUE(branch_targets.find(insn->jt_ptr) != end);
259 if (BPF_OP(insn->code) != BPF_JA) { 248 if (BPF_OP(insn->code) != BPF_JA) {
260 target_instructions.insert(insn->jf_ptr); 249 target_instructions.insert(insn->jf_ptr);
261 ASSERT_TRUE(insn->jf_ptr != NULL); 250 ASSERT_TRUE(insn->jf_ptr != NULL);
262 ASSERT_TRUE(branch_targets.find(insn->jf_ptr) != end); 251 ASSERT_TRUE(branch_targets.find(insn->jf_ptr) != end);
263 stack.push_back(insn->jf_ptr); 252 stack.push_back(insn->jf_ptr);
(...skipping 25 matching lines...) Expand all
289 target_instructions.end(), 278 target_instructions.end(),
290 non_target_instructions.begin()); 279 non_target_instructions.begin());
291 for (Instructions::const_iterator iter = non_target_instructions.begin(); 280 for (Instructions::const_iterator iter = non_target_instructions.begin();
292 iter != non_target_instructions.end(); 281 iter != non_target_instructions.end();
293 ++iter) { 282 ++iter) {
294 ASSERT_TRUE(branch_targets.find(*iter) == end); 283 ASSERT_TRUE(branch_targets.find(*iter) == end);
295 } 284 }
296 } 285 }
297 286
298 void CutGraphIntoBasicBlocks(CodeGenUnittestHelper* codegen, 287 void CutGraphIntoBasicBlocks(CodeGenUnittestHelper* codegen,
299 Instruction* prg, 288 CodeGen::Node prg,
300 int) { 289 int) {
301 BranchTargets branch_targets; 290 BranchTargets branch_targets;
302 codegen->FindBranchTargets(*prg, &branch_targets); 291 codegen->FindBranchTargets(*prg, &branch_targets);
303 TargetsToBlocks all_blocks; 292 TargetsToBlocks all_blocks;
304 BasicBlock* first_block = 293 BasicBlock* first_block =
305 codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks); 294 codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
306 ASSERT_TRUE(first_block != NULL); 295 ASSERT_TRUE(first_block != NULL);
307 ASSERT_TRUE(first_block->instructions.size() > 0); 296 ASSERT_TRUE(first_block->instructions.size() > 0);
308 Instruction* first_insn = first_block->instructions[0]; 297 CodeGen::Node first_insn = first_block->instructions[0];
309 298
310 // Basic blocks are supposed to start with a branch target and end with 299 // Basic blocks are supposed to start with a branch target and end with
311 // either a jump or a return instruction. It can also end, if the next 300 // either a jump or a return instruction. It can also end, if the next
312 // instruction forms the beginning of a new basic block. There should be 301 // instruction forms the beginning of a new basic block. There should be
313 // no other jumps or return instructions in the middle of a basic block. 302 // no other jumps or return instructions in the middle of a basic block.
314 for (TargetsToBlocks::const_iterator bb_iter = all_blocks.begin(); 303 for (TargetsToBlocks::const_iterator bb_iter = all_blocks.begin();
315 bb_iter != all_blocks.end(); 304 bb_iter != all_blocks.end();
316 ++bb_iter) { 305 ++bb_iter) {
317 BasicBlock* bb = bb_iter->second; 306 BasicBlock* bb = bb_iter->second;
318 ASSERT_TRUE(bb != NULL); 307 ASSERT_TRUE(bb != NULL);
319 ASSERT_TRUE(bb->instructions.size() > 0); 308 ASSERT_TRUE(bb->instructions.size() > 0);
320 Instruction* insn = bb->instructions[0]; 309 CodeGen::Node insn = bb->instructions[0];
321 ASSERT_TRUE(insn == first_insn || 310 ASSERT_TRUE(insn == first_insn ||
322 branch_targets.find(insn) != branch_targets.end()); 311 branch_targets.find(insn) != branch_targets.end());
323 for (Instructions::const_iterator insn_iter = bb->instructions.begin();;) { 312 for (Instructions::const_iterator insn_iter = bb->instructions.begin();;) {
324 insn = *insn_iter; 313 insn = *insn_iter;
325 if (++insn_iter != bb->instructions.end()) { 314 if (++insn_iter != bb->instructions.end()) {
326 ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_JMP); 315 ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_JMP);
327 ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_RET); 316 ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_RET);
328 } else { 317 } else {
329 ASSERT_TRUE(BPF_CLASS(insn->code) == BPF_JMP || 318 ASSERT_TRUE(BPF_CLASS(insn->code) == BPF_JMP ||
330 BPF_CLASS(insn->code) == BPF_RET || 319 BPF_CLASS(insn->code) == BPF_RET ||
331 branch_targets.find(insn->next) != branch_targets.end()); 320 branch_targets.find(insn->next) != branch_targets.end());
332 break; 321 break;
333 } 322 }
334 ASSERT_TRUE(branch_targets.find(*insn_iter) == branch_targets.end()); 323 ASSERT_TRUE(branch_targets.find(*insn_iter) == branch_targets.end());
335 } 324 }
336 } 325 }
337 } 326 }
338 327
339 void MergeTails(CodeGenUnittestHelper* codegen, Instruction* prg, int flags) { 328 void MergeTails(CodeGenUnittestHelper* codegen, CodeGen::Node prg, int flags) {
340 BranchTargets branch_targets; 329 BranchTargets branch_targets;
341 codegen->FindBranchTargets(*prg, &branch_targets); 330 codegen->FindBranchTargets(*prg, &branch_targets);
342 TargetsToBlocks all_blocks; 331 TargetsToBlocks all_blocks;
343 BasicBlock* first_block = 332 BasicBlock* first_block =
344 codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks); 333 codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
345 334
346 // The shape of our graph and thus the function of our program should 335 // The shape of our graph and thus the function of our program should
347 // still be unchanged after we run MergeTails(). We verify this by 336 // still be unchanged after we run MergeTails(). We verify this by
348 // serializing the graph and verifying that it is still the same. 337 // serializing the graph and verifying that it is still the same.
349 // We also verify that at least some of the edges changed because of 338 // We also verify that at least some of the edges changed because of
(...skipping 23 matching lines...) Expand all
373 } 362 }
374 } 363 }
375 364
376 // Also serialize the addresses the basic blocks as we encounter them. 365 // Also serialize the addresses the basic blocks as we encounter them.
377 // This will change as basic blocks are coalesed by MergeTails(). 366 // This will change as basic blocks are coalesed by MergeTails().
378 edges[i].append(reinterpret_cast<char*>(&bb), sizeof(bb)); 367 edges[i].append(reinterpret_cast<char*>(&bb), sizeof(bb));
379 368
380 // Depth-first traversal of the graph. We only ever need to look at the 369 // Depth-first traversal of the graph. We only ever need to look at the
381 // very last instruction in the basic block, as that is the only one that 370 // very last instruction in the basic block, as that is the only one that
382 // can change code flow. 371 // can change code flow.
383 Instruction* insn = bb->instructions.back(); 372 CodeGen::Node insn = bb->instructions.back();
384 if (BPF_CLASS(insn->code) == BPF_JMP) { 373 if (BPF_CLASS(insn->code) == BPF_JMP) {
385 // For jump instructions, we need to remember the "false" branch while 374 // For jump instructions, we need to remember the "false" branch while
386 // traversing the "true" branch. This is not necessary for BPF_JA which 375 // traversing the "true" branch. This is not necessary for BPF_JA which
387 // only has a single branch. 376 // only has a single branch.
388 if (BPF_OP(insn->code) != BPF_JA) { 377 if (BPF_OP(insn->code) != BPF_JA) {
389 stack.push_back(all_blocks[insn->jf_ptr]); 378 stack.push_back(all_blocks[insn->jf_ptr]);
390 } 379 }
391 bb = all_blocks[insn->jt_ptr]; 380 bb = all_blocks[insn->jt_ptr];
392 } else if (BPF_CLASS(insn->code) == BPF_RET) { 381 } else if (BPF_CLASS(insn->code) == BPF_RET) {
393 // After a BPF_RET, see if we need to back track. 382 // After a BPF_RET, see if we need to back track.
(...skipping 15 matching lines...) Expand all
409 codegen->MergeTails(&all_blocks); 398 codegen->MergeTails(&all_blocks);
410 } 399 }
411 ASSERT_TRUE(graph[0] == graph[1]); 400 ASSERT_TRUE(graph[0] == graph[1]);
412 if (flags & HAS_MERGEABLE_TAILS) { 401 if (flags & HAS_MERGEABLE_TAILS) {
413 ASSERT_TRUE(edges[0] != edges[1]); 402 ASSERT_TRUE(edges[0] != edges[1]);
414 } else { 403 } else {
415 ASSERT_TRUE(edges[0] == edges[1]); 404 ASSERT_TRUE(edges[0] == edges[1]);
416 } 405 }
417 } 406 }
418 407
419 void CompileAndCompare(CodeGenUnittestHelper* codegen, Instruction* prg, int) { 408 void CompileAndCompare(CodeGenUnittestHelper* codegen, CodeGen::Node prg, int) {
420 // TopoSortBasicBlocks() has internal checks that cause it to fail, if it 409 // TopoSortBasicBlocks() has internal checks that cause it to fail, if it
421 // detects a problem. Typically, if anything goes wrong, this looks to the 410 // detects a problem. Typically, if anything goes wrong, this looks to the
422 // TopoSort algorithm as if there had been cycles in the input data. 411 // TopoSort algorithm as if there had been cycles in the input data.
423 // This provides a pretty good unittest. 412 // This provides a pretty good unittest.
424 // We hand-crafted the program returned by SampleProgram() to exercise 413 // We hand-crafted the program returned by SampleProgram() to exercise
425 // several of the more interesting code-paths. See comments in 414 // several of the more interesting code-paths. See comments in
426 // SampleProgram() for details. 415 // SampleProgram() for details.
427 // In addition to relying on the internal consistency checks in the compiler, 416 // In addition to relying on the internal consistency checks in the compiler,
428 // we also serialize the graph and the resulting BPF program and compare 417 // we also serialize the graph and the resulting BPF program and compare
429 // them. With the exception of BPF_JA instructions that might have been 418 // them. With the exception of BPF_JA instructions that might have been
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 CompileAndCompare, 493 CompileAndCompare,
505 }; 494 };
506 495
507 INSTANTIATE_TEST_CASE_P(CodeGen, 496 INSTANTIATE_TEST_CASE_P(CodeGen,
508 ProgramTest, 497 ProgramTest,
509 ::testing::ValuesIn(kProgramTestFuncs)); 498 ::testing::ValuesIn(kProgramTestFuncs));
510 499
511 } // namespace 500 } // namespace
512 501
513 } // namespace sandbox 502 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/codegen.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698