]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link/internal/loader: expand methods for FuncInfo
authorThan McIntosh <thanm@google.com>
Wed, 8 Apr 2020 15:56:43 +0000 (11:56 -0400)
committerThan McIntosh <thanm@google.com>
Fri, 10 Apr 2020 12:33:04 +0000 (12:33 +0000)
Expand the methods for the FuncInfo helper, to support reading the
contents of an object file FuncInfo aux symbol using the new style
(that is to say, incrementally and without allocating slices to hold
the various bits).

Change-Id: I953d72c4a53f98c840e6b25b08fd33dc4a833dd5
Reviewed-on: https://go-review.googlesource.com/c/go/+/227585
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/internal/goobj2/funcinfo.go
src/cmd/link/internal/loader/loader.go

index 053d7adc155283b23b38c63ddbb6972d05e9d489..36b2de20cd40b42c4c03377214d42ee383deeee9 100644 (file)
@@ -100,8 +100,49 @@ func (a *FuncInfo) Read(b []byte) {
        }
 }
 
-// Accessors reading only some fields.
-// TODO: more accessors.
+// FuncInfoLengths is a cache containing a roadmap of offsets and
+// lengths for things within a serialized FuncInfo. Each length field
+// stores the number of items (e.g. files, inltree nodes, etc), and the
+// corresponding "off" field stores the byte offset of the start of
+// the items in question.
+type FuncInfoLengths struct {
+       NumPcdata      uint32
+       PcdataOff      uint32
+       NumFuncdataoff uint32
+       FuncdataoffOff uint32
+       NumFile        uint32
+       FileOff        uint32
+       NumInlTree     uint32
+       InlTreeOff     uint32
+       Initialized    bool
+}
+
+func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
+       var result FuncInfoLengths
+
+       const numpcdataOff = 24
+       result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
+       result.PcdataOff = numpcdataOff + 4
+
+       numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
+       result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
+       result.FuncdataoffOff = numfuncdataoffOff + 4
+
+       numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
+       result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
+       result.FileOff = numfileOff + 4
+
+       const symRefSize = 4 + 4
+       numinltreeOff := result.FileOff + symRefSize*result.NumFile
+       result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
+       result.InlTreeOff = numinltreeOff + 4
+
+       result.Initialized = true
+
+       return result
+}
+
+func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
 
 func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
 
@@ -110,6 +151,43 @@ func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
        return binary.LittleEndian.Uint32(b[8:]), binary.LittleEndian.Uint32(b[12:])
 }
 
