github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go (about) 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 // Copied and simplified from rsc.io/x86/x86asm/objdumpext_test.go. 6 7 package armasm 8 9 import ( 10 "bytes" 11 "debug/elf" 12 "encoding/binary" 13 "fmt" 14 "io" 15 "log" 16 "os" 17 "runtime" 18 "strconv" 19 "strings" 20 "testing" 21 ) 22 23 const objdumpPath = "/usr/local/bin/arm-linux-elf-objdump" 24 25 func testObjdumpARM(t *testing.T, generate func(func([]byte))) { 26 testObjdumpArch(t, generate, ModeARM) 27 } 28 29 func testObjdumpArch(t *testing.T, generate func(func([]byte)), arch Mode) { 30 if testing.Short() { 31 t.Skip("skipping objdump test in short mode") 32 } 33 if runtime.GOOS == "akaros" { 34 t.Skip("skipping objdump test on akaros") 35 } 36 37 if _, err := os.Stat(objdumpPath); err != nil { 38 t.Fatal(err) 39 } 40 41 testExtDis(t, "gnu", arch, objdump, generate, allowedMismatchObjdump) 42 } 43 44 func objdump(ext *ExtDis) error { 45 // File already written with instructions; add ELF header. 46 if ext.Arch == ModeARM { 47 if err := writeELF32(ext.File, ext.Size); err != nil { 48 return err 49 } 50 } else { 51 panic("unknown arch") 52 } 53 54 b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name()) 55 if err != nil { 56 return err 57 } 58 59 var ( 60 nmatch int 61 reading bool 62 next uint32 = start 63 addr uint32 64 encbuf [4]byte 65 enc []byte 66 text string 67 ) 68 flush := func() { 69 if addr == next { 70 if m := pcrel.FindStringSubmatch(text); m != nil { 71 targ, _ := strconv.ParseUint(m[2], 16, 64) 72 text = fmt.Sprintf("%s .%+#x", m[1], int32(uint32(targ)-addr-uint32(len(enc)))) 73 } 74 if strings.HasPrefix(text, "stmia") { 75 text = "stm" + text[5:] 76 } 77 if strings.HasPrefix(text, "stmfd") { 78 text = "stmdb" + text[5:] 79 } 80 if strings.HasPrefix(text, "ldmfd") { 81 text = "ldm" + text[5:] 82 } 83 text = strings.Replace(text, "#0.0", "#0", -1) 84 if text == "undefined" && len(enc) == 4 { 85 text = "error: unknown instruction" 86 enc = nil 87 } 88 if len(enc) == 4 { 89 // prints as word but we want to record bytes 90 enc[0], enc[3] = enc[3], enc[0] 91 enc[1], enc[2] = enc[2], enc[1] 92 } 93 ext.Dec <- ExtInst{addr, encbuf, len(enc), text} 94 encbuf = [4]byte{} 95 enc = nil 96 next += 4 97 } 98 } 99 var textangle = []byte("<.text>:") 100 for { 101 line, err := b.ReadSlice('\n') 102 if err != nil { 103 if err == io.EOF { 104 break 105 } 106 return fmt.Errorf("reading objdump output: %v", err) 107 } 108 if bytes.Contains(line, textangle) { 109 reading = true 110 continue 111 } 112 if !reading { 113 continue 114 } 115 if debug { 116 os.Stdout.Write(line) 117 } 118 if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil { 119 enc = enc1 120 continue 121 } 122 flush() 123 nmatch++ 124 addr, enc, text = parseLine(line, encbuf[:0]) 125 if addr > next { 126 return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line) 127 } 128 } 129 flush() 130 if next != start+uint32(ext.Size) { 131 return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size) 132 } 133 if err := ext.Wait(); err != nil { 134 return fmt.Errorf("exec: %v", err) 135 } 136 137 return nil 138 } 139 140 var ( 141 undefined = []byte("<UNDEFINED>") 142 unpredictable = []byte("<UNPREDICTABLE>") 143 illegalShifter = []byte("<illegal shifter operand>") 144 ) 145 146 func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) { 147 oline := line 148 i := index(line, ":\t") 149 if i < 0 { 150 log.Fatalf("cannot parse disassembly: %q", oline) 151 } 152 x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32) 153 if err != nil { 154 log.Fatalf("cannot parse disassembly: %q", oline) 155 } 156 addr = uint32(x) 157 line = line[i+2:] 158 i = bytes.IndexByte(line, '\t') 159 if i < 0 { 160 log.Fatalf("cannot parse disassembly: %q", oline) 161 } 162 enc, ok := parseHex(line[:i], encstart) 163 if !ok { 164 log.Fatalf("cannot parse disassembly: %q", oline) 165 } 166 line = trimSpace(line[i:]) 167 if bytes.Contains(line, undefined) { 168 text = "undefined" 169 return 170 } 171 if bytes.Contains(line, illegalShifter) { 172 text = "undefined" 173 return 174 } 175 if false && bytes.Contains(line, unpredictable) { 176 text = "unpredictable" 177 return 178 } 179 if i := bytes.IndexByte(line, ';'); i >= 0 { 180 line = trimSpace(line[:i]) 181 } 182 text = string(fixSpace(line)) 183 return 184 } 185 186 func parseContinuation(line []byte, enc []byte) []byte { 187 i := index(line, ":\t") 188 if i < 0 { 189 return nil 190 } 191 line = line[i+1:] 192 enc, _ = parseHex(line, enc) 193 return enc 194 } 195 196 // writeELF32 writes an ELF32 header to the file, 197 // describing a text segment that starts at start 198 // and extends for size bytes. 199 func writeELF32(f *os.File, size int) error { 200 f.Seek(0, 0) 201 var hdr elf.Header32 202 var prog elf.Prog32 203 var sect elf.Section32 204 var buf bytes.Buffer 205 binary.Write(&buf, binary.LittleEndian, &hdr) 206 off1 := buf.Len() 207 binary.Write(&buf, binary.LittleEndian, &prog) 208 off2 := buf.Len() 209 binary.Write(&buf, binary.LittleEndian, §) 210 off3 := buf.Len() 211 buf.Reset() 212 data := byte(elf.ELFDATA2LSB) 213 hdr = elf.Header32{ 214 Ident: [16]byte{0x7F, 'E', 'L', 'F', 1, data, 1}, 215 Type: 2, 216 Machine: uint16(elf.EM_ARM), 217 Version: 1, 218 Entry: start, 219 Phoff: uint32(off1), 220 Shoff: uint32(off2), 221 Flags: 0x05000002, 222 Ehsize: uint16(off1), 223 Phentsize: uint16(off2 - off1), 224 Phnum: 1, 225 Shentsize: uint16(off3 - off2), 226 Shnum: 3, 227 Shstrndx: 2, 228 } 229 binary.Write(&buf, binary.LittleEndian, &hdr) 230 prog = elf.Prog32{ 231 Type: 1, 232 Off: start, 233 Vaddr: start, 234 Paddr: start, 235 Filesz: uint32(size), 236 Memsz: uint32(size), 237 Flags: 5, 238 Align: start, 239 } 240 binary.Write(&buf, binary.LittleEndian, &prog) 241 binary.Write(&buf, binary.LittleEndian, §) // NULL section 242 sect = elf.Section32{ 243 Name: 1, 244 Type: uint32(elf.SHT_PROGBITS), 245 Addr: start, 246 Off: start, 247 Size: uint32(size), 248 Flags: uint32(elf.SHF_ALLOC | elf.SHF_EXECINSTR), 249 Addralign: 4, 250 } 251 binary.Write(&buf, binary.LittleEndian, §) // .text 252 sect = elf.Section32{ 253 Name: uint32(len("\x00.text\x00")), 254 Type: uint32(elf.SHT_STRTAB), 255 Addr: 0, 256 Off: uint32(off2 + (off3-off2)*3), 257 Size: uint32(len("\x00.text\x00.shstrtab\x00")), 258 Addralign: 1, 259 } 260 binary.Write(&buf, binary.LittleEndian, §) 261 buf.WriteString("\x00.text\x00.shstrtab\x00") 262 f.Write(buf.Bytes()) 263 return nil 264 }