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 package x86asm
      6 
      7 import (
      8 	"bytes"
      9 	"strings"
     10 	"testing"
     11 )
     12 
     13 func TestXed32Manual(t *testing.T)   { testXed32(t, hexCases(t, xedManualTests)) }
     14 func TestXed32Testdata(t *testing.T) { testXed32(t, concat(basicPrefixes, testdataCases(t))) }
     15 func TestXed32ModRM(t *testing.T)    { testXed32(t, concat(basicPrefixes, enumModRM)) }
     16 func TestXed32OneByte(t *testing.T)  { testBasic(t, testXed32) }
     17 func TestXed320F(t *testing.T)       { testBasic(t, testXed32, 0x0F) }
     18 func TestXed320F38(t *testing.T)     { testBasic(t, testXed32, 0x0F, 0x38) }
     19 func TestXed320F3A(t *testing.T)     { testBasic(t, testXed32, 0x0F, 0x3A) }
     20 func TestXed32Prefix(t *testing.T)   { testPrefix(t, testXed32) }
     21 
     22 func TestXed64Manual(t *testing.T)   { testXed64(t, hexCases(t, xedManualTests)) }
     23 func TestXed64Testdata(t *testing.T) { testXed64(t, concat(basicPrefixes, testdataCases(t))) }
     24 func TestXed64ModRM(t *testing.T)    { testXed64(t, concat(basicPrefixes, enumModRM)) }
     25 func TestXed64OneByte(t *testing.T)  { testBasic(t, testXed64) }
     26 func TestXed640F(t *testing.T)       { testBasic(t, testXed64, 0x0F) }
     27 func TestXed640F38(t *testing.T)     { testBasic(t, testXed64, 0x0F, 0x38) }
     28 func TestXed640F3A(t *testing.T)     { testBasic(t, testXed64, 0x0F, 0x3A) }
     29 func TestXed64Prefix(t *testing.T)   { testPrefix(t, testXed64) }
     30 
     31 func TestXed64REXTestdata(t *testing.T) {
     32 	testXed64(t, filter(concat3(basicPrefixes, rexPrefixes, testdataCases(t)), isValidREX))
     33 }
     34 func TestXed64REXModRM(t *testing.T)   { testXed64(t, concat3(basicPrefixes, rexPrefixes, enumModRM)) }
     35 func TestXed64REXOneByte(t *testing.T) { testBasicREX(t, testXed64) }
     36 func TestXed64REX0F(t *testing.T)      { testBasicREX(t, testXed64, 0x0F) }
     37 func TestXed64REX0F38(t *testing.T)    { testBasicREX(t, testXed64, 0x0F, 0x38) }
     38 func TestXed64REX0F3A(t *testing.T)    { testBasicREX(t, testXed64, 0x0F, 0x3A) }
     39 func TestXed64REXPrefix(t *testing.T)  { testPrefixREX(t, testXed64) }
     40 
     41 // xedManualTests holds test cases that will be run by TestXedManual32 and TestXedManual64.
     42 // If you are debugging a few cases that turned up in a longer run, it can be useful
     43 // to list them here and then use -run=XedManual, particularly with tracing enabled.
     44 var xedManualTests = `
     45 6690
     46 `
     47 
     48 // allowedMismatchXed reports whether the mismatch between text and dec
     49 // should be allowed by the test.
     50 func allowedMismatchXed(text string, size int, inst *Inst, dec ExtInst) bool {
     51 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "GENERAL_ERROR", "INSTR_TOO_LONG", "BAD_LOCK_PREFIX") {
     52 		return true
     53 	}
     54 
     55 	if contains(dec.text, "BAD_LOCK_PREFIX") && countExactPrefix(inst, PrefixLOCK|PrefixInvalid) > 0 {
     56 		return true
     57 	}
     58 
     59 	if contains(dec.text, "BAD_LOCK_PREFIX", "GENERAL_ERROR") && countExactPrefix(inst, PrefixLOCK|PrefixImplicit) > 0 {
     60 		return true
     61 	}
     62 
     63 	if text == "lock" && size == 1 && contains(dec.text, "BAD_LOCK_PREFIX") {
     64 		return true
     65 	}
     66 
     67 	// Instructions not known to us.
     68 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, unsupported...) {
     69 		return true
     70 	}
     71 
     72 	// Instructions not known to xed.
     73 	if contains(text, xedUnsupported...) && contains(dec.text, "ERROR") {
     74 		return true
     75 	}
     76 
     77 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "shl ") && (inst.Opcode>>16)&0xEC38 == 0xC030 {
     78 		return true
     79 	}
     80 
     81 	// 82 11 22: xed says 'adc byte ptr [ecx], 0x22' but there is no justification in the manuals for that.
     82 	// C0 30 11: xed says 'shl byte ptr [eax], 0x11' but there is no justification in the manuals for that.
     83 	// F6 08 11: xed says 'test byte ptr [eax], 0x11' but there is no justification in the manuals for that.
     84 	if (contains(text, "error:") || isPrefix(text) && size == 1) && hasByte(dec.enc[:dec.nenc], 0x82, 0xC0, 0xC1, 0xD0, 0xD1, 0xD2, 0xD3, 0xF6, 0xF7) {
     85 		return true
     86 	}
     87 
     88 	// F3 11 22 and many others: xed allows and drops misused rep/repn prefix.
     89 	if (text == "rep" && dec.enc[0] == 0xF3 || (text == "repn" || text == "repne") && dec.enc[0] == 0xF2) && (!contains(dec.text, "ins", "outs", "movs", "lods", "cmps", "scas") || contains(dec.text, "xmm")) {
     90 		return true
     91 	}
     92 
     93 	// 0F C7 30: xed says vmptrld qword ptr [eax]; we say rdrand eax.
     94 	// TODO(rsc): Fix, since we are probably wrong, but we don't have vmptrld in the manual.
     95 	if contains(text, "rdrand") && contains(dec.text, "vmptrld", "vmxon", "vmclear") {
     96 		return true
     97 	}
     98 
     99 	// F3 0F AE 00: we say 'rdfsbase dword ptr [eax]' but RDFSBASE needs a register.
    100 	// Also, this is a 64-bit only instruction.
    101 	// TODO(rsc): Fix to reject this encoding.
    102 	if contains(text, "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase") && contains(dec.text, "ERROR") {
    103 		return true
    104 	}
    105 
    106 	// 0F 01 F8: we say swapgs but that's only valid in 64-bit mode.
    107 	// TODO(rsc): Fix.
    108 	if contains(text, "swapgs") {
    109 		return true
    110 	}
    111 
    112 	// 0F 24 11: 'mov ecx, tr2' except there is no TR2.
    113 	// Or maybe the MOV to TR registers doesn't use RMF.
    114 	if contains(text, "cr1", "cr5", "cr6", "cr7", "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7") && contains(dec.text, "ERROR") {
    115 		return true
    116 	}
    117 
    118 	// 0F 19 11, 0F 1C 11, 0F 1D 11, 0F 1E 11, 0F 1F 11: xed says nop,
    119 	// but the Intel manuals say that the only NOP there is 0F 1F /0.
    120 	// Perhaps xed is reporting an older encoding.
    121 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "nop ") && (inst.Opcode>>8)&0xFFFF38 != 0x0F1F00 {
    122 		return true
    123 	}
    124 
    125 	// 66 0F AE 38: clflushopt but we only know clflush
    126 	if contains(text, "clflush") && contains(dec.text, "clflushopt") {
    127 		return true
    128 	}
    129 
    130 	// 0F 20 04 11: MOV SP, CR0 but has mod!=3 despite register argument.
    131 	// (This encoding ignores the mod bits.) The decoder sees the non-register
    132 	// mod and reads farther ahead to decode the memory reference that
    133 	// isn't really there, causing the size to be too large.
    134 	// TODO(rsc): Fix.
    135 	if text == dec.text && size > dec.nenc && contains(text, " cr", " dr", " tr") {
    136 		return true
    137 	}
    138 
    139 	// 0F AE E9: xed says lfence, which is wrong (only 0F AE E8 is lfence). And so on.
    140 	if contains(dec.text, "fence") && hasByte(dec.enc[:dec.nenc], 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF) {
    141 		return true
    142 	}
    143 
    144 	// DD C9, DF C9: xed says 'fxch st0, st1' but that instruction is D9 C9.
    145 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "fxch ") && hasByte(dec.enc[:dec.nenc], 0xDD, 0xDF) {
    146 		return true
    147 	}
    148 
    149 	// DC D4: xed says 'fcom st0, st4' but that instruction is D8 D4.
    150 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "fcom ") && hasByte(dec.enc[:dec.nenc], 0xD8, 0xDC) {
    151 		return true
    152 	}
    153 
    154 	// DE D4: xed says 'fcomp st0, st4' but that instruction is D8 D4.
    155 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "fcomp ") && hasByte(dec.enc[:dec.nenc], 0xDC, 0xDE) {
    156 		return true
    157 	}
    158 
    159 	// DF D4: xed says 'fstp st4, st0' but that instruction is DD D4.
    160 	if (contains(text, "error:") || isPrefix(text) && size == 1) && contains(dec.text, "fstp ") && hasByte(dec.enc[:dec.nenc], 0xDF) {
    161 		return true
    162 	}
    163 
    164 	return false
    165 }
    166 
    167 func countExactPrefix(inst *Inst, target Prefix) int {
    168 	n := 0
    169 	for _, p := range inst.Prefix {
    170 		if p == target {
    171 			n++
    172 		}
    173 	}
    174 	return n
    175 }
    176 
    177 func hasByte(src []byte, target ...byte) bool {
    178 	for _, b := range target {
    179 		if bytes.IndexByte(src, b) >= 0 {
    180 			return true
    181 		}
    182 	}
    183 	return false
    184 }
    185 
    186 // Instructions known to us but not to xed.
    187 var xedUnsupported = strings.Fields(`
    188 	xrstor
    189 	xsave
    190 	xsave
    191 	ud1
    192 	xgetbv
    193 	xsetbv
    194 	fxsave
    195 	fxrstor
    196 	clflush
    197 	lfence
    198 	mfence
    199 	sfence
    200 	rsqrtps
    201 	rcpps
    202 	emms
    203 	ldmxcsr
    204 	stmxcsr
    205 	movhpd
    206 	movnti
    207 	rdrand
    208 	movbe
    209 	movlpd
    210 	sysret
    211 `)
    212