blob: 11f57216b89208e88f1a142a948a5baa26ca0fd6 [file] [log] [blame] [edit]
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package ifuzz
import (
"encoding/hex"
"math/rand"
"testing"
"github.com/google/syzkaller/pkg/ifuzz/iset"
"github.com/google/syzkaller/pkg/testutil"
)
var allArches = []string{ArchX86, ArchPowerPC}
func TestMode(t *testing.T) {
for _, arch := range allArches {
t.Run(arch, func(t *testing.T) {
testMode(t, arch)
})
}
}
func testMode(t *testing.T, arch string) {
all := make(map[iset.Insn]bool)
for mode := iset.Mode(0); mode < iset.ModeLast; mode++ {
for priv := 0; priv < 2; priv++ {
for exec := 0; exec < 2; exec++ {
insns := allInsns(arch, mode, priv != 0, exec != 0)
t.Logf("mode=%v priv=%v exec=%v: %v instructions", mode, priv, exec, len(insns))
for _, insn := range insns {
all[insn] = true
}
}
}
}
t.Logf("total: %v instructions", len(all))
}
func TestDecode(t *testing.T) {
for _, arch := range allArches {
t.Run(arch, func(t *testing.T) {
testDecode(t, arch)
})
}
}
func testDecode(t *testing.T, arch string) {
insnset := iset.Arches[arch]
xedEnabled := false
if _, err := insnset.DecodeExt(0, nil); err == nil {
xedEnabled = true
}
r := rand.New(testutil.RandSource(t))
for repeat := 0; repeat < 10; repeat++ {
for mode := iset.Mode(0); mode < iset.ModeLast; mode++ {
cfg := &iset.Config{
Mode: mode,
Priv: true,
Exec: true,
}
failed := false
for _, insn := range allInsns(arch, mode, true, true) {
name, _, pseudo, _ := insn.Info()
text0 := insn.Encode(cfg, r)
text := text0
repeat:
size, err := insnset.Decode(mode, text)
if err != nil {
t.Errorf("decoding %v %v failed (mode=%v): %v", name, hex.EncodeToString(text), mode, err)
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
failed = true
continue
}
if xedEnabled {
xedSize, xedErr := insnset.DecodeExt(mode, text)
if xedErr != nil {
t.Errorf("xed decoding %v %v failed (mode=%v): %v", name, hex.EncodeToString(text), mode, xedErr)
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
failed = true
continue
}
if size != xedSize {
t.Errorf("decoding %v %v failed (mode=%v): decoded %v/%v, xed decoded %v/%v",
name, hex.EncodeToString(text), mode, size, xedSize, size, len(text))
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
failed = true
continue
}
}
if pseudo && size >= 0 && size < len(text) {
text = text[size:]
goto repeat
}
if size != len(text) {
t.Errorf("decoding %v %v failed (mode=%v): decoded %v/%v",
name, hex.EncodeToString(text), mode, size, len(text))
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
failed = true
}
}
if failed {
return
}
}
}
}
func allInsns(arch string, mode iset.Mode, priv, exec bool) []iset.Insn {
insnset := iset.Arches[arch]
insns := insnset.GetInsns(mode, iset.TypeUser)
if priv {
insns = append(insns, insnset.GetInsns(mode, iset.TypePriv)...)
if exec {
insns = append(insns, insnset.GetInsns(mode, iset.TypeExec)...)
}
}
return insns
}