1 package x86asm 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "strconv" 10 "strings" 11 "testing" 12 ) 13 14 // xed binary from Intel sde-external-6.22.0-2014-03-06. 15 const xedPath = "/Users/rsc/bin/xed" 16 17 func testXedArch(t *testing.T, arch int, generate func(func([]byte))) { 18 if testing.Short() { 19 t.Skip("skipping xed test in short mode") 20 } 21 if _, err := os.Stat(xedPath); err != nil { 22 t.Skip(err) 23 } 24 25 testExtDis(t, "intel", arch, xed, generate, allowedMismatchXed) 26 } 27 28 func testXed32(t *testing.T, generate func(func([]byte))) { 29 testXedArch(t, 32, generate) 30 } 31 32 func testXed64(t *testing.T, generate func(func([]byte))) { 33 testXedArch(t, 64, generate) 34 } 35 36 func xed(ext *ExtDis) error { 37 b, err := ext.Run(xedPath, fmt.Sprintf("-%d", ext.Arch), "-n", "1G", "-ir", ext.File.Name()) 38 if err != nil { 39 return err 40 } 41 42 nmatch := 0 43 next := uint32(start) 44 var ( 45 addr uint32 46 encbuf [32]byte 47 enc []byte 48 text string 49 ) 50 51 var xedEnd = []byte("# end of text section") 52 var xedEnd1 = []byte("# Errors") 53 54 eof := false 55 for { 56 line, err := b.ReadSlice('\n') 57 if err != nil { 58 if err == io.EOF { 59 break 60 } 61 return fmt.Errorf("reading objdump output: %v", err) 62 } 63 if debug { 64 os.Stdout.Write(line) 65 } 66 if bytes.HasPrefix(line, xedEnd) || bytes.HasPrefix(line, xedEnd1) { 67 eof = true 68 } 69 if eof { 70 continue 71 } 72 nmatch++ 73 addr, enc, text = parseLineXed(line, encbuf[:0]) 74 if addr > next { 75 return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line) 76 } 77 if addr < next { 78 continue 79 } 80 switch text { 81 case "repz": 82 text = "rep" 83 case "repnz": 84 text = "repn" 85 default: 86 text = strings.Replace(text, "repz ", "rep ", -1) 87 text = strings.Replace(text, "repnz ", "repn ", -1) 88 } 89 if m := pcrelw.FindStringSubmatch(text); m != nil { 90 targ, _ := strconv.ParseUint(m[2], 16, 64) 91 text = fmt.Sprintf("%s .%+#x", m[1], int16(uint32(targ)-uint32(uint16(addr))-uint32(len(enc)))) 92 } 93 if m := pcrel.FindStringSubmatch(text); m != nil { 94 targ, _ := strconv.ParseUint(m[2], 16, 64) 95 text = fmt.Sprintf("%s .%+#x", m[1], int32(uint32(targ)-addr-uint32(len(enc)))) 96 } 97 ext.Dec <- ExtInst{addr, encbuf, len(enc), text} 98 encbuf = [32]byte{} 99 enc = nil 100 next += 32 101 } 102 if next != start+uint32(ext.Size) { 103 return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size) 104 } 105 if err := ext.Wait(); err != nil { 106 return fmt.Errorf("exec: %v", err) 107 } 108 109 return nil 110 } 111 112 var ( 113 xedInRaw = []byte("In raw...") 114 xedDots = []byte("...") 115 xdis = []byte("XDIS ") 116 xedError = []byte("ERROR: ") 117 xedNoDecode = []byte("Could not decode at offset: 0x") 118 ) 119 120 func parseLineXed(line []byte, encstart []byte) (addr uint32, enc []byte, text string) { 121 oline := line 122 if bytes.HasPrefix(line, xedInRaw) || bytes.HasPrefix(line, xedDots) { 123 return 0, nil, "" 124 } 125 if bytes.HasPrefix(line, xedError) { 126 i := bytes.IndexByte(line[len(xedError):], ' ') 127 if i < 0 { 128 log.Fatalf("cannot parse error: %q", oline) 129 } 130 errstr := string(line[len(xedError):]) 131 i = bytes.Index(line, xedNoDecode) 132 if i < 0 { 133 log.Fatalf("cannot parse error: %q", oline) 134 } 135 i += len(xedNoDecode) 136 j := bytes.IndexByte(line[i:], ' ') 137 if j < 0 { 138 log.Fatalf("cannot parse error: %q", oline) 139 } 140 x, err := strconv.ParseUint(string(trimSpace(line[i:i+j])), 16, 32) 141 if err != nil { 142 log.Fatalf("cannot parse disassembly: %q", oline) 143 } 144 addr = uint32(x) 145 return addr, nil, errstr 146 } 147 148 if !bytes.HasPrefix(line, xdis) { 149 log.Fatalf("cannot parse disassembly: %q", oline) 150 } 151 152 i := bytes.IndexByte(line, ':') 153 if i < 0 { 154 log.Fatalf("cannot parse disassembly: %q", oline) 155 } 156 x, err := strconv.ParseUint(string(trimSpace(line[len(xdis):i])), 16, 32) 157 if err != nil { 158 log.Fatalf("cannot parse disassembly: %q", oline) 159 } 160 addr = uint32(x) 161 162 // spaces 163 i++ 164 for i < len(line) && line[i] == ' ' { 165 i++ 166 } 167 // instruction class, spaces 168 for i < len(line) && line[i] != ' ' { 169 i++ 170 } 171 for i < len(line) && line[i] == ' ' { 172 i++ 173 } 174 // instruction set, spaces 175 for i < len(line) && line[i] != ' ' { 176 i++ 177 } 178 for i < len(line) && line[i] == ' ' { 179 i++ 180 } 181 182 // hex 183 hexStart := i 184 for i < len(line) && line[i] != ' ' { 185 i++ 186 } 187 hexEnd := i 188 for i < len(line) && line[i] == ' ' { 189 i++ 190 } 191 192 // text 193 textStart := i 194 for i < len(line) && line[i] != '\n' { 195 i++ 196 } 197 textEnd := i 198 199 enc, ok := parseHex(line[hexStart:hexEnd], encstart) 200 if !ok { 201 log.Fatalf("cannot parse disassembly: %q", oline) 202 } 203 204 return addr, enc, string(fixSpace(line[textStart:textEnd])) 205 } 206