| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |