OLD | NEW |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Objdump disassembles executable files. | 5 // Objdump disassembles executable files. |
6 // | 6 // |
7 // Usage: | 7 // Usage: |
8 // | 8 // |
9 // go tool objdump [-s symregexp] binary | 9 // go tool objdump [-s symregexp] binary |
10 // | 10 // |
(...skipping 24 matching lines...) Expand all Loading... |
35 package main | 35 package main |
36 | 36 |
37 import ( | 37 import ( |
38 "bufio" | 38 "bufio" |
39 "bytes" | 39 "bytes" |
40 "debug/elf" | 40 "debug/elf" |
41 "debug/gosym" | 41 "debug/gosym" |
42 "debug/macho" | 42 "debug/macho" |
43 "debug/pe" | 43 "debug/pe" |
44 "debug/plan9obj" | 44 "debug/plan9obj" |
| 45 "encoding/binary" |
45 "flag" | 46 "flag" |
46 "fmt" | 47 "fmt" |
47 "io" | 48 "io" |
48 "log" | 49 "log" |
49 "os" | 50 "os" |
50 "regexp" | 51 "regexp" |
51 "sort" | 52 "sort" |
52 "strconv" | 53 "strconv" |
53 "strings" | 54 "strings" |
54 "text/tabwriter" | 55 "text/tabwriter" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 } | 129 } |
129 | 130 |
130 pcln := gosym.NewLineTable(pclntab, textStart) | 131 pcln := gosym.NewLineTable(pclntab, textStart) |
131 tab, err := gosym.NewTable(symtab, pcln) | 132 tab, err := gosym.NewTable(symtab, pcln) |
132 if err != nil { | 133 if err != nil { |
133 log.Fatalf("reading %s: %v", flag.Arg(0), err) | 134 log.Fatalf("reading %s: %v", flag.Arg(0), err) |
134 } | 135 } |
135 | 136 |
136 if flag.NArg() == 1 { | 137 if flag.NArg() == 1 { |
137 // disassembly of entire object - our format | 138 // disassembly of entire object - our format |
138 » » dump(tab, lookup, disasm, syms, textData, textStart) | 139 » » dump(tab, lookup, disasm, goarch, syms, textData, textStart) |
139 os.Exit(exitCode) | 140 os.Exit(exitCode) |
140 } | 141 } |
141 | 142 |
142 // disassembly of specific piece of object - gnu objdump format for ppro
f | 143 // disassembly of specific piece of object - gnu objdump format for ppro
f |
143 gnuDump(tab, lookup, disasm, textData, textStart) | 144 gnuDump(tab, lookup, disasm, textData, textStart) |
144 os.Exit(exitCode) | 145 os.Exit(exitCode) |
145 } | 146 } |
146 | 147 |
147 // base returns the final element in the path. | 148 // base returns the final element in the path. |
148 // It works on both Windows and Unix paths. | 149 // It works on both Windows and Unix paths. |
149 func base(path string) string { | 150 func base(path string) string { |
150 path = path[strings.LastIndex(path, "/")+1:] | 151 path = path[strings.LastIndex(path, "/")+1:] |
151 path = path[strings.LastIndex(path, `\`)+1:] | 152 path = path[strings.LastIndex(path, `\`)+1:] |
152 return path | 153 return path |
153 } | 154 } |
154 | 155 |
155 func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, syms []Sym, te
xtData []byte, textStart uint64) { | 156 func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string,
syms []Sym, textData []byte, textStart uint64) { |
156 stdout := bufio.NewWriter(os.Stdout) | 157 stdout := bufio.NewWriter(os.Stdout) |
157 defer stdout.Flush() | 158 defer stdout.Flush() |
158 | 159 |
159 printed := false | 160 printed := false |
160 for _, sym := range syms { | 161 for _, sym := range syms { |
161 if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sy
m.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(s
ym.Name) { | 162 if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sy
m.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(s
ym.Name) { |
162 continue | 163 continue |
163 } | 164 } |
164 if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint6
4(sym.Size) > textStart+uint64(len(textData)) { | 165 if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint6
4(sym.Size) > textStart+uint64(len(textData)) { |
165 break | 166 break |
166 } | 167 } |
167 if printed { | 168 if printed { |
168 fmt.Fprintf(stdout, "\n") | 169 fmt.Fprintf(stdout, "\n") |
169 } else { | 170 } else { |
170 printed = true | 171 printed = true |
171 } | 172 } |
172 file, _, _ := tab.PCToLine(sym.Addr) | 173 file, _, _ := tab.PCToLine(sym.Addr) |
173 fmt.Fprintf(stdout, "TEXT %s(SB) %s\n", sym.Name, file) | 174 fmt.Fprintf(stdout, "TEXT %s(SB) %s\n", sym.Name, file) |
174 tw := tabwriter.NewWriter(stdout, 1, 8, 1, '\t', 0) | 175 tw := tabwriter.NewWriter(stdout, 1, 8, 1, '\t', 0) |
175 start := sym.Addr | 176 start := sym.Addr |
176 end := sym.Addr + uint64(sym.Size) | 177 end := sym.Addr + uint64(sym.Size) |
177 for pc := start; pc < end; { | 178 for pc := start; pc < end; { |
178 i := pc - textStart | 179 i := pc - textStart |
179 text, size := disasm(textData[i:end-textStart], pc, look
up) | 180 text, size := disasm(textData[i:end-textStart], pc, look
up) |
180 file, line, _ := tab.PCToLine(pc) | 181 file, line, _ := tab.PCToLine(pc) |
181 » » » fmt.Fprintf(tw, "\t%s:%d\t%#x\t%x\t%s\n", base(file), li
ne, pc, textData[i:i+uint64(size)], text) | 182 |
| 183 » » » // ARM is word-based, so show actual word hex, not byte
hex. |
| 184 » » » // Since ARM is little endian, they're different. |
| 185 » » » if goarch == "arm" && size == 4 { |
| 186 » » » » fmt.Fprintf(tw, "\t%s:%d\t%#x\t%08x\t%s\n", base
(file), line, pc, binary.LittleEndian.Uint32(textData[i:i+uint64(size)]), text) |
| 187 » » » } else { |
| 188 » » » » fmt.Fprintf(tw, "\t%s:%d\t%#x\t%x\t%s\n", base(f
ile), line, pc, textData[i:i+uint64(size)], text) |
| 189 » » » } |
182 pc += uint64(size) | 190 pc += uint64(size) |
183 } | 191 } |
184 tw.Flush() | 192 tw.Flush() |
185 } | 193 } |
186 } | 194 } |
187 | 195 |
188 func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) { | 196 func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) { |
189 return disasm_x86(code, pc, lookup, 32) | 197 return disasm_x86(code, pc, lookup, 32) |
190 } | 198 } |
191 | 199 |
192 func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) { | 200 func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) { |
193 return disasm_x86(code, pc, lookup, 64) | 201 return disasm_x86(code, pc, lookup, 64) |
194 } | 202 } |
195 | 203 |
196 func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, in
t) { | 204 func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, in
t) { |
197 inst, err := x86_Decode(code, 64) | 205 inst, err := x86_Decode(code, 64) |
198 var text string | 206 var text string |
199 size := inst.Len | 207 size := inst.Len |
200 if err != nil || size == 0 || inst.Op == 0 { | 208 if err != nil || size == 0 || inst.Op == 0 { |
201 size = 1 | 209 size = 1 |
202 text = "?" | 210 text = "?" |
203 } else { | 211 } else { |
204 text = x86_plan9Syntax(inst, pc, lookup) | 212 text = x86_plan9Syntax(inst, pc, lookup) |
205 } | 213 } |
206 return text, size | 214 return text, size |
207 } | 215 } |
208 | 216 |
| 217 type textReader struct { |
| 218 code []byte |
| 219 pc uint64 |
| 220 } |
| 221 |
| 222 func (r textReader) ReadAt(data []byte, off int64) (n int, err error) { |
| 223 if off < 0 || uint64(off) < r.pc { |
| 224 return 0, io.EOF |
| 225 } |
| 226 d := uint64(off) - r.pc |
| 227 if d >= uint64(len(r.code)) { |
| 228 return 0, io.EOF |
| 229 } |
| 230 n = copy(data, r.code[d:]) |
| 231 if n < len(data) { |
| 232 err = io.ErrUnexpectedEOF |
| 233 } |
| 234 return |
| 235 } |
| 236 |
209 func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) { | 237 func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) { |
210 » /* | 238 » inst, err := arm_Decode(code, arm_ModeARM) |
211 » » inst, size, err := arm_Decode(code, 64) | 239 » var text string |
212 » » var text string | 240 » size := inst.Len |
213 » » if err != nil || size == 0 || inst.Op == 0 { | 241 » if err != nil || size == 0 || inst.Op == 0 { |
214 » » » size = 1 | 242 » » size = 4 |
215 » » » text = "?" | 243 » » text = "?" |
216 » » } else { | 244 » } else { |
217 » » » text = arm_plan9Syntax(inst, pc, lookup) | 245 » » text = arm_plan9Syntax(inst, pc, lookup, textReader{code, pc}) |
218 » » } | 246 » } |
219 » » return text, size | 247 » return text, size |
220 » */ | |
221 » return "?", 4 | |
222 } | 248 } |
223 | 249 |
224 var disasms = map[string]disasmFunc{ | 250 var disasms = map[string]disasmFunc{ |
225 "386": disasm_386, | 251 "386": disasm_386, |
226 "amd64": disasm_amd64, | 252 "amd64": disasm_amd64, |
227 "arm": disasm_arm, | 253 "arm": disasm_arm, |
228 } | 254 } |
229 | 255 |
230 func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []
byte, textStart uint64) { | 256 func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []
byte, textStart uint64) { |
231 start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 1
6, 64) | 257 start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 1
6, 64) |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips | 510 {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips |
485 {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm | 511 {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm |
486 {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 | 512 {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 |
487 } | 513 } |
488 | 514 |
489 type byAddr []Sym | 515 type byAddr []Sym |
490 | 516 |
491 func (x byAddr) Len() int { return len(x) } | 517 func (x byAddr) Len() int { return len(x) } |
492 func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | 518 func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } |
493 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } | 519 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } |
OLD | NEW |