Index: src/cmd/pprof/pprof.go |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/cmd/pprof/pprof.go |
@@ -0,0 +1,202 @@ |
+// Copyright 2014 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. |
+ |
+package main |
+ |
+import ( |
+ "debug/gosym" |
+ "flag" |
+ "fmt" |
+ "os" |
+ "regexp" |
+ "strings" |
+ |
+ "cmd/internal/objfile" |
+ "cmd/pprof/internal/commands" |
+ "cmd/pprof/internal/driver" |
+ "cmd/pprof/internal/fetch" |
+ "cmd/pprof/internal/plugin" |
+ "cmd/pprof/internal/profile" |
+ "cmd/pprof/internal/symbolizer" |
+ "cmd/pprof/internal/symbolz" |
+) |
+ |
+func main() { |
+ var extraCommands map[string]*commands.Command // no added Go-specific commands |
+ if err := driver.PProf(flags{}, fetch.Fetcher, symbolize, new(objTool), plugin.StandardUI(), extraCommands); err != nil { |
+ fmt.Fprintf(os.Stderr, "%v\n", err) |
+ } |
+} |
+ |
+// symbolize attempts to symbolize profile p. |
+// If the source is a local binary, it tries using symbolizer and obj. |
+// If the source is a URL, it fetches symbol information using symbolz. |
+func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error { |
+ remote, local := true, true |
+ for _, o := range strings.Split(strings.ToLower(mode), ":") { |
+ switch o { |
+ case "none", "no": |
+ return nil |
+ case "local": |
+ remote, local = false, true |
+ case "remote": |
+ remote, local = true, false |
+ default: |
+ ui.PrintErr("ignoring unrecognized symbolization option: " + mode) |
+ ui.PrintErr("expecting -symbolize=[local|remote|none][:force]") |
+ fallthrough |
+ case "", "force": |
+ // Ignore these options, -force is recognized by symbolizer.Symbolize |
+ } |
+ } |
+ |
+ var err error |
+ if local { |
+ // Symbolize using binutils. |
+ if err = symbolizer.Symbolize(mode, p, obj, ui); err == nil { |
+ return nil |
+ } |
+ } |
+ if remote { |
+ err = symbolz.Symbolize(source, fetch.PostURL, p) |
+ } |
+ return err |
+} |
+ |
+// flags implements the driver.FlagPackage interface using the builtin flag package. |
+type flags struct { |
+} |
+ |
+func (flags) Bool(o string, d bool, c string) *bool { |
+ return flag.Bool(o, d, c) |
+} |
+ |
+func (flags) Int(o string, d int, c string) *int { |
+ return flag.Int(o, d, c) |
+} |
+ |
+func (flags) Float64(o string, d float64, c string) *float64 { |
+ return flag.Float64(o, d, c) |
+} |
+ |
+func (flags) String(o, d, c string) *string { |
+ return flag.String(o, d, c) |
+} |
+ |
+func (flags) Parse(usage func()) []string { |
+ flag.Usage = usage |
+ flag.Parse() |
+ args := flag.Args() |
+ if len(args) == 0 { |
+ usage() |
+ } |
+ return args |
+} |
+ |
+func (flags) ExtraUsage() string { |
+ return "" |
+} |
+ |
+// objTool implements plugin.ObjTool using Go libraries |
+// (instead of invoking GNU binutils). |
+type objTool struct{} |
+ |
+func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) { |
+ of, err := objfile.Open(name) |
+ if err != nil { |
+ return nil, err |
+ } |
+ f := &file{ |
+ name: name, |
+ file: of, |
+ } |
+ return f, nil |
+} |
+ |
+func (*objTool) Demangle(names []string) (map[string]string, error) { |
+ // No C++, nothing to demangle. |
+ return make(map[string]string), nil |
+} |
+ |
+func (*objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { |
+ return nil, fmt.Errorf("disassembly not supported") |
+} |
+ |
+func (*objTool) SetConfig(config string) { |
+ // config is usually used to say what binaries to invoke. |
+ // Ignore entirely. |
+} |
+ |
+// file implements plugin.ObjFile using Go libraries |
+// (instead of invoking GNU binutils). |
+// A file represents a single executable being analyzed. |
+type file struct { |
+ name string |
+ sym []objfile.Sym |
+ file *objfile.File |
+ pcln *gosym.Table |
+} |
+ |
+func (f *file) Name() string { |
+ return f.name |
+} |
+ |
+func (f *file) Base() uint64 { |
+ // No support for shared libraries. |
+ return 0 |
+} |
+ |
+func (f *file) BuildID() string { |
+ // No support for build ID. |
+ return "" |
+} |
+ |
+func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) { |
+ if f.pcln == nil { |
+ pcln, err := f.file.PCLineTable() |
+ if err != nil { |
+ return nil, err |
+ } |
+ f.pcln = pcln |
+ } |
+ file, line, fn := f.pcln.PCToLine(addr) |
+ if fn == nil { |
+ return nil, fmt.Errorf("no line information for PC=%#x", addr) |
+ } |
+ frame := []plugin.Frame{ |
+ { |
+ Func: fn.Name, |
+ File: file, |
+ Line: line, |
+ }, |
+ } |
+ return frame, nil |
+} |
+ |
+func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) { |
+ if f.sym == nil { |
+ sym, err := f.file.Symbols() |
+ if err != nil { |
+ return nil, err |
+ } |
+ f.sym = sym |
+ } |
+ var out []*plugin.Sym |
+ for _, s := range f.sym { |
+ if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) { |
+ out = append(out, &plugin.Sym{ |
+ Name: []string{s.Name}, |
+ File: f.name, |
+ Start: s.Addr, |
+ End: s.Addr + uint64(s.Size) - 1, |
+ }) |
+ } |
+ } |
+ return out, nil |
+} |
+ |
+func (f *file) Close() error { |
+ f.file.Close() |
+ return nil |
+} |