+// return start and end offsets.
+func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
+       return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
+}
+
+// return start and end offsets.
+func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
+       return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
+}
+
+// return start and end offsets.
+func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
+       return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
+}
+
+// return start and end offsets.
+func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
+       return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
+}
+
+func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
+       return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
+}
+
+func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) SymRef {
+       p := binary.LittleEndian.Uint32(b[filesoff+8*k:])
+       s := binary.LittleEndian.Uint32(b[filesoff+4+8*k:])
+       return SymRef{p, s}
+}
+
+func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
+       const inlTreeNodeSize = 4 * 7
+       var result InlTreeNode
+       result.Read(b[inltreeoff+k*inlTreeNodeSize:])
+       return result
+}
+
 // InlTreeNode is the serialized form of FileInfo.InlTree.
 type InlTreeNode struct {
        Parent   int32
index cd5971c2e1a774b06bd3d6022c43de2e3cba74a9..390eb1af24325b0d86876f99874620c169b56f83 100644 (file)
@@ -1529,13 +1529,18 @@ func (x RelocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
 
 // FuncInfo provides hooks to access goobj2.FuncInfo in the objects.
 type FuncInfo struct {
-       l    *Loader
-       r    *oReader
-       data []byte
+       l       *Loader
+       r       *oReader
+       data    []byte
+       lengths goobj2.FuncInfoLengths
 }
 
 func (fi *FuncInfo) Valid() bool { return fi.r != nil }
 
+func (fi *FuncInfo) Args() int {
+       return int((*goobj2.FuncInfo)(nil).ReadArgs(fi.data))
+}
+
 func (fi *FuncInfo) Locals() int {
        return int((*goobj2.FuncInfo)(nil).ReadLocals(fi.data))
 }
@@ -1545,7 +1550,122 @@ func (fi *FuncInfo) Pcsp() []byte {
        return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
 }
 
-// TODO: more accessors.
+func (fi *FuncInfo) Pcfile() []byte {
+       pcf, end := (*goobj2.FuncInfo)(nil).ReadPcfile(fi.data)
+       return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
+}
+
+func (fi *FuncInfo) Pcline() []byte {
+       pcln, end := (*goobj2.FuncInfo)(nil).ReadPcline(fi.data)
+       return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
+}
+
+// Preload has to be called prior to invoking the various methods
+// below related to pcdata, funcdataoff, files, and inltree nodes.
+func (fi *FuncInfo) Preload() {
+       fi.lengths = (*goobj2.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
+}
+
+func (fi *FuncInfo) Pcinline() []byte {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       pcinl, end := (*goobj2.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
+       return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
+}
+
+func (fi *FuncInfo) NumPcdata() uint32 {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       return fi.lengths.NumPcdata
+}
+
+func (fi *FuncInfo) Pcdata(k int) []byte {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       pcdat, end := (*goobj2.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
+       return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
+}
+
+func (fi *FuncInfo) NumFuncdataoff() uint32 {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       return fi.lengths.NumFuncdataoff
+}
+
+func (fi *FuncInfo) Funcdataoff(k int) int64 {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       return (*goobj2.FuncInfo)(nil).ReadFuncdataoff(fi.data, fi.lengths.FuncdataoffOff, uint32(k))
+}
+
+func (fi *FuncInfo) Funcdata(fnsym Sym, syms []Sym) []Sym {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       if int(fi.lengths.NumFuncdataoff) > cap(syms) {
+               syms = make([]Sym, 0, fi.lengths.NumFuncdataoff)
+       } else {
+               syms = syms[:0]
+       }
+       r, li := fi.l.toLocal(fnsym)
+       auxs := r.Auxs2(li)
+       for j := range auxs {
+               a := &auxs[j]
+               if a.Type() == goobj2.AuxFuncdata {
+                       syms = append(syms, fi.l.resolve(fi.r, a.Sym()))
+               }
+       }
+       return syms
+}
+
+func (fi *FuncInfo) NumFile() uint32 {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       return fi.lengths.NumFile
+}
+
+func (fi *FuncInfo) File(k int) Sym {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       sr := (*goobj2.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
+       return fi.l.resolve(fi.r, sr)
+}
+
+type InlTreeNode struct {
+       Parent   int32
+       File     Sym
+       Line     int32
+       Func     Sym
+       ParentPC int32
+}
+
+func (fi *FuncInfo) NumInlTree() uint32 {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       return fi.lengths.NumInlTree
+}
+
+func (fi *FuncInfo) InlTree(k int) InlTreeNode {
+       if !fi.lengths.Initialized {
+               panic("need to call Preload first")
+       }
+       node := (*goobj2.FuncInfo)(nil).ReadInlTree(fi.data, fi.lengths.InlTreeOff, uint32(k))
+       return InlTreeNode{
+               Parent:   node.Parent,
+               File:     fi.l.resolve(fi.r, node.File),
+               Line:     node.Line,
+               Func:     fi.l.resolve(fi.r, node.Func),
+               ParentPC: node.ParentPC,
+       }
+}
 
 func (l *Loader) FuncInfo(i Sym) FuncInfo {
        var r *oReader
@@ -1566,7 +1686,7 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
                a := &auxs[j]
                if a.Type() == goobj2.AuxFuncInfo {
                        b := r.Data(int(a.Sym().SymIdx))
-                       return FuncInfo{l, r, b}
+                       return FuncInfo{l, r, b, goobj2.FuncInfoLengths{}}
                }
        }
        return FuncInfo{}