aboutsummaryrefslogtreecommitdiff
path: root/src/debug/dwarf/entry.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2016-03-16 14:15:54 -0700
committerIan Lance Taylor <iant@golang.org>2016-03-22 14:06:09 +0000
commitd1b8871f13203cd99d5e7d686170f0e266760084 (patch)
tree7458f93ff93d8c7b849eab786932a1682657337b /src/debug/dwarf/entry.go
parent77f4b773e72b0840a1ce0b314cba44dff9fbaf31 (diff)
downloadgo-d1b8871f13203cd99d5e7d686170f0e266760084.tar.xz
debug/dwarf: add Reader.SeekPC and Data.Ranges
These new methods help find the compilation unit to pass to the LineReader method in order to find the line information for a PC. The Ranges method also helps identify the specific function for a PC, needed to determine the function name. This uses the .debug.ranges section if necessary, and changes the object file format packages to pass in the section contents if available. Change-Id: I5ebc3d27faaf1a126ffb17a1e6027efdf64af836 Reviewed-on: https://go-review.googlesource.com/20769 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/debug/dwarf/entry.go')
-rw-r--r--src/debug/dwarf/entry.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index 6f72005e72..80bf14cb22 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -636,3 +636,123 @@ func (r *Reader) clone() typeReader {
func (r *Reader) offset() Offset {
return r.b.off
}
+
+// SeekPC returns the Entry for the compilation unit that includes pc,
+// and positions the reader to read the children of that unit. If pc
+// is not covered by any unit, SeekPC returns ErrUnknownPC and the
+// position of the reader is undefined.
+//
+// Because compilation units can describe multiple regions of the
+// executable, in the worst case SeekPC must search through all the
+// ranges in all the compilation units. Each call to SeekPC starts the
+// search at the compilation unit of the last call, so in general
+// looking up a series of PCs will be faster if they are sorted. If
+// the caller wishes to do repeated fast PC lookups, it should build
+// an appropriate index using the Ranges method.
+func (r *Reader) SeekPC(pc uint64) (*Entry, error) {
+ unit := r.unit
+ for i := 0; i < len(r.d.unit); i++ {
+ if unit >= len(r.d.unit) {
+ unit = 0
+ }
+ r.err = nil
+ r.lastChildren = false
+ r.unit = unit
+ u := &r.d.unit[unit]
+ r.b = makeBuf(r.d, u, "info", u.off, u.data)
+ e, err := r.Next()
+ if err != nil {
+ return nil, err
+ }
+ ranges, err := r.d.Ranges(e)
+ if err != nil {
+ return nil, err
+ }
+ for _, pcs := range ranges {
+ if pcs[0] <= pc && pc < pcs[1] {
+ return e, nil
+ }
+ }
+ unit++
+ }
+ return nil, ErrUnknownPC
+}
+
+// Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
+// Only some entry types, such as TagCompileUnit or TagSubprogram, have PC
+// ranges; for others, this will return nil with no error.
+func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
+ var ret [][2]uint64
+
+ low, lowOK := e.Val(AttrLowpc).(uint64)
+
+ var high uint64
+ var highOK bool
+ highField := e.AttrField(AttrHighpc)
+ if highField != nil {
+ switch highField.Class {
+ case ClassAddress:
+ high, highOK = highField.Val.(uint64)
+ case ClassConstant:
+ off, ok := highField.Val.(int64)
+ if ok {
+ high = low + uint64(off)
+ highOK = true
+ }
+ }
+ }
+
+ if lowOK && highOK {
+ ret = append(ret, [2]uint64{low, high})
+ }
+
+ ranges, rangesOK := e.Val(AttrRanges).(int64)
+ if rangesOK && d.ranges != nil {
+ // The initial base address is the lowpc attribute
+ // of the enclosing compilation unit.
+ // Although DWARF specifies the lowpc attribute,
+ // comments in gdb/dwarf2read.c say that some versions
+ // of GCC use the entrypc attribute, so we check that too.
+ var cu *Entry
+ if e.Tag == TagCompileUnit {
+ cu = e
+ } else {
+ i := d.offsetToUnit(e.Offset)
+ if i == -1 {
+ return nil, errors.New("no unit for entry")
+ }
+ u := &d.unit[i]
+ b := makeBuf(d, u, "info", u.off, u.data)
+ cu = b.entry(u.atable, u.base)
+ if b.err != nil {
+ return nil, b.err
+ }
+ }
+
+ var base uint64
+ if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
+ base = cuEntry
+ } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
+ base = cuLow
+ }
+
+ u := &d.unit[d.offsetToUnit(e.Offset)]
+ buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
+ for len(buf.data) > 0 {
+ low = buf.addr()
+ high = buf.addr()
+
+ if low == 0 && high == 0 {
+ break
+ }
+
+ if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
+ base = high
+ } else {
+ ret = append(ret, [2]uint64{base + low, base + high})
+ }
+ }
+ }
+
+ return ret, nil
+}