Home | History | Annotate | Download | only in x86asm
      1 // Copyright 2014 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 // Support for testing against external disassembler program.
      6 
      7 package x86asm
      8 
      9 import (
     10 	"bufio"
     11 	"bytes"
     12 	"encoding/hex"
     13 	"flag"
     14 	"fmt"
     15 	"io/ioutil"
     16 	"log"
     17 	"math/rand"
     18 	"os"
     19 	"os/exec"
     20 	"regexp"
     21 	"runtime"
     22 	"strings"
     23 	"testing"
     24 	"time"
     25 )
     26 
     27 var (
     28 	printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths")
     29 	dumpTest   = flag.Bool("dump", false, "dump all encodings")
     30 	mismatch   = flag.Bool("mismatch", false, "log allowed mismatches")
     31 	longTest   = flag.Bool("long", false, "long test")
     32 	keep       = flag.Bool("keep", false, "keep object files around")
     33 	debug      = false
     34 )
     35 
     36 // An ExtInst represents a single decoded instruction parsed
     37 // from an external disassembler's output.
     38 type ExtInst struct {
     39 	addr uint32
     40 	enc  [32]byte
     41 	nenc int
     42 	text string
     43 }
     44 
     45 func (r ExtInst) String() string {
     46 	return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
     47 }
     48 
     49 // An ExtDis is a connection between an external disassembler and a test.
     50 type ExtDis struct {
     51 	Arch     int
     52 	Dec      chan ExtInst
     53 	File     *os.File
     54 	Size     int
     55 	KeepFile bool
     56 	Cmd      *exec.Cmd
     57 }
     58 
     59 // Run runs the given command - the external disassembler - and returns
     60 // a buffered reader of its standard output.
     61 func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
     62 	if *keep {
     63 		log.Printf("%s\n", strings.Join(cmd, " "))
     64 	}
     65 	ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
     66 	out, err := ext.Cmd.StdoutPipe()
     67 	if err != nil {
     68 		return nil, fmt.Errorf("stdoutpipe: %v", err)
     69 	}
     70 	if err := ext.Cmd.Start(); err != nil {
     71 		return nil, fmt.Errorf("exec: %v", err)
     72 	}
     73 
     74 	b := bufio.NewReaderSize(out, 1<<20)
     75 	return b, nil
     76 }
     77 
     78 // Wait waits for the command started with Run to exit.
     79 func (ext *ExtDis) Wait() error {
     80 	return ext.Cmd.Wait()
     81 }
     82 
     83 // testExtDis tests a set of byte sequences against an external disassembler.
     84 // The disassembler is expected to produce the given syntax and be run
     85 // in the given architecture mode (16, 32, or 64-bit).
     86 // The extdis function must start the external disassembler
     87 // and then parse its output, sending the parsed instructions on ext.Dec.
     88 // The generate function calls its argument f once for each byte sequence
     89 // to be tested. The generate function itself will be called twice, and it must
     90 // make the same sequence of calls to f each time.
     91 // When a disassembly does not match the internal decoding,
     92 // allowedMismatch determines whether this mismatch should be
     93 // allowed, or else considered an error.
     94 func testExtDis(
     95 	t *testing.T,
     96 	syntax string,
     97 	arch int,
     98 	extdis func(ext *ExtDis) error,
     99 	generate func(f func([]byte)),
    100 	allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool,
    101 ) {
    102 	start := time.Now()
    103 	ext := &ExtDis{
    104 		Dec:  make(chan ExtInst),
    105 		Arch: arch,
    106 	}
    107 	errc := make(chan error)
    108 
    109 	// First pass: write instructions to input file for external disassembler.
    110 	file, f, size, err := writeInst(generate)
    111 	if err != nil {
    112 		t.Fatal(err)
    113 	}
    114 	ext.Size = size
    115 	ext.File = f
    116 	defer func() {
    117 		f.Close()
    118 		if !*keep {
    119 			os.Remove(file)
    120 		}
    121 	}()
    122 
    123 	// Second pass: compare disassembly against our decodings.
    124 	var (
    125 		totalTests  = 0
    126 		totalSkips  = 0
    127 		totalErrors = 0
    128 
    129 		errors = make([]string, 0, 100) // sampled errors, at most cap
    130 	)
    131 	go func() {
    132 		errc <- extdis(ext)
    133 	}()
    134 	generate(func(enc []byte) {
    135 		dec, ok := <-ext.Dec
    136 		if !ok {
    137 			t.Errorf("decoding stream ended early")
    138 			return
    139 		}
    140 		inst, text := disasm(syntax, arch, pad(enc))
    141 		totalTests++
    142 		if *dumpTest {
    143 			fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
    144 		}
    145 		if text != dec.text || inst.Len != dec.nenc {
    146 			suffix := ""
    147 			if allowedMismatch(text, size, &inst, dec) {
    148 				totalSkips++
    149 				if !*mismatch {
    150 					return
    151 				}
    152 				suffix += " (allowed mismatch)"
    153 			}
    154 			totalErrors++
    155 			if len(errors) >= cap(errors) {
    156 				j := rand.Intn(totalErrors)
    157 				if j >= cap(errors) {
    158 					return
    159 				}
    160 				errors = append(errors[:j], errors[j+1:]...)
    161 			}
    162 			errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix))
    163 		}
    164 	})
    165 
    166 	if *mismatch {
    167 		totalErrors -= totalSkips
    168 	}
    169 
    170 	for _, b := range errors {
    171 		t.Log(b)
    172 	}
    173 
    174 	if totalErrors > 0 {
    175 		t.Fail()
    176 	}
    177 	t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
    178 
    179 	if err := <-errc; err != nil {
    180 		t.Fatalf("external disassembler: %v", err)
    181 	}
    182 }
    183 
    184 const start = 0x8000 // start address of text
    185 
    186 // writeInst writes the generated byte sequences to a new file
    187 // starting at offset start. That file is intended to be the input to
    188 // the external disassembler.
    189 func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
    190 	f, err = ioutil.TempFile("", "x86map")
    191 	if err != nil {
    192 		return
    193 	}
    194 
    195 	file = f.Name()
    196 
    197 	f.Seek(start, 0)
    198 	w := bufio.NewWriter(f)
    199 	defer w.Flush()
    200 	size = 0
    201 	generate(func(x []byte) {
    202 		if len(x) > 16 {
    203 			x = x[:16]
    204 		}
    205 		if debug {
    206 			fmt.Printf("%#x: %x%x\n", start+size, x, pops[len(x):])
    207 		}
    208 		w.Write(x)
    209 		w.Write(pops[len(x):])
    210 		size += len(pops)
    211 	})
    212 	return file, f, size, nil
    213 }
    214 
    215 // 0x5F is a single-byte pop instruction.
    216 // We pad the bytes we want decoded with enough 0x5Fs
    217 // that no matter what state the instruction stream is in
    218 // after reading our bytes, the pops will get us back to
    219 // a forced instruction boundary.
    220 var pops = []byte{
    221 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
    222 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
    223 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
    224 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
    225 }
    226 
    227 // pad pads the code sequence with pops.
    228 func pad(enc []byte) []byte {
    229 	return append(enc[:len(enc):len(enc)], pops...)
    230 }
    231 
    232 // disasm returns the decoded instruction and text
    233 // for the given source bytes, using the given syntax and mode.
    234 func disasm(syntax string, mode int, src []byte) (inst Inst, text string) {
    235 	// If printTests is set, we record the coverage value
    236 	// before and after, and we write out the inputs for which
    237 	// coverage went up, in the format expected in testdata/decode.text.
    238 	// This produces a fairly small set of test cases that exercise nearly
    239 	// all the code.
    240 	var cover float64
    241 	if *printTests {
    242 		cover -= coverage()
    243 	}
    244 
    245 	inst, err := decode1(src, mode, syntax == "gnu")
    246 	if err != nil {
    247 		text = "error: " + err.Error()
    248 	} else {
    249 		switch syntax {
    250 		case "gnu":
    251 			text = GNUSyntax(inst, 0, nil)
    252 		case "intel":
    253 			text = IntelSyntax(inst, 0, nil)
    254 		case "plan9": // [sic]
    255 			text = GoSyntax(inst, 0, nil)
    256 		default:
    257 			text = "error: unknown syntax " + syntax
    258 		}
    259 	}
    260 
    261 	if *printTests {
    262 		cover += coverage()
    263 		if cover > 0 {
    264 			max := len(src)
    265 			if max > 16 && inst.Len <= 16 {
    266 				max = 16
    267 			}
    268 			fmt.Printf("%x|%x\t%d\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], mode, syntax, text)
    269 		}
    270 	}
    271 
    272 	return
    273 }
    274 
    275 // coverage returns a floating point number denoting the
    276 // test coverage until now. The number increases when new code paths are exercised,
    277 // both in the Go program and in the decoder byte code.
    278 func coverage() float64 {
    279 	/*
    280 		testing.Coverage is not in the main distribution.
    281 		The implementation, which must go in package testing, is:
    282 
    283 		// Coverage reports the current code coverage as a fraction in the range [0, 1].
    284 		func Coverage() float64 {
    285 			var n, d int64
    286 			for _, counters := range cover.Counters {
    287 				for _, c := range counters {
    288 					if c > 0 {
    289 						n++
    290 					}
    291 					d++
    292 				}
    293 			}
    294 			if d == 0 {
    295 				return 0
    296 			}
    297 			return float64(n) / float64(d)
    298 		}
    299 	*/
    300 
    301 	var f float64
    302 	// f += testing.Coverage()
    303 	f += decodeCoverage()
    304 	return f
    305 }
    306 
    307 func decodeCoverage() float64 {
    308 	n := 0
    309 	for _, t := range decoderCover {
    310 		if t {
    311 			n++
    312 		}
    313 	}
    314 	return float64(1+n) / float64(1+len(decoderCover))
    315 }
    316 
    317 // Helpers for writing disassembler output parsers.
    318 
    319 // isPrefix reports whether text is the name of an instruction prefix.
    320 func isPrefix(text string) bool {
    321 	return prefixByte[text] > 0
    322 }
    323 
    324 // prefixByte maps instruction prefix text to actual prefix byte values.
    325 var prefixByte = map[string]byte{
    326 	"es":       0x26,
    327 	"cs":       0x2e,
    328 	"ss":       0x36,
    329 	"ds":       0x3e,
    330 	"fs":       0x64,
    331 	"gs":       0x65,
    332 	"data16":   0x66,
    333 	"addr16":   0x67,
    334 	"lock":     0xf0,
    335 	"repn":     0xf2,
    336 	"repne":    0xf2,
    337 	"rep":      0xf3,
    338 	"repe":     0xf3,
    339 	"xacquire": 0xf2,
    340 	"xrelease": 0xf3,
    341 	"bnd":      0xf2,
    342 	"addr32":   0x66,
    343 	"data32":   0x67,
    344 }
    345 
    346 // hasPrefix reports whether any of the space-separated words in the text s
    347 // begins with any of the given prefixes.
    348 func hasPrefix(s string, prefixes ...string) bool {
    349 	for _, prefix := range prefixes {
    350 		for s := s; s != ""; {
    351 			if strings.HasPrefix(s, prefix) {
    352 				return true
    353 			}
    354 			i := strings.Index(s, " ")
    355 			if i < 0 {
    356 				break
    357 			}
    358 			s = s[i+1:]
    359 		}
    360 	}
    361 	return false
    362 }
    363 
    364 // contains reports whether the text s contains any of the given substrings.
    365 func contains(s string, substrings ...string) bool {
    366 	for _, sub := range substrings {
    367 		if strings.Contains(s, sub) {
    368 			return true
    369 		}
    370 	}
    371 	return false
    372 }
    373 
    374 // isHex reports whether b is a hexadecimal character (0-9A-Fa-f).
    375 func isHex(b byte) bool { return b == '0' || unhex[b] > 0 }
    376 
    377 // parseHex parses the hexadecimal byte dump in hex,
    378 // appending the parsed bytes to raw and returning the updated slice.
    379 // The returned bool signals whether any invalid hex was found.
    380 // Spaces and tabs between bytes are okay but any other non-hex is not.
    381 func parseHex(hex []byte, raw []byte) ([]byte, bool) {
    382 	hex = trimSpace(hex)
    383 	for j := 0; j < len(hex); {
    384 		for hex[j] == ' ' || hex[j] == '\t' {
    385 			j++
    386 		}
    387 		if j >= len(hex) {
    388 			break
    389 		}
    390 		if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
    391 			return nil, false
    392 		}
    393 		raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]])
    394 		j += 2
    395 	}
    396 	return raw, true
    397 }
    398 
    399 var unhex = [256]byte{
    400 	'0': 0,
    401 	'1': 1,
    402 	'2': 2,
    403 	'3': 3,
    404 	'4': 4,
    405 	'5': 5,
    406 	'6': 6,
    407 	'7': 7,
    408 	'8': 8,
    409 	'9': 9,
    410 	'A': 10,
    411 	'B': 11,
    412 	'C': 12,
    413 	'D': 13,
    414 	'E': 14,
    415 	'F': 15,
    416 	'a': 10,
    417 	'b': 11,
    418 	'c': 12,
    419 	'd': 13,
    420 	'e': 14,
    421 	'f': 15,
    422 }
    423 
    424 // index is like bytes.Index(s, []byte(t)) but avoids the allocation.
    425 func index(s []byte, t string) int {
    426 	i := 0
    427 	for {
    428 		j := bytes.IndexByte(s[i:], t[0])
    429 		if j < 0 {
    430 			return -1
    431 		}
    432 		i = i + j
    433 		if i+len(t) > len(s) {
    434 			return -1
    435 		}
    436 		for k := 1; k < len(t); k++ {
    437 			if s[i+k] != t[k] {
    438 				goto nomatch
    439 			}
    440 		}
    441 		return i
    442 	nomatch:
    443 		i++
    444 	}
    445 }
    446 
    447 // fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
    448 // If s must be rewritten, it is rewritten in place.
    449 func fixSpace(s []byte) []byte {
    450 	s = trimSpace(s)
    451 	for i := 0; i < len(s); i++ {
    452 		if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
    453 			goto Fix
    454 		}
    455 	}
    456 	return s
    457 
    458 Fix:
    459 	b := s
    460 	w := 0
    461 	for i := 0; i < len(s); i++ {
    462 		c := s[i]
    463 		if c == '\t' || c == '\n' {
    464 			c = ' '
    465 		}
    466 		if c == ' ' && w > 0 && b[w-1] == ' ' {
    467 			continue
    468 		}
    469 		b[w] = c
    470 		w++
    471 	}
    472 	if w > 0 && b[w-1] == ' ' {
    473 		w--
    474 	}
    475 	return b[:w]
    476 }
    477 
    478 // trimSpace trims leading and trailing space from s, returning a subslice of s.
    479 func trimSpace(s []byte) []byte {
    480 	j := len(s)
    481 	for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') {
    482 		j--
    483 	}
    484 	i := 0
    485 	for i < j && (s[i] == ' ' || s[i] == '\t') {
    486 		i++
    487 	}
    488 	return s[i:j]
    489 }
    490 
    491 // pcrel and pcrelw match instructions using relative addressing mode.
    492 var (
    493 	pcrel  = regexp.MustCompile(`^((?:.* )?(?:j[a-z]+|call|ljmp|loopn?e?w?|xbegin)q?(?:,p[nt])?) 0x([0-9a-f]+)$`)
    494 	pcrelw = regexp.MustCompile(`^((?:.* )?(?:callw|jmpw|xbeginw|ljmpw)(?:,p[nt])?) 0x([0-9a-f]+)$`)
    495 )
    496 
    497 // Generators.
    498 //
    499 // The test cases are described as functions that invoke a callback repeatedly,
    500 // with a new input sequence each time. These helpers make writing those
    501 // a little easier.
    502 
    503 // hexCases generates the cases written in hexadecimal in the encoded string.
    504 // Spaces in 'encoded' separate entire test cases, not individual bytes.
    505 func hexCases(t *testing.T, encoded string) func(func([]byte)) {
    506 	return func(try func([]byte)) {
    507 		for _, x := range strings.Fields(encoded) {
    508 			src, err := hex.DecodeString(x)
    509 			if err != nil {
    510 				t.Errorf("parsing %q: %v", x, err)
    511 			}
    512 			try(src)
    513 		}
    514 	}
    515 }
    516 
    517 // testdataCases generates the test cases recorded in testdata/decode.txt.
    518 // It only uses the inputs; it ignores the answers recorded in that file.
    519 func testdataCases(t *testing.T) func(func([]byte)) {
    520 	var codes [][]byte
    521 	data, err := ioutil.ReadFile("testdata/decode.txt")
    522 	if err != nil {
    523 		t.Fatal(err)
    524 	}
    525 	for _, line := range strings.Split(string(data), "\n") {
    526 		line = strings.TrimSpace(line)
    527 		if line == "" || strings.HasPrefix(line, "#") {
    528 			continue
    529 		}
    530 		f := strings.Fields(line)[0]
    531 		i := strings.Index(f, "|")
    532 		if i < 0 {
    533 			t.Errorf("parsing %q: missing | separator", f)
    534 			continue
    535 		}
    536 		if i%2 != 0 {
    537 			t.Errorf("parsing %q: misaligned | separator", f)
    538 		}
    539 		code, err := hex.DecodeString(f[:i] + f[i+1:])
    540 		if err != nil {
    541 			t.Errorf("parsing %q: %v", f, err)
    542 			continue
    543 		}
    544 		codes = append(codes, code)
    545 	}
    546 
    547 	return func(try func([]byte)) {
    548 		for _, code := range codes {
    549 			try(code)
    550 		}
    551 	}
    552 }
    553 
    554 // manyPrefixes generates all possible 2 combinations of nine chosen prefixes.
    555 // The relative ordering of the prefixes within the combinations varies deterministically.
    556 func manyPrefixes(try func([]byte)) {
    557 	var prefixBytes = []byte{0x66, 0x67, 0xF0, 0xF2, 0xF3, 0x3E, 0x36, 0x66, 0x67}
    558 	var enc []byte
    559 	for i := 0; i < 1<<uint(len(prefixBytes)); i++ {
    560 		enc = enc[:0]
    561 		for j, p := range prefixBytes {
    562 			if i&(1<<uint(j)) != 0 {
    563 				enc = append(enc, p)
    564 			}
    565 		}
    566 		if len(enc) > 0 {
    567 			k := i % len(enc)
    568 			enc[0], enc[k] = enc[k], enc[0]
    569 		}
    570 		try(enc)
    571 	}
    572 }
    573 
    574 // basicPrefixes geneartes 8 different possible prefix cases: no prefix
    575 // and then one each of seven different prefix bytes.
    576 func basicPrefixes(try func([]byte)) {
    577 	try(nil)
    578 	for _, b := range []byte{0x66, 0x67, 0xF0, 0xF2, 0xF3, 0x3E, 0x36} {
    579 		try([]byte{b})
    580 	}
    581 }
    582 
    583 func rexPrefixes(try func([]byte)) {
    584 	try(nil)
    585 	for _, b := range []byte{0x40, 0x48, 0x43, 0x4C} {
    586 		try([]byte{b})
    587 	}
    588 }
    589 
    590 // concat takes two generators and returns a generator for the
    591 // cross product of the two, concatenating the results from each.
    592 func concat(gen1, gen2 func(func([]byte))) func(func([]byte)) {
    593 	return func(try func([]byte)) {
    594 		gen1(func(enc1 []byte) {
    595 			gen2(func(enc2 []byte) {
    596 				try(append(enc1[:len(enc1):len(enc1)], enc2...))
    597 			})
    598 		})
    599 	}
    600 }
    601 
    602 // concat3 takes three generators and returns a generator for the
    603 // cross product of the three, concatenating the results from each.
    604 func concat3(gen1, gen2, gen3 func(func([]byte))) func(func([]byte)) {
    605 	return func(try func([]byte)) {
    606 		gen1(func(enc1 []byte) {
    607 			gen2(func(enc2 []byte) {
    608 				gen3(func(enc3 []byte) {
    609 					try(append(append(enc1[:len(enc1):len(enc1)], enc2...), enc3...))
    610 				})
    611 			})
    612 		})
    613 	}
    614 }
    615 
    616 // concat4 takes four generators and returns a generator for the
    617 // cross product of the four, concatenating the results from each.
    618 func concat4(gen1, gen2, gen3, gen4 func(func([]byte))) func(func([]byte)) {
    619 	return func(try func([]byte)) {
    620 		gen1(func(enc1 []byte) {
    621 			gen2(func(enc2 []byte) {
    622 				gen3(func(enc3 []byte) {
    623 					gen4(func(enc4 []byte) {
    624 						try(append(append(append(enc1[:len(enc1):len(enc1)], enc2...), enc3...), enc4...))
    625 					})
    626 				})
    627 			})
    628 		})
    629 	}
    630 }
    631 
    632 // filter generates the sequences from gen that satisfy ok.
    633 func filter(gen func(func([]byte)), ok func([]byte) bool) func(func([]byte)) {
    634 	return func(try func([]byte)) {
    635 		gen(func(enc []byte) {
    636 			if ok(enc) {
    637 				try(enc)
    638 			}
    639 		})
    640 	}
    641 }
    642 
    643 // enum8bit generates all possible 1-byte sequences, followed by distinctive padding.
    644 func enum8bit(try func([]byte)) {
    645 	for i := 0; i < 1<<8; i++ {
    646 		try([]byte{byte(i), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88})
    647 	}
    648 }
    649 
    650 // enum8bit generates all possible 2-byte sequences, followed by distinctive padding.
    651 func enum16bit(try func([]byte)) {
    652 	for i := 0; i < 1<<16; i++ {
    653 		try([]byte{byte(i), byte(i >> 8), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88})
    654 	}
    655 }
    656 
    657 // enum24bit generates all possible 3-byte sequences, followed by distinctive padding.
    658 func enum24bit(try func([]byte)) {
    659 	for i := 0; i < 1<<24; i++ {
    660 		try([]byte{byte(i), byte(i >> 8), byte(i >> 16), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88})
    661 	}
    662 }
    663 
    664 // enumModRM generates all possible modrm bytes and, for modrm values that indicate
    665 // a following sib byte, all possible modrm, sib combinations.
    666 func enumModRM(try func([]byte)) {
    667 	for i := 0; i < 256; i++ {
    668 		if (i>>3)&07 == 04 && i>>6 != 3 { // has sib
    669 			for j := 0; j < 256; j++ {
    670 				try([]byte{0, byte(i), byte(j), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) // byte encodings
    671 				try([]byte{1, byte(i), byte(j), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) // word encodings
    672 			}
    673 		} else {
    674 			try([]byte{0, byte(i), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) // byte encodings
    675 			try([]byte{1, byte(i), 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}) // word encodings
    676 		}
    677 	}
    678 }
    679 
    680 // fixed generates the single case b.
    681 // It's mainly useful to prepare an argument for concat or concat3.
    682 func fixed(b ...byte) func(func([]byte)) {
    683 	return func(try func([]byte)) {
    684 		try(b)
    685 	}
    686 }
    687 
    688 // testBasic runs the given test function with cases all using opcode as the initial opcode bytes.
    689 // It runs three phases:
    690 //
    691 // First, zero-or-one prefixes followed by opcode followed by all possible 1-byte values.
    692 // If in -short mode, that's all.
    693 //
    694 // Second, zero-or-one prefixes followed by opcode followed by all possible 2-byte values.
    695 // If not in -long mode, that's all. This phase and the next run in parallel with other tests
    696 // (using t.Parallel).
    697 //
    698 // Finally, opcode followed by all possible 3-byte values. The test can take a very long time
    699 // and prints progress messages to package log.
    700 func testBasic(t *testing.T, testfn func(*testing.T, func(func([]byte))), opcode ...byte) {
    701 	testfn(t, concat3(basicPrefixes, fixed(opcode...), enum8bit))
    702 	if testing.Short() {
    703 		return
    704 	}
    705 
    706 	t.Parallel()
    707 	testfn(t, concat3(basicPrefixes, fixed(opcode...), enum16bit))
    708 	if !*longTest {
    709 		return
    710 	}
    711 
    712 	name := caller(2)
    713 	op1 := make([]byte, len(opcode)+1)
    714 	copy(op1, opcode)
    715 	for i := 0; i < 256; i++ {
    716 		log.Printf("%s 24-bit: %d/256\n", name, i)
    717 		op1[len(opcode)] = byte(i)
    718 		testfn(t, concat(fixed(op1...), enum16bit))
    719 	}
    720 }
    721 
    722 func testBasicREX(t *testing.T, testfn func(*testing.T, func(func([]byte))), opcode ...byte) {
    723 	testfn(t, filter(concat4(basicPrefixes, rexPrefixes, fixed(opcode...), enum8bit), isValidREX))
    724 	if testing.Short() {
    725 		return
    726 	}
    727 
    728 	t.Parallel()
    729 	testfn(t, filter(concat4(basicPrefixes, rexPrefixes, fixed(opcode...), enum16bit), isValidREX))
    730 	if !*longTest {
    731 		return
    732 	}
    733 
    734 	name := caller(2)
    735 	op1 := make([]byte, len(opcode)+1)
    736 	copy(op1, opcode)
    737 	for i := 0; i < 256; i++ {
    738 		log.Printf("%s 24-bit: %d/256\n", name, i)
    739 		op1[len(opcode)] = byte(i)
    740 		testfn(t, filter(concat3(rexPrefixes, fixed(op1...), enum16bit), isValidREX))
    741 	}
    742 }
    743 
    744 // testPrefix runs the given test function for all many prefix possibilities
    745 // followed by all possible 1-byte sequences.
    746 //
    747 // If in -long mode, it then runs a test of all the prefix possibilities followed
    748 // by all possible 2-byte sequences.
    749 func testPrefix(t *testing.T, testfn func(*testing.T, func(func([]byte)))) {
    750 	t.Parallel()
    751 	testfn(t, concat(manyPrefixes, enum8bit))
    752 	if testing.Short() || !*longTest {
    753 		return
    754 	}
    755 
    756 	name := caller(2)
    757 	for i := 0; i < 256; i++ {
    758 		log.Printf("%s 16-bit: %d/256\n", name, i)
    759 		testfn(t, concat3(manyPrefixes, fixed(byte(i)), enum8bit))
    760 	}
    761 }
    762 
    763 func testPrefixREX(t *testing.T, testfn func(*testing.T, func(func([]byte)))) {
    764 	t.Parallel()
    765 	testfn(t, filter(concat3(manyPrefixes, rexPrefixes, enum8bit), isValidREX))
    766 	if testing.Short() || !*longTest {
    767 		return
    768 	}
    769 
    770 	name := caller(2)
    771 	for i := 0; i < 256; i++ {
    772 		log.Printf("%s 16-bit: %d/256\n", name, i)
    773 		testfn(t, filter(concat4(manyPrefixes, rexPrefixes, fixed(byte(i)), enum8bit), isValidREX))
    774 	}
    775 }
    776 
    777 func caller(skip int) string {
    778 	pc, _, _, _ := runtime.Caller(skip)
    779 	f := runtime.FuncForPC(pc)
    780 	name := "?"
    781 	if f != nil {
    782 		name = f.Name()
    783 		if i := strings.LastIndex(name, "."); i >= 0 {
    784 			name = name[i+1:]
    785 		}
    786 	}
    787 	return name
    788 }
    789 
    790 func isValidREX(x []byte) bool {
    791 	i := 0
    792 	for i < len(x) && isPrefixByte(x[i]) {
    793 		i++
    794 	}
    795 	if i < len(x) && Prefix(x[i]).IsREX() {
    796 		i++
    797 		if i < len(x) {
    798 			return !isPrefixByte(x[i]) && !Prefix(x[i]).IsREX()
    799 		}
    800 	}
    801 	return true
    802 }
    803 
    804 func isPrefixByte(b byte) bool {
    805 	switch b {
    806 	case 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65, 0x66, 0x67, 0xF0, 0xF2, 0xF3:
    807 		return true
    808 	}
    809 	return false
    810 }
    811