summaryrefslogtreecommitdiff
path: root/src/cmd/objdump
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-04-14 10:58:49 -0400
committerRuss Cox <rsc@golang.org>2014-04-14 10:58:49 -0400
commit4fe30da9cc61d4e614eb1d00a2bb7277302e7d03 (patch)
treec909ac021e89dfa76c89a27987b38e7cca9de897 /src/cmd/objdump
parenteefdadea3fd0782d3146598ac3e332347f4cf311 (diff)
downloadgo-4fe30da9cc61d4e614eb1d00a2bb7277302e7d03.tar.gz
cmd/objdump: rewrite in Go
Update cmd/dist not to build the C version. Update cmd/go to install the Go version to the tool directory. Update issue 7452 This is the basic logic needed for objdump, and it works well enough to support the pprof list and weblist commands. A real disassembler needs to be added in order to support the pprof disasm command and the per-line assembly displays in weblist. That's still to come. Probably objdump will move to go.tools when the disassembler is added, but it can stay here for now. LGTM=minux.ma R=golang-codereviews, minux.ma CC=golang-codereviews, iant, r https://codereview.appspot.com/87580043
Diffstat (limited to 'src/cmd/objdump')
-rw-r--r--src/cmd/objdump/main.c68
-rw-r--r--src/cmd/objdump/main.go162
2 files changed, 162 insertions, 68 deletions
diff --git a/src/cmd/objdump/main.c b/src/cmd/objdump/main.c
deleted file mode 100644
index b684be7fb..000000000
--- a/src/cmd/objdump/main.c
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * objdump simulation - only enough to make pprof work on Macs
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-void
-usage(void)
-{
- fprint(2, "usage: objdump binary start stop\n");
- fprint(2, "Disassembles binary from PC start up to stop.\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd, n;
- uvlong pc, start, stop;
- Fhdr fhdr;
- Biobuf bout;
- char buf[1024];
- Map *text;
-
- ARGBEGIN{
- default:
- usage();
- }ARGEND
-
- if(argc != 3)
- usage();
- start = strtoull(argv[1], 0, 16);
- stop = strtoull(argv[2], 0, 16);
-
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
- text = loadmap(nil, fd, &fhdr);
- if(text == nil)
- sysfatal("loadmap: %r");
-
- Binit(&bout, 1, OWRITE);
- for(pc=start; pc<stop; ) {
- if(fileline(buf, sizeof buf, pc))
- Bprint(&bout, "%s\n", buf);
- buf[0] = '\0';
- machdata->das(text, pc, 0, buf, sizeof buf);
- Bprint(&bout, " %llx: %s\n", pc, buf);
- n = machdata->instsize(text, pc);
- if(n <= 0)
- break;
- pc += n;
- }
- Bflush(&bout);
- exits(0);
-}
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
new file mode 100644
index 000000000..222ee32f3
--- /dev/null
+++ b/src/cmd/objdump/main.go
@@ -0,0 +1,162 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// objdump simulation - only enough to make pprof work on Macs
+
+package main
+
+import (
+ "bufio"
+ "debug/elf"
+ "debug/gosym"
+ "debug/macho"
+ "debug/pe"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "strconv"
+)
+
+func printUsage(w *os.File) {
+ fmt.Fprintf(w, "usage: objdump binary start end\n")
+ fmt.Fprintf(w, "disassembles binary from start PC to end PC.\n")
+}
+
+func usage() {
+ printUsage(os.Stderr)
+ os.Exit(2)
+}
+
+func main() {
+ log.SetFlags(0)
+ log.SetPrefix("objdump: ")
+
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 3 {
+ usage()
+ }
+
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ textStart, textData, symtab, pclntab, err := loadTables(f)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ pcln := gosym.NewLineTable(pclntab, textStart)
+ tab, err := gosym.NewTable(symtab, pcln)
+ if err != nil {
+ log.Fatalf("reading %s: %v", flag.Arg(0), err)
+ }
+
+ 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 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
+ }
+ 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)
+ if file != spanFile || line != spanLine || fn != spanFn {
+ flush(pc)
+ spanPC, spanFile, spanLine, spanFn = pc, file, line, fn
+ }
+ }
+ flush(end)
+
+ stdout.Flush()
+}
+
+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()
+ }
+ if sect := obj.Section(".gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ if sect := obj.Section(".gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ 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()
+ }
+ if sect := obj.Section("__gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ if sect := obj.Section("__gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ 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()
+ }
+ if sect := obj.Section(".gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ if sect := obj.Section(".gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, nil, err
+ }
+ }
+ return textStart, textData, symtab, pclntab, nil
+ }
+
+ return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format")
+}