Index: src/cmd/objdump/main.go |
=================================================================== |
copy from src/cmd/addr2line/main.go |
copy to src/cmd/objdump/main.go |
--- a/src/cmd/addr2line/main.go |
+++ b/src/cmd/objdump/main.go |
@@ -2,7 +2,7 @@ |
// Use of this source code is governed by a BSD-style |
// license that can be found in the LICENSE file. |
-// addr2line simulation - only enough to make pprof work on Macs |
+// objdump simulation - only enough to make pprof work on Macs |
package main |
@@ -17,14 +17,11 @@ |
"log" |
"os" |
"strconv" |
- "strings" |
) |
func printUsage(w *os.File) { |
- fmt.Fprintf(w, "usage: addr2line binary\n") |
- fmt.Fprintf(w, "reads addresses from standard input and writes two lines for each:\n") |
- fmt.Fprintf(w, "\tfunction name\n") |
- fmt.Fprintf(w, "\tfile:line\n") |
+ fmt.Fprintf(w, "usage: objdump binary start end\n") |
+ fmt.Fprintf(w, "disassembles binary from start PC to end PC.\n") |
r
2014/04/15 19:41:19
tell me what base or notation is used for the PC
|
} |
func usage() { |
@@ -34,17 +31,11 @@ |
func main() { |
log.SetFlags(0) |
- log.SetPrefix("addr2line: ") |
- |
- // pprof expects this behavior when checking for addr2line |
- if len(os.Args) > 1 && os.Args[1] == "--help" { |
- printUsage(os.Stdout) |
- os.Exit(0) |
- } |
+ log.SetPrefix("objdump: ") |
flag.Usage = usage |
flag.Parse() |
- if flag.NArg() != 1 { |
+ if flag.NArg() != 3 { |
usage() |
} |
@@ -53,7 +44,7 @@ |
log.Fatal(err) |
} |
- textStart, symtab, pclntab, err := loadTables(f) |
+ textStart, textData, symtab, pclntab, err := loadTables(f) |
if err != nil { |
log.Fatalf("reading %s: %v", flag.Arg(0), err) |
} |
@@ -64,84 +55,108 @@ |
log.Fatalf("reading %s: %v", flag.Arg(0), err) |
} |
- stdin := bufio.NewScanner(os.Stdin) |
+ start, err := strconv.ParseUint(flag.Arg(1), 0, 64) |
+ if err != nil { |
+ log.Fatalf("invalid start PC: %v", err) |
+ } |
+ end, err := strconv.ParseUint(flag.Arg(2), 0, 64) |
+ if err != nil { |
+ log.Fatalf("invalid end PC: %v", err) |
+ } |
+ |
stdout := bufio.NewWriter(os.Stdout) |
- for stdin.Scan() { |
- p := stdin.Text() |
- if strings.Contains(p, ":") { |
- // Reverse translate file:line to pc. |
- // This was an extension in the old C version of 'go tool addr2line' |
- // and is probably not used by anyone, but recognize the syntax. |
- // We don't have an implementation. |
- fmt.Fprintf(stdout, "!reverse translation not implemented\n") |
- continue |
+ // For now, find spans of same PC/line/fn and |
+ // emit them as having dummy instructions. |
+ var ( |
+ spanPC uint64 |
+ spanFile string |
+ spanLine int |
+ spanFn *gosym.Func |
+ ) |
+ |
+ flush := func(endPC uint64) { |
+ if spanPC == 0 { |
+ return |
} |
- pc, _ := strconv.ParseUint(p, 16, 64) |
+ fmt.Fprintf(stdout, "%s:%d\n", spanFile, spanLine) |
+ for pc := spanPC; pc < endPC; pc++ { |
+ // TODO(rsc): Disassemble instructions here. |
+ if textStart <= pc && pc-textStart < uint64(len(textData)) { |
+ fmt.Fprintf(stdout, " %x: byte %#x\n", pc, textData[pc-textStart]) |
+ } else { |
+ fmt.Fprintf(stdout, " %x: ?\n", pc) |
+ } |
+ } |
+ spanPC = 0 |
+ } |
+ |
+ for pc := start; pc < end; pc++ { |
file, line, fn := tab.PCToLine(pc) |
- name := "?" |
- if fn != nil { |
- name = fn.Name |
- } else { |
- file = "?" |
- line = 0 |
+ if file != spanFile || line != spanLine || fn != spanFn { |
+ flush(pc) |
+ spanPC, spanFile, spanLine, spanFn = pc, file, line, fn |
} |
- fmt.Fprintf(stdout, "%s\n%s:%d\n", name, file, line) |
} |
+ flush(end) |
+ |
stdout.Flush() |
} |
-func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) { |
+func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) { |
if obj, err := elf.NewFile(f); err == nil { |
if sect := obj.Section(".text"); sect != nil { |
textStart = sect.Addr |
+ textData, _ = sect.Data() |
iant
2014/04/14 15:39:56
Don't ignore the error return here, you'll just cr
rsc
2014/04/14 16:39:15
I don't believe I will. textData will be an empty
|
} |
if sect := obj.Section(".gosymtab"); sect != nil { |
if symtab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
if sect := obj.Section(".gopclntab"); sect != nil { |
if pclntab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
- return textStart, symtab, pclntab, nil |
+ return textStart, textData, symtab, pclntab, nil |
} |
if obj, err := macho.NewFile(f); err == nil { |
if sect := obj.Section("__text"); sect != nil { |
textStart = sect.Addr |
+ textData, _ = sect.Data() |
iant
2014/04/14 15:39:56
Don't ignore error return.
|
} |
if sect := obj.Section("__gosymtab"); sect != nil { |
if symtab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
if sect := obj.Section("__gopclntab"); sect != nil { |
if pclntab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
- return textStart, symtab, pclntab, nil |
+ return textStart, textData, symtab, pclntab, nil |
} |
if obj, err := pe.NewFile(f); err == nil { |
if sect := obj.Section(".text"); sect != nil { |
textStart = uint64(sect.VirtualAddress) |
+ textData, _ = sect.Data() |
iant
2014/04/14 15:39:56
Don't ignore error return.
|
} |
if sect := obj.Section(".gosymtab"); sect != nil { |
if symtab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
if sect := obj.Section(".gopclntab"); sect != nil { |
if pclntab, err = sect.Data(); err != nil { |
- return 0, nil, nil, err |
+ return 0, nil, nil, nil, err |
} |
} |
- return textStart, symtab, pclntab, nil |
+ return textStart, textData, symtab, pclntab, nil |
} |
- return 0, nil, nil, fmt.Errorf("unrecognized binary format") |
+ return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format") |
} |