diff options
author | Russ Cox <rsc@golang.org> | 2014-04-14 10:58:49 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-04-14 10:58:49 -0400 |
commit | 4fe30da9cc61d4e614eb1d00a2bb7277302e7d03 (patch) | |
tree | c909ac021e89dfa76c89a27987b38e7cca9de897 /src/cmd/objdump | |
parent | eefdadea3fd0782d3146598ac3e332347f4cf311 (diff) | |
download | go-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.c | 68 | ||||
-rw-r--r-- | src/cmd/objdump/main.go | 162 |
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") +} |