OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / bpf / instructions_test.go
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package bpf
6
7 import (
8         "fmt"
9         "io/ioutil"
10         "reflect"
11         "strconv"
12         "strings"
13         "testing"
14 )
15
16 // This is a direct translation of the program in
17 // testdata/all_instructions.txt.
18 var allInstructions = []Instruction{
19         LoadConstant{Dst: RegA, Val: 42},
20         LoadConstant{Dst: RegX, Val: 42},
21
22         LoadScratch{Dst: RegA, N: 3},
23         LoadScratch{Dst: RegX, N: 3},
24
25         LoadAbsolute{Off: 42, Size: 1},
26         LoadAbsolute{Off: 42, Size: 2},
27         LoadAbsolute{Off: 42, Size: 4},
28
29         LoadIndirect{Off: 42, Size: 1},
30         LoadIndirect{Off: 42, Size: 2},
31         LoadIndirect{Off: 42, Size: 4},
32
33         LoadMemShift{Off: 42},
34
35         LoadExtension{Num: ExtLen},
36         LoadExtension{Num: ExtProto},
37         LoadExtension{Num: ExtType},
38         LoadExtension{Num: ExtRand},
39
40         StoreScratch{Src: RegA, N: 3},
41         StoreScratch{Src: RegX, N: 3},
42
43         ALUOpConstant{Op: ALUOpAdd, Val: 42},
44         ALUOpConstant{Op: ALUOpSub, Val: 42},
45         ALUOpConstant{Op: ALUOpMul, Val: 42},
46         ALUOpConstant{Op: ALUOpDiv, Val: 42},
47         ALUOpConstant{Op: ALUOpOr, Val: 42},
48         ALUOpConstant{Op: ALUOpAnd, Val: 42},
49         ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
50         ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
51         ALUOpConstant{Op: ALUOpMod, Val: 42},
52         ALUOpConstant{Op: ALUOpXor, Val: 42},
53
54         ALUOpX{Op: ALUOpAdd},
55         ALUOpX{Op: ALUOpSub},
56         ALUOpX{Op: ALUOpMul},
57         ALUOpX{Op: ALUOpDiv},
58         ALUOpX{Op: ALUOpOr},
59         ALUOpX{Op: ALUOpAnd},
60         ALUOpX{Op: ALUOpShiftLeft},
61         ALUOpX{Op: ALUOpShiftRight},
62         ALUOpX{Op: ALUOpMod},
63         ALUOpX{Op: ALUOpXor},
64
65         NegateA{},
66
67         Jump{Skip: 10},
68         JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
69         JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
70         JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
71         JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
72         JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
73         JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
74         JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
75
76         TAX{},
77         TXA{},
78
79         RetA{},
80         RetConstant{Val: 42},
81 }
82 var allInstructionsExpected = "testdata/all_instructions.bpf"
83
84 // Check that we produce the same output as the canonical bpf_asm
85 // linux kernel tool.
86 func TestInterop(t *testing.T) {
87         out, err := Assemble(allInstructions)
88         if err != nil {
89                 t.Fatalf("assembly of allInstructions program failed: %s", err)
90         }
91         t.Logf("Assembled program is %d instructions long", len(out))
92
93         bs, err := ioutil.ReadFile(allInstructionsExpected)
94         if err != nil {
95                 t.Fatalf("reading %s: %s", allInstructionsExpected, err)
96         }
97         // First statement is the number of statements, last statement is
98         // empty. We just ignore both and rely on slice length.
99         stmts := strings.Split(string(bs), ",")
100         if len(stmts)-2 != len(out) {
101                 t.Fatalf("test program lengths don't match: %s has %d, Go implementation has %d", allInstructionsExpected, len(stmts)-2, len(allInstructions))
102         }
103
104         for i, stmt := range stmts[1 : len(stmts)-2] {
105                 nums := strings.Split(stmt, " ")
106                 if len(nums) != 4 {
107                         t.Fatalf("malformed instruction %d in %s: %s", i+1, allInstructionsExpected, stmt)
108                 }
109
110                 actual := out[i]
111
112                 op, err := strconv.ParseUint(nums[0], 10, 16)
113                 if err != nil {
114                         t.Fatalf("malformed opcode %s in instruction %d of %s", nums[0], i+1, allInstructionsExpected)
115                 }
116                 if actual.Op != uint16(op) {
117                         t.Errorf("opcode mismatch on instruction %d (%#v): got 0x%02x, want 0x%02x", i+1, allInstructions[i], actual.Op, op)
118                 }
119
120                 jt, err := strconv.ParseUint(nums[1], 10, 8)
121                 if err != nil {
122                         t.Fatalf("malformed jt offset %s in instruction %d of %s", nums[1], i+1, allInstructionsExpected)
123                 }
124                 if actual.Jt != uint8(jt) {
125                         t.Errorf("jt mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jt, jt)
126                 }
127
128                 jf, err := strconv.ParseUint(nums[2], 10, 8)
129                 if err != nil {
130                         t.Fatalf("malformed jf offset %s in instruction %d of %s", nums[2], i+1, allInstructionsExpected)
131                 }
132                 if actual.Jf != uint8(jf) {
133                         t.Errorf("jf mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jf, jf)
134                 }
135
136                 k, err := strconv.ParseUint(nums[3], 10, 32)
137                 if err != nil {
138                         t.Fatalf("malformed constant %s in instruction %d of %s", nums[3], i+1, allInstructionsExpected)
139                 }
140                 if actual.K != uint32(k) {
141                         t.Errorf("constant mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.K, k)
142                 }
143         }
144 }
145
146 // Check that assembly and disassembly match each other.
147 func TestAsmDisasm(t *testing.T) {
148         prog1, err := Assemble(allInstructions)
149         if err != nil {
150                 t.Fatalf("assembly of allInstructions program failed: %s", err)
151         }
152         t.Logf("Assembled program is %d instructions long", len(prog1))
153
154         got, allDecoded := Disassemble(prog1)
155         if !allDecoded {
156                 t.Errorf("Disassemble(Assemble(allInstructions)) produced unrecognized instructions:")
157                 for i, inst := range got {
158                         if r, ok := inst.(RawInstruction); ok {
159                                 t.Logf("  insn %d, %#v --> %#v", i+1, allInstructions[i], r)
160                         }
161                 }
162         }
163
164         if len(allInstructions) != len(got) {
165                 t.Fatalf("disassembly changed program size: %d insns before, %d insns after", len(allInstructions), len(got))
166         }
167         if !reflect.DeepEqual(allInstructions, got) {
168                 t.Errorf("program mutated by disassembly:")
169                 for i := range got {
170                         if !reflect.DeepEqual(allInstructions[i], got[i]) {
171                                 t.Logf("  insn %d, s: %#v, p1: %#v, got: %#v", i+1, allInstructions[i], prog1[i], got[i])
172                         }
173                 }
174         }
175 }
176
177 type InvalidInstruction struct{}
178
179 func (a InvalidInstruction) Assemble() (RawInstruction, error) {
180         return RawInstruction{}, fmt.Errorf("Invalid Instruction")
181 }
182
183 func (a InvalidInstruction) String() string {
184         return fmt.Sprintf("unknown instruction: %#v", a)
185 }
186
187 func TestString(t *testing.T) {
188         testCases := []struct {
189                 instruction Instruction
190                 assembler   string
191         }{
192                 {
193                         instruction: LoadConstant{Dst: RegA, Val: 42},
194                         assembler:   "ld #42",
195                 },
196                 {
197                         instruction: LoadConstant{Dst: RegX, Val: 42},
198                         assembler:   "ldx #42",
199                 },
200                 {
201                         instruction: LoadConstant{Dst: 0xffff, Val: 42},
202                         assembler:   "unknown instruction: bpf.LoadConstant{Dst:0xffff, Val:0x2a}",
203                 },
204                 {
205                         instruction: LoadScratch{Dst: RegA, N: 3},
206                         assembler:   "ld M[3]",
207                 },
208                 {
209                         instruction: LoadScratch{Dst: RegX, N: 3},
210                         assembler:   "ldx M[3]",
211                 },
212                 {
213                         instruction: LoadScratch{Dst: 0xffff, N: 3},
214                         assembler:   "unknown instruction: bpf.LoadScratch{Dst:0xffff, N:3}",
215                 },
216                 {
217                         instruction: LoadAbsolute{Off: 42, Size: 1},
218                         assembler:   "ldb [42]",
219                 },
220                 {
221                         instruction: LoadAbsolute{Off: 42, Size: 2},
222                         assembler:   "ldh [42]",
223                 },
224                 {
225                         instruction: LoadAbsolute{Off: 42, Size: 4},
226                         assembler:   "ld [42]",
227                 },
228                 {
229                         instruction: LoadAbsolute{Off: 42, Size: -1},
230                         assembler:   "unknown instruction: bpf.LoadAbsolute{Off:0x2a, Size:-1}",
231                 },
232                 {
233                         instruction: LoadIndirect{Off: 42, Size: 1},
234                         assembler:   "ldb [x + 42]",
235                 },
236                 {
237                         instruction: LoadIndirect{Off: 42, Size: 2},
238                         assembler:   "ldh [x + 42]",
239                 },
240                 {
241                         instruction: LoadIndirect{Off: 42, Size: 4},
242                         assembler:   "ld [x + 42]",
243                 },
244                 {
245                         instruction: LoadIndirect{Off: 42, Size: -1},
246                         assembler:   "unknown instruction: bpf.LoadIndirect{Off:0x2a, Size:-1}",
247                 },
248                 {
249                         instruction: LoadMemShift{Off: 42},
250                         assembler:   "ldx 4*([42]&0xf)",
251                 },
252                 {
253                         instruction: LoadExtension{Num: ExtLen},
254                         assembler:   "ld #len",
255                 },
256                 {
257                         instruction: LoadExtension{Num: ExtProto},
258                         assembler:   "ld #proto",
259                 },
260                 {
261                         instruction: LoadExtension{Num: ExtType},
262                         assembler:   "ld #type",
263                 },
264                 {
265                         instruction: LoadExtension{Num: ExtPayloadOffset},
266                         assembler:   "ld #poff",
267                 },
268                 {
269                         instruction: LoadExtension{Num: ExtInterfaceIndex},
270                         assembler:   "ld #ifidx",
271                 },
272                 {
273                         instruction: LoadExtension{Num: ExtNetlinkAttr},
274                         assembler:   "ld #nla",
275                 },
276                 {
277                         instruction: LoadExtension{Num: ExtNetlinkAttrNested},
278                         assembler:   "ld #nlan",
279                 },
280                 {
281                         instruction: LoadExtension{Num: ExtMark},
282                         assembler:   "ld #mark",
283                 },
284                 {
285                         instruction: LoadExtension{Num: ExtQueue},
286                         assembler:   "ld #queue",
287                 },
288                 {
289                         instruction: LoadExtension{Num: ExtLinkLayerType},
290                         assembler:   "ld #hatype",
291                 },
292                 {
293                         instruction: LoadExtension{Num: ExtRXHash},
294                         assembler:   "ld #rxhash",
295                 },
296                 {
297                         instruction: LoadExtension{Num: ExtCPUID},
298                         assembler:   "ld #cpu",
299                 },
300                 {
301                         instruction: LoadExtension{Num: ExtVLANTag},
302                         assembler:   "ld #vlan_tci",
303                 },
304                 {
305                         instruction: LoadExtension{Num: ExtVLANTagPresent},
306                         assembler:   "ld #vlan_avail",
307                 },
308                 {
309                         instruction: LoadExtension{Num: ExtVLANProto},
310                         assembler:   "ld #vlan_tpid",
311                 },
312                 {
313                         instruction: LoadExtension{Num: ExtRand},
314                         assembler:   "ld #rand",
315                 },
316                 {
317                         instruction: LoadAbsolute{Off: 0xfffff038, Size: 4},
318                         assembler:   "ld #rand",
319                 },
320                 {
321                         instruction: LoadExtension{Num: 0xfff},
322                         assembler:   "unknown instruction: bpf.LoadExtension{Num:4095}",
323                 },
324                 {
325                         instruction: StoreScratch{Src: RegA, N: 3},
326                         assembler:   "st M[3]",
327                 },
328                 {
329                         instruction: StoreScratch{Src: RegX, N: 3},
330                         assembler:   "stx M[3]",
331                 },
332                 {
333                         instruction: StoreScratch{Src: 0xffff, N: 3},
334                         assembler:   "unknown instruction: bpf.StoreScratch{Src:0xffff, N:3}",
335                 },
336                 {
337                         instruction: ALUOpConstant{Op: ALUOpAdd, Val: 42},
338                         assembler:   "add #42",
339                 },
340                 {
341                         instruction: ALUOpConstant{Op: ALUOpSub, Val: 42},
342                         assembler:   "sub #42",
343                 },
344                 {
345                         instruction: ALUOpConstant{Op: ALUOpMul, Val: 42},
346                         assembler:   "mul #42",
347                 },
348                 {
349                         instruction: ALUOpConstant{Op: ALUOpDiv, Val: 42},
350                         assembler:   "div #42",
351                 },
352                 {
353                         instruction: ALUOpConstant{Op: ALUOpOr, Val: 42},
354                         assembler:   "or #42",
355                 },
356                 {
357                         instruction: ALUOpConstant{Op: ALUOpAnd, Val: 42},
358                         assembler:   "and #42",
359                 },
360                 {
361                         instruction: ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
362                         assembler:   "lsh #42",
363                 },
364                 {
365                         instruction: ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
366                         assembler:   "rsh #42",
367                 },
368                 {
369                         instruction: ALUOpConstant{Op: ALUOpMod, Val: 42},
370                         assembler:   "mod #42",
371                 },
372                 {
373                         instruction: ALUOpConstant{Op: ALUOpXor, Val: 42},
374                         assembler:   "xor #42",
375                 },
376                 {
377                         instruction: ALUOpConstant{Op: 0xffff, Val: 42},
378                         assembler:   "unknown instruction: bpf.ALUOpConstant{Op:0xffff, Val:0x2a}",
379                 },
380                 {
381                         instruction: ALUOpX{Op: ALUOpAdd},
382                         assembler:   "add x",
383                 },
384                 {
385                         instruction: ALUOpX{Op: ALUOpSub},
386                         assembler:   "sub x",
387                 },
388                 {
389                         instruction: ALUOpX{Op: ALUOpMul},
390                         assembler:   "mul x",
391                 },
392                 {
393                         instruction: ALUOpX{Op: ALUOpDiv},
394                         assembler:   "div x",
395                 },
396                 {
397                         instruction: ALUOpX{Op: ALUOpOr},
398                         assembler:   "or x",
399                 },
400                 {
401                         instruction: ALUOpX{Op: ALUOpAnd},
402                         assembler:   "and x",
403                 },
404                 {
405                         instruction: ALUOpX{Op: ALUOpShiftLeft},
406                         assembler:   "lsh x",
407                 },
408                 {
409                         instruction: ALUOpX{Op: ALUOpShiftRight},
410                         assembler:   "rsh x",
411                 },
412                 {
413                         instruction: ALUOpX{Op: ALUOpMod},
414                         assembler:   "mod x",
415                 },
416                 {
417                         instruction: ALUOpX{Op: ALUOpXor},
418                         assembler:   "xor x",
419                 },
420                 {
421                         instruction: ALUOpX{Op: 0xffff},
422                         assembler:   "unknown instruction: bpf.ALUOpX{Op:0xffff}",
423                 },
424                 {
425                         instruction: NegateA{},
426                         assembler:   "neg",
427                 },
428                 {
429                         instruction: Jump{Skip: 10},
430                         assembler:   "ja 10",
431                 },
432                 {
433                         instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
434                         assembler:   "jeq #42,8,9",
435                 },
436                 {
437                         instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8},
438                         assembler:   "jeq #42,8",
439                 },
440                 {
441                         instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipFalse: 8},
442                         assembler:   "jneq #42,8",
443                 },
444                 {
445                         instruction: JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
446                         assembler:   "jneq #42,8",
447                 },
448                 {
449                         instruction: JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
450                         assembler:   "jlt #42,7",
451                 },
452                 {
453                         instruction: JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
454                         assembler:   "jle #42,6",
455                 },
456                 {
457                         instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
458                         assembler:   "jgt #42,4,5",
459                 },
460                 {
461                         instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4},
462                         assembler:   "jgt #42,4",
463                 },
464                 {
465                         instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
466                         assembler:   "jge #42,3,4",
467                 },
468                 {
469                         instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3},
470                         assembler:   "jge #42,3",
471                 },
472                 {
473                         instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
474                         assembler:   "jset #42,2,3",
475                 },
476                 {
477                         instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2},
478                         assembler:   "jset #42,2",
479                 },
480                 {
481                         instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
482                         assembler:   "jset #42,3,2",
483                 },
484                 {
485                         instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2},
486                         assembler:   "jset #42,0,2",
487                 },
488                 {
489                         instruction: JumpIf{Cond: 0xffff, Val: 42, SkipTrue: 1, SkipFalse: 2},
490                         assembler:   "unknown instruction: bpf.JumpIf{Cond:0xffff, Val:0x2a, SkipTrue:0x1, SkipFalse:0x2}",
491                 },
492                 {
493                         instruction: TAX{},
494                         assembler:   "tax",
495                 },
496                 {
497                         instruction: TXA{},
498                         assembler:   "txa",
499                 },
500                 {
501                         instruction: RetA{},
502                         assembler:   "ret a",
503                 },
504                 {
505                         instruction: RetConstant{Val: 42},
506                         assembler:   "ret #42",
507                 },
508                 // Invalid instruction
509                 {
510                         instruction: InvalidInstruction{},
511                         assembler:   "unknown instruction: bpf.InvalidInstruction{}",
512                 },
513         }
514
515         for _, testCase := range testCases {
516                 if input, ok := testCase.instruction.(fmt.Stringer); ok {
517                         got := input.String()
518                         if got != testCase.assembler {
519                                 t.Errorf("String did not return expected assembler notation, expected: %s, got: %s", testCase.assembler, got)
520                         }
521                 } else {
522                         t.Errorf("Instruction %#v is not a fmt.Stringer", testCase.instruction)
523                 }
524         }
525 }