// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package armasm import ( "encoding/binary" "strings" "testing" ) func TestObjdumpARMTestdata(t *testing.T) { testObjdumpARM(t, testdataCases(t)) } func TestObjdumpARMManual(t *testing.T) { testObjdumpARM(t, hexCases(t, objdumpManualTests)) } func TestObjdumpARMCond(t *testing.T) { testObjdumpARM(t, condCases(t)) } func TestObjdumpARMUncond(t *testing.T) { testObjdumpARM(t, uncondCases(t)) } func TestObjdumpARMVFP(t *testing.T) { testObjdumpARM(t, vfpCases(t)) } // objdumpManualTests holds test cases that will be run by TestObjdumpARMManual. // If you are debugging a few cases that turned up in a longer run, it can be useful // to list them here and then use -run=Manual, particularly with tracing enabled. // Note that these are byte sequences, so they must be reversed from the usual // word presentation. var objdumpManualTests = ` 002a9b1d 001b9bed 020b8ded 003a9b1d 060b8ded fcde1100 b4de1100 bc480000 0b008de7 0b00ade7 fdbcfaf7 ` // allowedMismatchObjdump reports whether the mismatch between text and dec // should be allowed by the test. func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool { if hasPrefix(text, "error:") { if hasPrefix(dec.text, unsupported...) || strings.Contains(dec.text, "invalid:") || strings.HasSuffix(dec.text, "^") || strings.Contains(dec.text, "f16.f64") || strings.Contains(dec.text, "f64.f16") { return true } // word 4320F02C: libopcodes says 'nopmi {44}'. if hasPrefix(dec.text, "nop") && strings.Contains(dec.text, "{") { return true } } if hasPrefix(dec.text, "error:") && text == "undef" && inst.Enc == 0xf7fabcfd { return true } // word 00f02053: libopcodes says 'noppl {0}'. if hasPrefix(dec.text, "nop") && hasPrefix(text, "nop") && dec.text == text+" {0}" { return true } // word F57FF04F. we say 'dsb #15', libopcodes says 'dsb sy'. if hasPrefix(text, "dsb") && hasPrefix(dec.text, "dsb") { return true } // word F57FF06F. we say 'isb #15', libopcodes says 'isb sy'. if hasPrefix(text, "isb") && hasPrefix(dec.text, "isb") { return true } // word F57FF053. we say 'dmb #3', libopcodes says 'dmb osh'. if hasPrefix(text, "dmb") && hasPrefix(dec.text, "dmb") { return true } // word 992D0000. push/stmdb with no registers (undefined). // we say 'stmdbls sp!, {}', libopcodes says 'pushls {}'. if hasPrefix(text, "stmdb") && hasPrefix(dec.text, "push") && strings.Contains(text, "{}") && strings.Contains(dec.text, "{}") { return true } // word 28BD0000. pop/ldm with no registers (undefined). // we say 'ldmcs sp!, {}', libopcodes says 'popcs {}'. if hasPrefix(text, "ldm") && hasPrefix(dec.text, "pop") && strings.Contains(text, "{}") && strings.Contains(dec.text, "{}") { return true } // word 014640F0. // libopcodes emits #-0 for negative zero; we don't. if strings.Replace(dec.text, "#-0", "#0", -1) == text || strings.Replace(dec.text, ", #-0", "", -1) == text { return true } // word 91EF90F0. we say 'strdls r9, [pc, #0]!' but libopcodes says 'strdls r9, [pc]'. // word D16F60F0. we say 'strdle r6, [pc, #0]!' but libopcodes says 'strdle r6, [pc, #-0]'. if strings.Replace(text, ", #0]!", "]", -1) == strings.Replace(dec.text, ", #-0]", "]", -1) { return true } // word 510F4000. we say apsr, libopcodes says CPSR. if strings.Replace(dec.text, "CPSR", "apsr", -1) == text { return true } // word 06A4B059. // for ssat and usat, libopcodes decodes asr #0 as asr #0 but the manual seems to say it should be asr #32. // There is never an asr #0. if strings.Replace(dec.text, ", asr #0", ", asr #32", -1) == text { return true } if len(dec.enc) >= 4 { raw := binary.LittleEndian.Uint32(dec.enc[:4]) // word 21FFF0B5. // the manual is clear that this is pre-indexed mode (with !) but libopcodes generates post-index (without !). if raw&0x01200000 == 0x01200000 && strings.Replace(text, "!", "", -1) == dec.text { return true } // word C100543E: libopcodes says tst, but no evidence for that. if strings.HasPrefix(dec.text, "tst") && raw&0x0ff00000 != 0x03100000 && raw&0x0ff00000 != 0x01100000 { return true } // word C3203CE8: libopcodes says teq, but no evidence for that. if strings.HasPrefix(dec.text, "teq") && raw&0x0ff00000 != 0x03300000 && raw&0x0ff00000 != 0x01300000 { return true } // word D14C552E: libopcodes says cmp but no evidence for that. if strings.HasPrefix(dec.text, "cmp") && raw&0x0ff00000 != 0x03500000 && raw&0x0ff00000 != 0x01500000 { return true } // word 2166AA4A: libopcodes says cmn but no evidence for that. if strings.HasPrefix(dec.text, "cmn") && raw&0x0ff00000 != 0x03700000 && raw&0x0ff00000 != 0x01700000 { return true } // word E70AEEEF: libopcodes says str but no evidence for that. if strings.HasPrefix(dec.text, "str") && len(dec.text) >= 5 && (dec.text[3] == ' ' || dec.text[5] == ' ') && raw&0x0e500018 != 0x06000000 && raw&0x0e500000 != 0x0400000 { return true } // word B0AF48F4: libopcodes says strd but P=0,W=1 which is unpredictable. if hasPrefix(dec.text, "ldr", "str") && raw&0x01200000 == 0x00200000 { return true } // word B6CC1C76: libopcodes inexplicably says 'uxtab16lt r1, ip, r6, ROR #24' instead of 'uxtab16lt r1, ip, r6, ror #24' if strings.ToLower(dec.text) == text { return true } // word F410FDA1: libopcodes says PLDW but the manual is clear that PLDW is F5/F7, not F4. // word F7D0FB17: libopcodes says PLDW but the manual is clear that PLDW has 0x10 clear if hasPrefix(dec.text, "pld") && raw&0xfd000010 != 0xf5000000 { return true } // word F650FE14: libopcodes says PLI but the manual is clear that PLI has 0x10 clear if hasPrefix(dec.text, "pli") && raw&0xff000010 != 0xf6000000 { return true } } return false } // Instructions known to libopcodes (or xed) but not to us. // Most of these are floating point coprocessor instructions. var unsupported = strings.Fields(` abs acs adf aes asn atn cdp cf cmf cnf cos cps crc32 dvf eret exp fadd fcmp fcpy fcvt fdiv fdv fix fld flt fmac fmd fml fmr fms fmul fmx fneg fnm frd fsit fsq fst fsu fto fui hlt hvc lda ldc ldf lfm lgn log mar mcr mcrr mia mnf mra mrc mrrc mrs msr msr muf mvf nrm pol pow rdf rfc rfe rfs rmf rnd rpw rsf sdiv sev sfm sha1 sha256 sin smc sqt srs stc stf stl suf tan udf udiv urd vfma vfms vfnma vfnms vrint wfc wfs `)