aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ifuzz
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@linux.ibm.com>2021-07-12 14:48:15 +1000
committerDmitry Vyukov <dvyukov@google.com>2021-07-19 11:29:36 +0200
commit8cad1b789fd41ebbae53b5ffd4aefb21b738fdab (patch)
tree37f62e666082b0e5d87010b80ec2371106225c29 /pkg/ifuzz
parentad7f042a5c22180cc9c17af50e7c1475ad69d5cc (diff)
pkg/ifuzz/powerpc: preload registers with interesting numbers
GenerateInt() generates sort of random numbers for instruction fuzzer with focus on corner cases, let's use it for POWERPC too. Since we want memory access instruction to try these addresses, we preload generated values in GPRs used by just generated instruction. This in turn requires Insn::Encode() access for the instruction map to encode load instructions so this moves ld64() from the generator to insnSetMap and adds Insn::insnMap. This adds enc() to encode just the instruction without any randomization. This does not add additional instructions if cfg.MemRegions is empty so the ifuzz_test.go test still passes. Since EncodeParam() is not used by anything but Encode(), this open codes it. Signed-off-by: Alexey Kardashevskiy <aik@linux.ibm.com>
Diffstat (limited to 'pkg/ifuzz')
-rw-r--r--pkg/ifuzz/powerpc/powerpc.go82
-rw-r--r--pkg/ifuzz/powerpc/pseudo.go42
2 files changed, 69 insertions, 55 deletions
diff --git a/pkg/ifuzz/powerpc/powerpc.go b/pkg/ifuzz/powerpc/powerpc.go
index 56fb0a5b2..d87f073b6 100644
--- a/pkg/ifuzz/powerpc/powerpc.go
+++ b/pkg/ifuzz/powerpc/powerpc.go
@@ -35,6 +35,7 @@ type Insn struct {
Opcode uint32
Mask uint32
+ insnMap *insnSetMap
generator func(cfg *iset.Config, r *rand.Rand) []byte
}
@@ -72,27 +73,23 @@ func encodeBits(n uint, f InsnBits) uint32 {
return uint32((n & mask) << (31 - (f.Start + f.Length - 1)))
}
-func (insn *Insn) EncodeParam(v map[string]uint, r *rand.Rand) []byte {
- insn32 := insn.Opcode
- for reg, bits := range insn.Fields {
- if val, ok := v[reg]; ok {
- insn32 |= encodeBits(val, bits)
- } else if r != nil {
- insn32 |= encodeBits(uint(r.Intn(1<<16)), bits)
- }
- }
-
- ret := make([]byte, 4)
- binary.LittleEndian.PutUint32(ret, insn32)
- return ret
-}
-
func (insn Insn) Encode(cfg *iset.Config, r *rand.Rand) []byte {
if insn.Pseudo {
return insn.generator(cfg, r)
}
- return insn.EncodeParam(nil, r)
+ ret := make([]byte, 0)
+ insn32 := insn.Opcode
+ for reg, bits := range insn.Fields {
+ field := uint(r.Intn(1 << 16))
+ insn32 |= encodeBits(field, bits)
+ if len(cfg.MemRegions) != 0 && (reg == "RA" || reg == "RB") {
+ val := iset.GenerateInt(cfg, r, 8)
+ ret = append(ret, insn.insnMap.ld64(field, val)...)
+ }
+ }
+
+ return append(ret, uint32toBytes(insn32)...)
}
func Register(insns []*Insn) {
@@ -105,6 +102,7 @@ func Register(insns []*Insn) {
}
for _, insn := range insnset.Insns {
insnset.insnMap[insn.Name] = insn
+ insn.insnMap = &insnset.insnMap
}
insnset.initPseudo()
for _, insn := range insnset.Insns {
@@ -123,3 +121,55 @@ func (insn Insn) mode() iset.Mode {
}
return (1 << iset.ModeLong64) | (1 << iset.ModeProt32)
}
+
+func uint32toBytes(v uint32) []byte {
+ ret := make([]byte, 4)
+ binary.LittleEndian.PutUint32(ret, v)
+
+ return ret
+}
+
+func (insn *Insn) enc(v map[string]uint) []byte {
+ insn32 := insn.Opcode
+ for reg, bits := range insn.Fields {
+ if val, ok := v[reg]; ok {
+ insn32 |= encodeBits(val, bits)
+ }
+ }
+ return uint32toBytes(insn32)
+}
+
+func (imap insnSetMap) ld64(reg uint, v uint64) []byte {
+ ret := make([]byte, 0)
+
+ // This is a widely used macro to load immediate on ppc64
+ // #define LOAD64(rn,name)
+ // addis rn,0,name##@highest \ lis rn,name##@highest
+ // ori rn,rn,name##@higher
+ // rldicr rn,rn,32,31
+ // oris rn,rn,name##@h
+ // ori rn,rn,name##@l
+ ret = append(ret, imap["addis"].enc(map[string]uint{
+ "RT": reg,
+ "RA": 0, // In "addis", '0' means 0, not GPR0 .
+ "SI": uint((v >> 48) & 0xffff)})...)
+ ret = append(ret, imap["ori"].enc(map[string]uint{
+ "RA": reg,
+ "RS": reg,
+ "UI": uint((v >> 32) & 0xffff)})...)
+ ret = append(ret, imap["rldicr"].enc(map[string]uint{
+ "RA": reg,
+ "RS": reg,
+ "SH": 32,
+ "ME": 31})...)
+ ret = append(ret, imap["oris"].enc(map[string]uint{
+ "RA": reg,
+ "RS": reg,
+ "UI": uint((v >> 16) & 0xffff)})...)
+ ret = append(ret, imap["ori"].enc(map[string]uint{
+ "RA": reg,
+ "RS": reg,
+ "UI": uint(v & 0xffff)})...)
+
+ return ret
+}
diff --git a/pkg/ifuzz/powerpc/pseudo.go b/pkg/ifuzz/powerpc/pseudo.go
index b1231092b..7529a16fc 100644
--- a/pkg/ifuzz/powerpc/pseudo.go
+++ b/pkg/ifuzz/powerpc/pseudo.go
@@ -62,48 +62,12 @@ func (gen *generator) byte(v []byte) {
gen.text = append(gen.text, v...)
}
-func (gen *generator) ld64(reg uint, v uint64) {
- // This is a widely used macro to load immediate on ppc64
- // #define LOAD64(rn,name)
- // addis rn,0,name##@highest \ lis rn,name##@highest
- // ori rn,rn,name##@higher
- // rldicr rn,rn,32,31
- // oris rn,rn,name##@h
- // ori rn,rn,name##@l
- gen.byte(gen.imap["addis"].EncodeParam(map[string]uint{
- "RT": reg,
- "RA": 0, // In "addis", '0' means 0, not GPR0 .
- "SI": uint((v >> 48) & 0xffff)},
- nil))
- gen.byte(gen.imap["ori"].EncodeParam(map[string]uint{
- "RA": reg,
- "RS": reg,
- "UI": uint((v >> 32) & 0xffff)},
- nil))
- gen.byte(gen.imap["rldicr"].EncodeParam(map[string]uint{
- "RA": reg,
- "RS": reg,
- "SH": 32,
- "ME": 31},
- nil))
- gen.byte(gen.imap["oris"].EncodeParam(map[string]uint{
- "RA": reg,
- "RS": reg,
- "UI": uint((v >> 16) & 0xffff)},
- nil))
- gen.byte(gen.imap["ori"].EncodeParam(map[string]uint{
- "RA": reg,
- "RS": reg,
- "UI": uint(v & 0xffff)},
- nil))
-}
-
func (gen *generator) sc(lev uint) {
n := gen.r.Intn(9)
// Valid hcall humbers at the momemt are: 4..0x450
- gen.ld64(3, uint64(gen.r.Intn(4+(0x450-4)/4)))
+ gen.byte(gen.imap.ld64(3, uint64(gen.r.Intn(4+(0x450-4)/4))))
for i := 4; i < n+4; i++ {
- gen.ld64(uint(i), gen.r.Uint64())
+ gen.byte(gen.imap.ld64(uint(i), gen.r.Uint64()))
}
- gen.byte(gen.imap["sc"].EncodeParam(map[string]uint{"LEV": lev}, nil))
+ gen.byte(gen.imap["sc"].enc(map[string]uint{"LEV": lev}))
}