github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go (about)

     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 sequenc 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  }