github.com/aloncn/graphics-go@v0.0.1/src/cmd/pprof/pprof.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "debug/gosym" 9 "flag" 10 "fmt" 11 "os" 12 "regexp" 13 "strings" 14 "sync" 15 16 "cmd/internal/objfile" 17 "cmd/pprof/internal/commands" 18 "cmd/pprof/internal/driver" 19 "cmd/pprof/internal/fetch" 20 "cmd/pprof/internal/plugin" 21 "cmd/pprof/internal/profile" 22 "cmd/pprof/internal/symbolizer" 23 "cmd/pprof/internal/symbolz" 24 ) 25 26 func main() { 27 var extraCommands map[string]*commands.Command // no added Go-specific commands 28 if err := driver.PProf(flags{}, fetch.Fetcher, symbolize, new(objTool), plugin.StandardUI(), extraCommands); err != nil { 29 fmt.Fprintf(os.Stderr, "%v\n", err) 30 os.Exit(2) 31 } 32 } 33 34 // symbolize attempts to symbolize profile p. 35 // If the source is a local binary, it tries using symbolizer and obj. 36 // If the source is a URL, it fetches symbol information using symbolz. 37 func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error { 38 remote, local := true, true 39 for _, o := range strings.Split(strings.ToLower(mode), ":") { 40 switch o { 41 case "none", "no": 42 return nil 43 case "local": 44 remote, local = false, true 45 case "remote": 46 remote, local = true, false 47 default: 48 ui.PrintErr("ignoring unrecognized symbolization option: " + mode) 49 ui.PrintErr("expecting -symbolize=[local|remote|none][:force]") 50 fallthrough 51 case "", "force": 52 // Ignore these options, -force is recognized by symbolizer.Symbolize 53 } 54 } 55 56 var err error 57 if local { 58 // Symbolize using binutils. 59 if err = symbolizer.Symbolize(mode, p, obj, ui); err == nil { 60 return nil 61 } 62 } 63 if remote { 64 err = symbolz.Symbolize(source, fetch.PostURL, p) 65 } 66 return err 67 } 68 69 // flags implements the driver.FlagPackage interface using the builtin flag package. 70 type flags struct { 71 } 72 73 func (flags) Bool(o string, d bool, c string) *bool { 74 return flag.Bool(o, d, c) 75 } 76 77 func (flags) Int(o string, d int, c string) *int { 78 return flag.Int(o, d, c) 79 } 80 81 func (flags) Float64(o string, d float64, c string) *float64 { 82 return flag.Float64(o, d, c) 83 } 84 85 func (flags) String(o, d, c string) *string { 86 return flag.String(o, d, c) 87 } 88 89 func (flags) Parse(usage func()) []string { 90 flag.Usage = usage 91 flag.Parse() 92 args := flag.Args() 93 if len(args) == 0 { 94 usage() 95 } 96 return args 97 } 98 99 func (flags) ExtraUsage() string { 100 return "" 101 } 102 103 // objTool implements plugin.ObjTool using Go libraries 104 // (instead of invoking GNU binutils). 105 type objTool struct { 106 mu sync.Mutex 107 disasmCache map[string]*objfile.Disasm 108 } 109 110 func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) { 111 of, err := objfile.Open(name) 112 if err != nil { 113 return nil, err 114 } 115 f := &file{ 116 name: name, 117 file: of, 118 } 119 return f, nil 120 } 121 122 func (*objTool) Demangle(names []string) (map[string]string, error) { 123 // No C++, nothing to demangle. 124 return make(map[string]string), nil 125 } 126 127 func (t *objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { 128 d, err := t.cachedDisasm(file) 129 if err != nil { 130 return nil, err 131 } 132 var asm []plugin.Inst 133 d.Decode(start, end, func(pc, size uint64, file string, line int, text string) { 134 asm = append(asm, plugin.Inst{Addr: pc, File: file, Line: line, Text: text}) 135 }) 136 return asm, nil 137 } 138 139 func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) { 140 t.mu.Lock() 141 defer t.mu.Unlock() 142 if t.disasmCache == nil { 143 t.disasmCache = make(map[string]*objfile.Disasm) 144 } 145 d := t.disasmCache[file] 146 if d != nil { 147 return d, nil 148 } 149 f, err := objfile.Open(file) 150 if err != nil { 151 return nil, err 152 } 153 d, err = f.Disasm() 154 f.Close() 155 if err != nil { 156 return nil, err 157 } 158 t.disasmCache[file] = d 159 return d, nil 160 } 161 162 func (*objTool) SetConfig(config string) { 163 // config is usually used to say what binaries to invoke. 164 // Ignore entirely. 165 } 166 167 // file implements plugin.ObjFile using Go libraries 168 // (instead of invoking GNU binutils). 169 // A file represents a single executable being analyzed. 170 type file struct { 171 name string 172 sym []objfile.Sym 173 file *objfile.File 174 pcln *gosym.Table 175 } 176 177 func (f *file) Name() string { 178 return f.name 179 } 180 181 func (f *file) Base() uint64 { 182 // No support for shared libraries. 183 return 0 184 } 185 186 func (f *file) BuildID() string { 187 // No support for build ID. 188 return "" 189 } 190 191 func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) { 192 if f.pcln == nil { 193 pcln, err := f.file.PCLineTable() 194 if err != nil { 195 return nil, err 196 } 197 f.pcln = pcln 198 } 199 file, line, fn := f.pcln.PCToLine(addr) 200 if fn == nil { 201 return nil, fmt.Errorf("no line information for PC=%#x", addr) 202 } 203 frame := []plugin.Frame{ 204 { 205 Func: fn.Name, 206 File: file, 207 Line: line, 208 }, 209 } 210 return frame, nil 211 } 212 213 func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) { 214 if f.sym == nil { 215 sym, err := f.file.Symbols() 216 if err != nil { 217 return nil, err 218 } 219 f.sym = sym 220 } 221 var out []*plugin.Sym 222 for _, s := range f.sym { 223 if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) { 224 out = append(out, &plugin.Sym{ 225 Name: []string{s.Name}, 226 File: f.name, 227 Start: s.Addr, 228 End: s.Addr + uint64(s.Size) - 1, 229 }) 230 } 231 } 232 return out, nil 233 } 234 235 func (f *file) Close() error { 236 f.file.Close() 237 return nil 238 }