]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/objdump: rewrite in Go
authorRuss Cox <rsc@golang.org>
Mon, 14 Apr 2014 14:58:49 +0000 (10:58 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 14 Apr 2014 14:58:49 +0000 (10:58 -0400)
Update cmd/dist not to build the C version.
Update cmd/go to install the Go version to the tool directory.

Update #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://golang.org/cl/87580043

src/cmd/dist/build.c
src/cmd/go/pkg.go
src/cmd/objdump/main.c [deleted file]
src/cmd/objdump/main.go [new file with mode: 0644]

index be05b82f19f673cc0a29edd7c32a3bc6e89d1da8..3ef9f6592c8c2d6dc72db94ba4a0019e17305b23 100644 (file)
@@ -1332,7 +1332,6 @@ static char *buildorder[] = {
 
        "misc/pprof",
 
-       "cmd/objdump",
        "cmd/prof",
 
        "cmd/cc",  // must be before c
@@ -1409,7 +1408,6 @@ static char *cleantab[] = {
        "cmd/cc",
        "cmd/gc",
        "cmd/go",       
-       "cmd/objdump",
        "cmd/prof",
        "lib9",
        "libbio",
index 0964008dd8713b1733bb4388afe0d364489b679b..59c5d357e37f3e868bb0683b74b3db17edd6bfb5 100644 (file)
@@ -313,6 +313,7 @@ var goTools = map[string]targetDir{
        "cmd/fix":                              toTool,
        "cmd/link":                             toTool,
        "cmd/nm":                               toTool,
+       "cmd/objdump":                          toTool,
        "cmd/pack":                             toTool,
        "cmd/yacc":                             toTool,
        "code.google.com/p/go.tools/cmd/cover": toTool,
diff --git a/src/cmd/objdump/main.c b/src/cmd/objdump/main.c
deleted file mode 100644 (file)
index b684be7..0000000
+++ /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 (file)
index 0000000..222ee32
--- /dev/null
@@ -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")
+}