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
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
163 i++
164 for i < len(line) && line[i] == ' ' {
165 i++
166 }
167
168 for i < len(line) && line[i] != ' ' {
169 i++
170 }
171 for i < len(line) && line[i] == ' ' {
172 i++
173 }
174
175 for i < len(line) && line[i] != ' ' {
176 i++
177 }
178 for i < len(line) && line[i] == ' ' {
179 i++
180 }
181
182
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
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
View as plain text