Extended Berkeley Packet Filter (eBPF) assembler and virtual machine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

153 lines
3.2 KiB

package ebpf
import (
"encoding/hex"
"reflect"
"testing"
)
func TestDisassemble(t *testing.T) {
tests := []struct {
Name string
Data []byte
Want []string
}{
{
Name: "alu",
Data: mustUnhex("040100000200000004090000ffffffff0c210000000000001c210000000000002c210000000000003c210000000000004c210000000000005c210000000000006c210000000000007c2100000000000084010000000000009c21000000000000ac21000000000000bc21000000000000cc21000000000000d401000010000000d401000020000000d401000040000000dc01000010000000dc01000020000000dc01000040000000"),
Want: []string{
"add32 R1, 0x2",
"add32 R9, 0xffffffff",
"add32 R1, R2",
"sub32 R1, R2",
"mul32 R1, R2",
"div32 R1, R2",
"or32 R1, R2",
"and32 R1, R2",
"lsh32 R1, R2",
"rsh32 R1, R2",
"neg32 R1",
"mod32 R1, R2",
"xor32 R1, R2",
"mov32 R1, R2",
"arsh32 R1, R2",
"le16 R1",
"le32 R1",
"le64 R1",
"be16 R1",
"be32 R1",
"be64 R1",
},
},
/*
{
Name: "alu-bit",
Want: []string{
"mov32 R0, 0x0",
"mov32 R1, 0x1",
"mov32 R2, 0x2",
"mov32 R3, 0x3",
"mov32 R4, 0x4",
"mov32 R5, 0x5",
"mov32 R6, 0x6",
"mov32 R7, 0x7",
"mov32 R8, 0x8",
"or32 R0, R5",
"or32 R0, 0xa0",
"and32 R0, 0xa3",
"mov32 R9, 0x91",
"and32 R0, R9",
"lsh32 R0, 22",
"lsh32 R0, R8",
"rsh32 R0, 19",
"rsh32 R0, R7",
"xor32 R0, 3",
"xor32 R0, R2",
"exit",
},
},
*/
{
Name: "ja",
Data: mustUnhex("b7000000010000000500010000000000b7000000020000009500000000000000"),
Want: []string{
"mov R0, 0x1",
"ja +1",
"mov R0, 0x2",
"exit",
},
},
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
ins, err := Disassemble(test.Data)
if err != nil {
t.Fatal(err)
}
if l := len(ins); l != len(test.Want) {
t.Errorf("expected %d instructions, got %d", len(test.Want), l)
}
for i, a := range ins {
if i < len(test.Want) {
if v := a.String(); v != test.Want[i] {
t.Errorf("unexpected assembly in line %d:\ntest: %q\nwant: %q", i+1, test.Want[i], v)
}
} else {
t.Errorf("unexpected %q", a)
}
}
})
}
}
func mustUnhex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
type testInstruction struct {
Test Instruction
WantRaw RawInstruction
WantError string
WantString string
}
func (test testInstruction) Run(t *testing.T) {
t.Helper()
r, err := test.Test.Assemble()
if err != nil {
if test.WantError == "" {
t.Fatal(err)
return
} else if v := err.Error(); v != test.WantError {
t.Errorf("unexpected error:\nwant: %v\ntest: %v", test.WantError, err)
}
t.Log(err)
return
}
if !reflect.DeepEqual(r, test.WantRaw) {
t.Errorf("unexpected result:\nwant: %#+v\ntest: %#+v", test.WantRaw, r)
}
if v := test.Test.String(); v != test.WantString {
t.Errorf("unexpected result:\nwant: %q\ntest: %q", test.WantString, v)
} else {
t.Log(v)
}
}
type testInstructionSuite []testInstruction
func (suite testInstructionSuite) Run(t *testing.T) {
t.Helper()
for _, test := range suite {
t.Run(test.WantString, func(it *testing.T) {
test.Run(it)
})
}
}