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