| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package bpf_test |
| |
| import ( |
| "testing" |
| |
| "golang.org/x/net/bpf" |
| ) |
| |
| func TestVMStoreScratchInvalidScratchRegisterTooSmall(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: -1, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid scratch slot -1" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMStoreScratchInvalidScratchRegisterTooLarge(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: 16, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid scratch slot 16" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMStoreScratchUnknownSourceRegister(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.StoreScratch{ |
| Src: 100, |
| N: 0, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid source register 100" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMLoadScratchInvalidScratchRegisterTooSmall(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.LoadScratch{ |
| Dst: bpf.RegX, |
| N: -1, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid scratch slot -1" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMLoadScratchInvalidScratchRegisterTooLarge(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.LoadScratch{ |
| Dst: bpf.RegX, |
| N: 16, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid scratch slot 16" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMLoadScratchUnknownDestinationRegister(t *testing.T) { |
| _, _, err := testVM(t, []bpf.Instruction{ |
| bpf.LoadScratch{ |
| Dst: 100, |
| N: 0, |
| }, |
| bpf.RetA{}, |
| }) |
| if errStr(err) != "assembling instruction 1: invalid target register 100" { |
| t.Fatalf("unexpected error: %v", err) |
| } |
| } |
| |
| func TestVMStoreScratchLoadScratchOneValue(t *testing.T) { |
| vm, done, err := testVM(t, []bpf.Instruction{ |
| // Load byte 255 |
| bpf.LoadAbsolute{ |
| Off: 8, |
| Size: 1, |
| }, |
| // Copy to X and store in scratch[0] |
| bpf.TAX{}, |
| bpf.StoreScratch{ |
| Src: bpf.RegX, |
| N: 0, |
| }, |
| // Load byte 1 |
| bpf.LoadAbsolute{ |
| Off: 9, |
| Size: 1, |
| }, |
| // Overwrite 1 with 255 from scratch[0] |
| bpf.LoadScratch{ |
| Dst: bpf.RegA, |
| N: 0, |
| }, |
| // Return 255 |
| bpf.RetA{}, |
| }) |
| if err != nil { |
| t.Fatalf("failed to load BPF program: %v", err) |
| } |
| defer done() |
| |
| out, err := vm.Run([]byte{ |
| 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0xff, 0xff, 0xff, |
| 255, 1, 2, |
| }) |
| if err != nil { |
| t.Fatalf("unexpected error while running program: %v", err) |
| } |
| if want, got := 3, out; want != got { |
| t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", |
| want, got) |
| } |
| } |
| |
| func TestVMStoreScratchLoadScratchMultipleValues(t *testing.T) { |
| vm, done, err := testVM(t, []bpf.Instruction{ |
| // Load byte 10 |
| bpf.LoadAbsolute{ |
| Off: 8, |
| Size: 1, |
| }, |
| // Store in scratch[0] |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: 0, |
| }, |
| // Load byte 20 |
| bpf.LoadAbsolute{ |
| Off: 9, |
| Size: 1, |
| }, |
| // Store in scratch[1] |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: 1, |
| }, |
| // Load byte 30 |
| bpf.LoadAbsolute{ |
| Off: 10, |
| Size: 1, |
| }, |
| // Store in scratch[2] |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: 2, |
| }, |
| // Load byte 1 |
| bpf.LoadAbsolute{ |
| Off: 11, |
| Size: 1, |
| }, |
| // Store in scratch[3] |
| bpf.StoreScratch{ |
| Src: bpf.RegA, |
| N: 3, |
| }, |
| // Load in byte 10 to X |
| bpf.LoadScratch{ |
| Dst: bpf.RegX, |
| N: 0, |
| }, |
| // Copy X -> A |
| bpf.TXA{}, |
| // Verify value is 10 |
| bpf.JumpIf{ |
| Cond: bpf.JumpEqual, |
| Val: 10, |
| SkipTrue: 1, |
| }, |
| // Fail test if incorrect |
| bpf.RetConstant{ |
| Val: 0, |
| }, |
| // Load in byte 20 to A |
| bpf.LoadScratch{ |
| Dst: bpf.RegA, |
| N: 1, |
| }, |
| // Verify value is 20 |
| bpf.JumpIf{ |
| Cond: bpf.JumpEqual, |
| Val: 20, |
| SkipTrue: 1, |
| }, |
| // Fail test if incorrect |
| bpf.RetConstant{ |
| Val: 0, |
| }, |
| // Load in byte 30 to A |
| bpf.LoadScratch{ |
| Dst: bpf.RegA, |
| N: 2, |
| }, |
| // Verify value is 30 |
| bpf.JumpIf{ |
| Cond: bpf.JumpEqual, |
| Val: 30, |
| SkipTrue: 1, |
| }, |
| // Fail test if incorrect |
| bpf.RetConstant{ |
| Val: 0, |
| }, |
| // Return first two bytes on success |
| bpf.RetConstant{ |
| Val: 10, |
| }, |
| }) |
| if err != nil { |
| t.Fatalf("failed to load BPF program: %v", err) |
| } |
| defer done() |
| |
| out, err := vm.Run([]byte{ |
| 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0xff, 0xff, 0xff, |
| 10, 20, 30, 1, |
| }) |
| if err != nil { |
| t.Fatalf("unexpected error while running program: %v", err) |
| } |
| if want, got := 2, out; want != got { |
| t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", |
| want, got) |
| } |
| } |