Russ Cox | c75f81f | 2014-09-30 12:28:24 -0400 | [diff] [blame] | 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 TestObjdump32Manual(t *testing.T) { testObjdump32(t, hexCases(t, objdumpManualTests)) } |
| 14 | func TestObjdump32Testdata(t *testing.T) { testObjdump32(t, concat(basicPrefixes, testdataCases(t))) } |
| 15 | func TestObjdump32ModRM(t *testing.T) { testObjdump32(t, concat(basicPrefixes, enumModRM)) } |
| 16 | func TestObjdump32OneByte(t *testing.T) { testBasic(t, testObjdump32) } |
| 17 | func TestObjdump320F(t *testing.T) { testBasic(t, testObjdump32, 0x0F) } |
| 18 | func TestObjdump320F38(t *testing.T) { testBasic(t, testObjdump32, 0x0F, 0x38) } |
| 19 | func TestObjdump320F3A(t *testing.T) { testBasic(t, testObjdump32, 0x0F, 0x3A) } |
| 20 | func TestObjdump32Prefix(t *testing.T) { testPrefix(t, testObjdump32) } |
| 21 | |
| 22 | func TestObjdump64Manual(t *testing.T) { testObjdump64(t, hexCases(t, objdumpManualTests)) } |
| 23 | func TestObjdump64Testdata(t *testing.T) { testObjdump64(t, concat(basicPrefixes, testdataCases(t))) } |
| 24 | func TestObjdump64ModRM(t *testing.T) { testObjdump64(t, concat(basicPrefixes, enumModRM)) } |
| 25 | func TestObjdump64OneByte(t *testing.T) { testBasic(t, testObjdump64) } |
| 26 | func TestObjdump640F(t *testing.T) { testBasic(t, testObjdump64, 0x0F) } |
| 27 | func TestObjdump640F38(t *testing.T) { testBasic(t, testObjdump64, 0x0F, 0x38) } |
| 28 | func TestObjdump640F3A(t *testing.T) { testBasic(t, testObjdump64, 0x0F, 0x3A) } |
| 29 | func TestObjdump64Prefix(t *testing.T) { testPrefix(t, testObjdump64) } |
| 30 | |
| 31 | func TestObjdump64REXTestdata(t *testing.T) { |
| 32 | testObjdump64(t, filter(concat3(basicPrefixes, rexPrefixes, testdataCases(t)), isValidREX)) |
| 33 | } |
| 34 | func TestObjdump64REXModRM(t *testing.T) { |
| 35 | testObjdump64(t, concat3(basicPrefixes, rexPrefixes, enumModRM)) |
| 36 | } |
| 37 | func TestObjdump64REXOneByte(t *testing.T) { testBasicREX(t, testObjdump64) } |
| 38 | func TestObjdump64REX0F(t *testing.T) { testBasicREX(t, testObjdump64, 0x0F) } |
| 39 | func TestObjdump64REX0F38(t *testing.T) { testBasicREX(t, testObjdump64, 0x0F, 0x38) } |
| 40 | func TestObjdump64REX0F3A(t *testing.T) { testBasicREX(t, testObjdump64, 0x0F, 0x3A) } |
| 41 | func TestObjdump64REXPrefix(t *testing.T) { testPrefixREX(t, testObjdump64) } |
| 42 | |
| 43 | // objdumpManualTests holds test cases that will be run by TestObjdumpManual. |
| 44 | // If you are debugging a few cases that turned up in a longer run, it can be useful |
| 45 | // to list them here and then use -run=ObjdumpManual, particularly with tracing enabled. |
| 46 | var objdumpManualTests = ` |
| 47 | F390 |
| 48 | ` |
| 49 | |
| 50 | // allowedMismatchObjdump reports whether the mismatch between text and dec |
| 51 | // should be allowed by the test. |
| 52 | func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool { |
| 53 | if size == 15 && dec.nenc == 15 && contains(text, "truncated") && contains(dec.text, "(bad)") { |
| 54 | return true |
| 55 | } |
| 56 | |
| 57 | if i := strings.LastIndex(dec.text, " "); isPrefix(dec.text[i+1:]) && size == 1 && isPrefix(text) { |
| 58 | return true |
| 59 | } |
| 60 | |
| 61 | if size == dec.nenc && contains(dec.text, "movupd") && contains(dec.text, "data32") { |
| 62 | s := strings.Replace(dec.text, "data32 ", "", -1) |
| 63 | if text == s { |
| 64 | return true |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // Simplify our invalid instruction text. |
| 69 | if text == "error: unrecognized instruction" { |
| 70 | text = "BAD" |
| 71 | } |
| 72 | |
| 73 | // Invalid instructions for which libopcodes prints %? register. |
| 74 | // FF E8 11 22 33 44: |
| 75 | // Invalid instructions for which libopcodes prints "internal disassembler error". |
| 76 | // Invalid instructions for which libopcodes prints 8087 only (e.g., DB E0) |
| 77 | // or prints 287 only (e.g., DB E4). |
| 78 | if contains(dec.text, "%?", "<internal disassembler error>", "(8087 only)", "(287 only)") { |
| 79 | dec.text = "(bad)" |
| 80 | } |
| 81 | |
| 82 | // 0F 19 11, 0F 1C 11, 0F 1D 11, 0F 1E 11, 0F 1F 11: libopcodes says nop, |
| 83 | // but the Intel manuals say that the only NOP there is 0F 1F /0. |
| 84 | // Perhaps libopcodes is reporting an older encoding. |
| 85 | i := bytes.IndexByte(dec.enc[:], 0x0F) |
| 86 | if contains(dec.text, "nop") && i >= 0 && i+2 < len(dec.enc) && dec.enc[i+1]&^7 == 0x18 && (dec.enc[i+1] != 0x1F || (dec.enc[i+2]>>3)&7 != 0) { |
| 87 | dec.text = "(bad)" |
| 88 | } |
| 89 | |
| 90 | // Any invalid instruction. |
| 91 | if text == "BAD" && contains(dec.text, "(bad)") { |
| 92 | return true |
| 93 | } |
| 94 | |
| 95 | // Instructions libopcodes knows but we do not (e.g., 0F 19 11). |
| 96 | if (text == "BAD" || size == 1 && isPrefix(text)) && hasPrefix(dec.text, unsupported...) { |
| 97 | return true |
| 98 | } |
| 99 | |
| 100 | // Instructions we know but libopcodes does not (e.g., 0F D0 11). |
| 101 | if (contains(dec.text, "(bad)") || dec.nenc == 1 && isPrefix(dec.text)) && hasPrefix(text, libopcodesUnsupported...) { |
| 102 | return true |
| 103 | } |
| 104 | |
| 105 | // Libopcodes rejects F2 90 as NOP. Not sure why. |
| 106 | if (contains(dec.text, "(bad)") || dec.nenc == 1 && isPrefix(dec.text)) && inst.Opcode>>24 == 0x90 && countPrefix(inst, 0xF2) > 0 { |
| 107 | return true |
| 108 | } |
| 109 | |
| 110 | // 0F 20 11, 0F 21 11, 0F 22 11, 0F 23 11, 0F 24 11: |
| 111 | // Moves into and out of some control registers seem to be unsupported by libopcodes. |
| 112 | // TODO(rsc): Are they invalid somehow? |
| 113 | if (contains(dec.text, "(bad)") || dec.nenc == 1 && isPrefix(dec.text)) && contains(text, "%cr", "%db", "%tr") { |
| 114 | return true |
| 115 | } |
| 116 | |
| 117 | if contains(dec.text, "fwait") && dec.nenc == 1 && dec.enc[0] != 0x9B { |
| 118 | return true |
| 119 | } |
| 120 | |
| 121 | // 9B D9 11: libopcodes reports FSTSW instead of FWAIT + FNSTSW. |
| 122 | // This is correct in that FSTSW is a pseudo-op for the pair, but it really |
| 123 | // is a pair of instructions: execution can stop between them. |
| 124 | // Our decoder chooses to separate them. |
| 125 | if (text == "fwait" || strings.HasSuffix(text, " fwait")) && dec.nenc >= len(strings.Fields(text)) && dec.enc[len(strings.Fields(text))-1] == 0x9B { |
| 126 | return true |
| 127 | } |
| 128 | |
| 129 | // 0F 18 77 11: |
| 130 | // Invalid instructions for which libopcodes prints "nop/reserved". |
| 131 | // Perhaps libopcodes is reporting an older encoding. |
| 132 | if text == "BAD" && contains(dec.text, "nop/reserved") { |
| 133 | return true |
| 134 | } |
| 135 | |
| 136 | // 0F C7 B0 11 22 33 44: libopcodes says vmptrld 0x44332211(%eax); we say rdrand %eax. |
| 137 | // TODO(rsc): Fix, since we are probably wrong, but we don't have vmptrld in the manual. |
| 138 | if contains(text, "rdrand") && contains(dec.text, "vmptrld", "vmxon", "vmclear") { |
| 139 | return true |
| 140 | } |
| 141 | |
| 142 | // DD C8: libopcodes says FNOP but the Intel manual is clear FNOP is only D9 D0. |
| 143 | // Perhaps libopcodes is reporting an older encoding. |
| 144 | if text == "BAD" && contains(dec.text, "fnop") && (dec.enc[0] != 0xD9 || dec.enc[1] != 0xD0) { |
| 145 | return true |
| 146 | } |
| 147 | |
| 148 | // 66 90: libopcodes says xchg %ax,%ax; we say 'data16 nop'. |
| 149 | // The 16-bit swap will preserve the high bits of the register, |
| 150 | // so they are the same. |
| 151 | if contains(text, "nop") && contains(dec.text, "xchg %ax,%ax") { |
| 152 | return true |
| 153 | } |
| 154 | |
| 155 | // If there are multiple prefixes, allow libopcodes to use an alternate name. |
| 156 | if size == 1 && dec.nenc == 1 && prefixByte[text] > 0 && prefixByte[text] == prefixByte[dec.text] { |
| 157 | return true |
| 158 | } |
| 159 | |
| 160 | // 26 9B: libopcodes reports "fwait"/1, ignoring segment prefix. |
| 161 | // https://sourceware.org/bugzilla/show_bug.cgi?id=16891 |
| 162 | // F0 82: Decode="lock"/1 but libopcodes="lock (bad)"/2. |
| 163 | if size == 1 && dec.nenc >= 1 && prefixByte[text] == dec.enc[0] && contains(dec.text, "(bad)", "fwait", "fnop") { |
| 164 | return true |
| 165 | } |
| 166 | |
| 167 | // libopcodes interprets 660f801122 as taking a rel16 but |
| 168 | // truncating the address at 16 bits. Not sure what is correct. |
| 169 | if contains(text, ".+0x2211", ".+0x11") && contains(dec.text, " .-") { |
| 170 | return true |
| 171 | } |
| 172 | |
| 173 | // 66 F3 0F D6 C5, 66 F2 0F D6 C0: libopcodes reports use of XMM register instead of MMX register, |
| 174 | // but only when the instruction has a 66 prefix. Maybe they know something we don't. |
| 175 | if countPrefix(inst, 0x66) > 0 && contains(dec.text, "movdq2q", "movq2dq") && !contains(dec.text, "%mm") { |
| 176 | return true |
| 177 | } |
| 178 | |
| 179 | // 0F 01 F8, 0F 05, 0F 07: these are 64-bit instructions but libopcodes accepts them. |
| 180 | if (text == "BAD" || size == 1 && isPrefix(text)) && contains(dec.text, "swapgs", "syscall", "sysret", "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase") { |
| 181 | return true |
| 182 | } |
| 183 | |
| 184 | return false |
| 185 | } |
| 186 | |
| 187 | // Instructions known to libopcodes (or xed) but not to us. |
| 188 | // Most of these come from supplementary manuals of one form or another. |
| 189 | var unsupported = strings.Fields(` |
| 190 | bndc |
| 191 | bndl |
| 192 | bndm |
| 193 | bnds |
| 194 | clac |
| 195 | clgi |
| 196 | femms |
| 197 | fldln |
| 198 | fldz |
| 199 | getsec |
| 200 | invlpga |
| 201 | kmov |
| 202 | montmul |
| 203 | pavg |
| 204 | pf2i |
| 205 | pfacc |
| 206 | pfadd |
| 207 | pfcmp |
| 208 | pfmax |
| 209 | pfmin |
| 210 | pfmul |
| 211 | pfna |
| 212 | pfpnac |
| 213 | pfrc |
| 214 | pfrs |
| 215 | pfsub |
| 216 | phadd |
| 217 | phsub |
| 218 | pi2f |
| 219 | pmulhr |
| 220 | prefetch |
| 221 | pswap |
| 222 | ptest |
| 223 | rdseed |
| 224 | sha1 |
| 225 | sha256 |
| 226 | skinit |
| 227 | stac |
| 228 | stgi |
| 229 | vadd |
| 230 | vand |
| 231 | vcmp |
| 232 | vcomis |
| 233 | vcvt |
| 234 | vcvt |
| 235 | vdiv |
| 236 | vhadd |
| 237 | vhsub |
| 238 | vld |
| 239 | vmax |
| 240 | vmcall |
| 241 | vmfunc |
| 242 | vmin |
| 243 | vmlaunch |
| 244 | vmload |
| 245 | vmmcall |
| 246 | vmov |
| 247 | vmov |
| 248 | vmov |
| 249 | vmptrld |
| 250 | vmptrst |
| 251 | vmread |
| 252 | vmresume |
| 253 | vmrun |
| 254 | vmsave |
| 255 | vmul |
| 256 | vmwrite |
| 257 | vmxoff |
| 258 | vor |
| 259 | vpack |
| 260 | vpadd |
| 261 | vpand |
| 262 | vpavg |
| 263 | vpcmp |
| 264 | vpcmp |
| 265 | vpins |
| 266 | vpmadd |
| 267 | vpmax |
| 268 | vpmin |
| 269 | vpmul |
| 270 | vpmul |
| 271 | vpor |
| 272 | vpsad |
| 273 | vpshuf |
| 274 | vpsll |
| 275 | vpsra |
| 276 | vpsrad |
| 277 | vpsrl |
| 278 | vpsub |
| 279 | vpunp |
| 280 | vpxor |
| 281 | vrcp |
| 282 | vrsqrt |
| 283 | vshuf |
| 284 | vsqrt |
| 285 | vsub |
| 286 | vucomis |
| 287 | vunp |
| 288 | vxor |
| 289 | vzero |
| 290 | xcrypt |
| 291 | xsha1 |
| 292 | xsha256 |
| 293 | xstore-rng |
| 294 | insertq |
| 295 | extrq |
| 296 | vmclear |
| 297 | invvpid |
| 298 | adox |
| 299 | vmxon |
| 300 | invept |
| 301 | adcx |
| 302 | vmclear |
| 303 | prefetchwt1 |
| 304 | enclu |
| 305 | encls |
| 306 | salc |
| 307 | fstpnce |
| 308 | fdisi8087_nop |
| 309 | fsetpm287_nop |
| 310 | feni8087_nop |
| 311 | syscall |
| 312 | sysret |
| 313 | `) |
| 314 | |
| 315 | // Instructions known to us but not to libopcodes (at least in binutils 2.24). |
| 316 | var libopcodesUnsupported = strings.Fields(` |
| 317 | addsubps |
| 318 | aes |
| 319 | blend |
| 320 | cvttpd2dq |
| 321 | dpp |
| 322 | extract |
| 323 | haddps |
| 324 | hsubps |
| 325 | insert |
| 326 | invpcid |
| 327 | lddqu |
| 328 | movmsk |
| 329 | movnt |
| 330 | movq2dq |
| 331 | mps |
| 332 | pack |
| 333 | pblend |
| 334 | pclmul |
| 335 | pcmp |
| 336 | pext |
| 337 | phmin |
| 338 | pins |
| 339 | pmax |
| 340 | pmin |
| 341 | pmov |
| 342 | pmovmsk |
| 343 | pmul |
| 344 | popcnt |
| 345 | pslld |
| 346 | psllq |
| 347 | psllw |
| 348 | psrad |
| 349 | psraw |
| 350 | psrl |
| 351 | ptest |
| 352 | punpck |
| 353 | round |
| 354 | xrstor |
| 355 | xsavec |
| 356 | xsaves |
| 357 | comis |
| 358 | ucomis |
| 359 | movhps |
| 360 | movntps |
| 361 | rsqrt |
| 362 | rcpp |
| 363 | puncpck |
| 364 | bsf |
| 365 | movq2dq |
| 366 | cvttpd2dq |
| 367 | movq |
| 368 | hsubpd |
| 369 | movdqa |
| 370 | movhpd |
| 371 | addsubpd |
| 372 | movd |
| 373 | haddpd |
| 374 | cvtps2dq |
| 375 | bsr |
| 376 | cvtdq2ps |
| 377 | rdrand |
| 378 | maskmov |
| 379 | movq2dq |
| 380 | movlhps |
| 381 | movbe |
| 382 | movlpd |
| 383 | `) |