aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/pprof
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2016-03-23 17:10:18 -0700
committerIan Lance Taylor <iant@golang.org>2016-03-31 04:05:06 +0000
commitb4117995e3e01a669be737c36033c2393858d555 (patch)
treec01edce64a80a4d284a398d3a94efc0873196113 /src/cmd/pprof
parent4b209dbf0bf3e5fd4cffda1e11f11bf45ddf212d (diff)
downloadgo-b4117995e3e01a669be737c36033c2393858d555.tar.gz
go-b4117995e3e01a669be737c36033c2393858d555.zip
cmd/pprof: use DWARF info to lookup unknown PC addresses
Test to follow in a separate CL that arranges for the runtime package to store non-Go addresses in a CPU profile. Change-Id: I33ce1d66b77340b1e62b54505fc9b1abcec108a9 Reviewed-on: https://go-review.googlesource.com/21055 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/cmd/pprof')
-rw-r--r--src/cmd/pprof/pprof.go95
1 files changed, 88 insertions, 7 deletions
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 2b20f1da77..1c55d05d5d 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -5,6 +5,7 @@
package main
import (
+ "debug/dwarf"
"debug/gosym"
"flag"
"fmt"
@@ -172,6 +173,9 @@ type file struct {
sym []objfile.Sym
file *objfile.File
pcln *gosym.Table
+
+ triedDwarf bool
+ dwarf *dwarf.Data
}
func (f *file) Name() string {
@@ -197,17 +201,94 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
f.pcln = pcln
}
file, line, fn := f.pcln.PCToLine(addr)
- if fn == nil {
- return nil, fmt.Errorf("no line information for PC=%#x", addr)
+ if fn != nil {
+ frame := []plugin.Frame{
+ {
+ Func: fn.Name,
+ File: file,
+ Line: line,
+ },
+ }
+ return frame, nil
+ }
+
+ frames := f.dwarfSourceLine(addr)
+ if frames != nil {
+ return frames, nil
+ }
+
+ return nil, fmt.Errorf("no line information for PC=%#x", addr)
+}
+
+// dwarfSourceLine tries to get file/line information using DWARF.
+// This is for C functions that appear in the profile.
+// Returns nil if there is no information available.
+func (f *file) dwarfSourceLine(addr uint64) []plugin.Frame {
+ if f.dwarf == nil && !f.triedDwarf {
+ // Ignore any error--we don't care exactly why there
+ // is no DWARF info.
+ f.dwarf, _ = f.file.DWARF()
+ f.triedDwarf = true
+ }
+
+ if f.dwarf != nil {
+ r := f.dwarf.Reader()
+ unit, err := r.SeekPC(addr)
+ if err == nil {
+ if frames := f.dwarfSourceLineEntry(r, unit, addr); frames != nil {
+ return frames
+ }
+ }
+ }
+
+ return nil
+}
+
+// dwarfSourceLineEntry tries to get file/line information from a
+// DWARF compilation unit. Returns nil if it doesn't find anything.
+func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []plugin.Frame {
+ lines, err := f.dwarf.LineReader(entry)
+ if err != nil {
+ return nil
+ }
+ var lentry dwarf.LineEntry
+ if err := lines.SeekPC(addr, &lentry); err != nil {
+ return nil
}
- frame := []plugin.Frame{
+
+ // Try to find the function name.
+ name := ""
+FindName:
+ for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
+ if entry.Tag == dwarf.TagSubprogram {
+ ranges, err := f.dwarf.Ranges(entry)
+ if err != nil {
+ return nil
+ }
+ for _, pcs := range ranges {
+ if pcs[0] <= addr && addr < pcs[1] {
+ var ok bool
+ // TODO: AT_linkage_name, AT_MIPS_linkage_name.
+ name, ok = entry.Val(dwarf.AttrName).(string)
+ if ok {
+ break FindName
+ }
+ }
+ }
+ }
+ }
+
+ // TODO: Report inlined functions.
+
+ frames := []plugin.Frame{
{
- Func: fn.Name,
- File: file,
- Line: line,
+ Func: name,
+ File: lentry.File.Name,
+ Line: lentry.Line,
},
}
- return frame, nil
+
+ return frames
}
func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {