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