diff options
author | Cherry Zhang <cherryyz@google.com> | 2020-07-30 20:49:29 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2020-08-11 17:15:15 +0000 |
commit | 9559877543976f8e7b15ae02a7196c4f930fc371 (patch) | |
tree | cfb69dcc4a81d16d03664d8f578b7544712a42b7 /src/cmd/internal/archive | |
parent | a8463c32823d451800aae14226c1e36481d692bc (diff) | |
download | go-git-9559877543976f8e7b15ae02a7196c4f930fc371.tar.gz |
[dev.link] cmd/internal/objfile: read Go object file using goobj2 package
Read Go object files using cmd/internal/goobj2 package directly,
instead of using cmd/internal/goobj as an intermediate layer.
Now cmd/internal/archive is only about reading archives.
Change-Id: Ifecb217fb26c16c26fc1bbc3fba0ed44710020ed
Reviewed-on: https://go-review.googlesource.com/c/go/+/246443
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/cmd/internal/archive')
-rw-r--r-- | src/cmd/internal/archive/archive_test.go (renamed from src/cmd/internal/archive/goobj_test.go) | 133 | ||||
-rw-r--r-- | src/cmd/internal/archive/read.go | 253 | ||||
-rw-r--r-- | src/cmd/internal/archive/readnew.go | 200 |
3 files changed, 130 insertions, 456 deletions
diff --git a/src/cmd/internal/archive/goobj_test.go b/src/cmd/internal/archive/archive_test.go index 4a4d35a413..6ef0b68daa 100644 --- a/src/cmd/internal/archive/goobj_test.go +++ b/src/cmd/internal/archive/archive_test.go @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package goobj +package archive import ( + "bytes" "debug/elf" "debug/macho" "debug/pe" @@ -159,22 +160,23 @@ func TestParseGoobj(t *testing.T) { } defer f.Close() - p, err := Parse(f, "mypkg") + a, err := Parse(f) if err != nil { t.Fatal(err) } - if p.Arch != runtime.GOARCH { - t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) + if len(a.Entries) != 2 { + t.Errorf("expect 2 entry, found %d", len(a.Entries)) } - var found bool - for _, s := range p.Syms { - if s.Name == "mypkg.go1" { - found = true - break + for _, e := range a.Entries { + if e.Type == EntryPkgDef { + continue + } + if e.Type != EntryGoObj { + t.Errorf("wrong type of object: wnat EntryGoObj, got %v", e.Type) + } + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) } - } - if !found { - t.Errorf(`%s: symbol "mypkg.go1" not found`, path) } } @@ -187,28 +189,37 @@ func TestParseArchive(t *testing.T) { } defer f.Close() - p, err := Parse(f, "mypkg") + a, err := Parse(f) if err != nil { t.Fatal(err) } - if p.Arch != runtime.GOARCH { - t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) + if len(a.Entries) != 3 { + t.Errorf("expect 3 entry, found %d", len(a.Entries)) } var found1 bool var found2 bool - for _, s := range p.Syms { - if s.Name == "mypkg.go1" { + for _, e := range a.Entries { + if e.Type == EntryPkgDef { + continue + } + if e.Type != EntryGoObj { + t.Errorf("wrong type of object: wnat EntryGoObj, got %v", e.Type) + } + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) + } + if e.Name == "go1.o" { found1 = true } - if s.Name == "mypkg.go2" { + if e.Name == "go2.o" { found2 = true } } if !found1 { - t.Errorf(`%s: symbol "mypkg.go1" not found`, path) + t.Errorf(`object "go1.o" not found`) } if !found2 { - t.Errorf(`%s: symbol "mypkg.go2" not found`, path) + t.Errorf(`object "go2.o" not found`) } } @@ -223,41 +234,47 @@ func TestParseCGOArchive(t *testing.T) { } defer f.Close() - p, err := Parse(f, "mycgo") + a, err := Parse(f) if err != nil { t.Fatal(err) } - if p.Arch != runtime.GOARCH { - t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) - } - var found1 bool - var found2 bool - for _, s := range p.Syms { - if s.Name == "mycgo.go1" { - found1 = true - } - if s.Name == "mycgo.go2" { - found2 = true - } - } - if !found1 { - t.Errorf(`%s: symbol "mycgo.go1" not found`, path) - } - if !found2 { - t.Errorf(`%s: symbol "mycgo.go2" not found`, path) - } c1 := "c1" c2 := "c2" - - found1 = false - found2 = false - switch runtime.GOOS { case "darwin": c1 = "_" + c1 c2 = "_" + c2 - for _, obj := range p.Native { + case "windows": + if runtime.GOARCH == "386" { + c1 = "_" + c1 + c2 = "_" + c2 + } + case "aix": + c1 = "." + c1 + c2 = "." + c2 + } + + var foundgo, found1, found2 bool + + for _, e := range a.Entries { + switch e.Type { + default: + t.Errorf("unknown object type") + case EntryPkgDef: + continue + case EntryGoObj: + foundgo = true + if !bytes.Contains(e.Obj.TextHeader, []byte(runtime.GOARCH)) { + t.Errorf("text header does not contain GOARCH %s: %q", runtime.GOARCH, e.Obj.TextHeader) + } + continue + case EntryNativeObj: + } + + obj := io.NewSectionReader(f, e.Offset, e.Size) + switch runtime.GOOS { + case "darwin": mf, err := macho.NewFile(obj) if err != nil { t.Fatal(err) @@ -273,13 +290,7 @@ func TestParseCGOArchive(t *testing.T) { found2 = true } } - } - case "windows": - if runtime.GOARCH == "386" { - c1 = "_" + c1 - c2 = "_" + c2 - } - for _, obj := range p.Native { + case "windows": pf, err := pe.NewFile(obj) if err != nil { t.Fatal(err) @@ -292,11 +303,7 @@ func TestParseCGOArchive(t *testing.T) { found2 = true } } - } - case "aix": - c1 = "." + c1 - c2 = "." + c2 - for _, obj := range p.Native { + case "aix": xf, err := xcoff.NewFile(obj) if err != nil { t.Fatal(err) @@ -309,10 +316,7 @@ func TestParseCGOArchive(t *testing.T) { found2 = true } } - } - - default: - for _, obj := range p.Native { + default: // ELF ef, err := elf.NewFile(obj) if err != nil { t.Fatal(err) @@ -332,10 +336,13 @@ func TestParseCGOArchive(t *testing.T) { } } + if !foundgo { + t.Errorf(`go object not found`) + } if !found1 { - t.Errorf(`%s: symbol %q not found`, path, c1) + t.Errorf(`symbol %q not found`, c1) } if !found2 { - t.Errorf(`%s: symbol %q not found`, path, c2) + t.Errorf(`symbol %q not found`, c2) } } diff --git a/src/cmd/internal/archive/read.go b/src/cmd/internal/archive/read.go index cb388a84cd..6875dbce75 100644 --- a/src/cmd/internal/archive/read.go +++ b/src/cmd/internal/archive/read.go @@ -2,58 +2,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package goobj implements reading of Go object files and archives. -// -// TODO(rsc): Decide where this package should live. (golang.org/issue/6932) -// TODO(rsc): Decide the appropriate integer types for various fields. -package goobj +// Package archive implements reading of archive files generated by the Go +// toolchain. +package archive import ( "bufio" "bytes" + "cmd/internal/bio" "cmd/internal/goobj2" - "cmd/internal/objabi" "errors" "fmt" "io" "os" "strconv" - "strings" ) -// A Sym is a named symbol in an object file. -type Sym struct { - SymID // symbol identifier (name and version) - Kind objabi.SymKind // kind of symbol - DupOK bool // are duplicate definitions okay? - Size int64 // size of corresponding data - Type SymID // symbol for Go type information - Data Data // memory image of symbol - Reloc []Reloc // relocations to apply to Data - Func *Func // additional data for functions -} - -// A SymID - the combination of Name and Version - uniquely identifies -// a symbol within a package. -type SymID struct { - // Name is the name of a symbol. - Name string - - // Version is zero for symbols with global visibility. - // Symbols with only file visibility (such as file-level static - // declarations in C) have a non-zero version distinguishing - // a symbol in one file from a symbol of the same name - // in another file - Version int64 -} - -func (s SymID) String() string { - if s.Version == 0 { - return s.Name - } - return fmt.Sprintf("%s<%d>", s.Name, s.Version) -} - // A Data is a reference to data stored in an object file. // It records the offset and size of the data, so that a client can // read the data only if necessary. @@ -62,88 +26,29 @@ type Data struct { Size int64 } -// A Reloc describes a relocation applied to a memory image to refer -// to an address within a particular symbol. -type Reloc struct { - // The bytes at [Offset, Offset+Size) within the containing Sym - // should be updated to refer to the address Add bytes after the start - // of the symbol Sym. - Offset int64 - Size int64 - Sym SymID - Add int64 - - // The Type records the form of address expected in the bytes - // described by the previous fields: absolute, PC-relative, and so on. - // TODO(rsc): The interpretation of Type is not exposed by this package. - Type objabi.RelocType -} - -// A Var describes a variable in a function stack frame: a declared -// local variable, an input argument, or an output result. -type Var struct { - // The combination of Name, Kind, and Offset uniquely - // identifies a variable in a function stack frame. - // Using fewer of these - in particular, using only Name - does not. - Name string // Name of variable. - Kind int64 // TODO(rsc): Define meaning. - Offset int64 // Frame offset. TODO(rsc): Define meaning. - - Type SymID // Go type for variable. +type Archive struct { + f *os.File + Entries []Entry } -// Func contains additional per-symbol information specific to functions. -type Func struct { - Args int64 // size in bytes of argument frame: inputs and outputs - Frame int64 // size in bytes of local variable frame - Align uint32 // alignment requirement in bytes for the address of the function - Leaf bool // function omits save of link register (ARM) - NoSplit bool // function omits stack split prologue - TopFrame bool // function is the top of the call stack - Var []Var // detail about local variables - PCSP Data // PC → SP offset map - PCFile Data // PC → file number map (index into File) - PCLine Data // PC → line number map - PCInline Data // PC → inline tree index map - PCData []Data // PC → runtime support data map - FuncData []FuncData // non-PC-specific runtime support data - File map[goobj2.CUFileIndex]struct{} // set of files used in this function - InlTree []InlinedCall +type Entry struct { + Name string + Type EntryType + Data + Obj *GoObj // nil if this entry is not a Go object file } -// TODO: Add PCData []byte and PCDataIter (similar to liblink). - -// A FuncData is a single function-specific data value. -type FuncData struct { - Sym SymID // symbol holding data - Offset int64 // offset into symbol for funcdata pointer -} +type EntryType int -// An InlinedCall is a node in an InlTree. -// See cmd/internal/obj.InlTree for details. -type InlinedCall struct { - Parent int64 - File goobj2.CUFileIndex - Line int64 - Func SymID - ParentPC int64 -} +const ( + EntryPkgDef EntryType = iota + EntryGoObj + EntryNativeObj +) -// A Package is a parsed Go object file or archive defining a Go package. -type Package struct { - ImportPath string // import path denoting this package - Imports []string // packages imported by this package - SymRefs []SymID // list of symbol names and versions referred to by this pack - Syms []*Sym // symbols defined by this package - MaxVersion int64 // maximum Version in any SymID in Syms - Arch string // architecture - Native []*NativeReader // native object data (e.g. ELF) - FileList []string // List of files for this package. -} - -type NativeReader struct { - Name string - io.ReaderAt +type GoObj struct { + TextHeader []byte + Data } var ( @@ -159,26 +64,20 @@ var ( // An objReader is an object file reader. type objReader struct { - p *Package - b *bufio.Reader - f *os.File - err error - offset int64 - dataOffset int64 - limit int64 - tmp [256]byte - pkgprefix string + a *Archive + b *bio.Reader + err error + offset int64 + limit int64 + tmp [256]byte } -// init initializes r to read package p from f. -func (r *objReader) init(f *os.File, p *Package) { - r.f = f - r.p = p +func (r *objReader) init(f *os.File) { + r.a = &Archive{f, nil} r.offset, _ = f.Seek(0, io.SeekCurrent) r.limit, _ = f.Seek(0, io.SeekEnd) f.Seek(r.offset, io.SeekStart) - r.b = bufio.NewReader(f) - r.pkgprefix = objabi.PathToPrefix(p.ImportPath) + "." + r.b = bio.NewReader(f) } // error records that an error occurred. @@ -278,27 +177,16 @@ func (r *objReader) skip(n int64) { r.readFull(r.tmp[:n]) } else { // Seek, giving up buffered data. - _, err := r.f.Seek(r.offset+n, io.SeekStart) - if err != nil { - r.error(err) - } + r.b.MustSeek(r.offset+n, io.SeekStart) r.offset += n - r.b.Reset(r.f) } } -// Parse parses an object file or archive from f, -// assuming that its import path is pkgpath. -func Parse(f *os.File, pkgpath string) (*Package, error) { - if pkgpath == "" { - pkgpath = `""` - } - p := new(Package) - p.ImportPath = pkgpath - - var rd objReader - rd.init(f, p) - err := rd.readFull(rd.tmp[:8]) +// Parse parses an object file or archive from f. +func Parse(f *os.File) (*Archive, error) { + var r objReader + r.init(f) + t, err := r.peek(8) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF @@ -310,17 +198,20 @@ func Parse(f *os.File, pkgpath string) (*Package, error) { default: return nil, errNotObject - case bytes.Equal(rd.tmp[:8], archiveHeader): - if err := rd.parseArchive(); err != nil { + case bytes.Equal(t, archiveHeader): + if err := r.parseArchive(); err != nil { return nil, err } - case bytes.Equal(rd.tmp[:8], goobjHeader): - if err := rd.parseObject(goobjHeader); err != nil { + case bytes.Equal(t, goobjHeader): + off := r.offset + o := &GoObj{} + if err := r.parseObject(o, r.limit-off); err != nil { return nil, err } + r.a.Entries = []Entry{{f.Name(), EntryGoObj, Data{off, r.limit - off}, o}} } - return p, nil + return r.a, nil } // trimSpace removes trailing spaces from b and returns the corresponding string. @@ -331,6 +222,7 @@ func trimSpace(b []byte) string { // parseArchive parses a Unix archive of Go object files. func (r *objReader) parseArchive() error { + r.readFull(r.tmp[:8]) // consume header (already checked) for r.offset < r.limit { if err := r.readFull(r.tmp[:60]); err != nil { return err @@ -371,28 +263,25 @@ func (r *objReader) parseArchive() error { } switch name { case "__.PKGDEF": + r.a.Entries = append(r.a.Entries, Entry{name, EntryPkgDef, Data{r.offset, size}, nil}) r.skip(size) default: - oldLimit := r.limit - r.limit = r.offset + size - + var typ EntryType + var o *GoObj + offset := r.offset p, err := r.peek(8) if err != nil { return err } if bytes.Equal(p, goobjHeader) { - if err := r.parseObject(nil); err != nil { - return fmt.Errorf("parsing archive member %q: %v", name, err) - } + typ = EntryGoObj + o = &GoObj{} + r.parseObject(o, size) } else { - r.p.Native = append(r.p.Native, &NativeReader{ - Name: name, - ReaderAt: io.NewSectionReader(r.f, r.offset, size), - }) + typ = EntryNativeObj + r.skip(size) } - - r.skip(r.limit - r.offset) - r.limit = oldLimit + r.a.Entries = append(r.a.Entries, Entry{name, typ, Data{offset, size}, o}) } if size&1 != 0 { r.skip(1) @@ -402,16 +291,12 @@ func (r *objReader) parseArchive() error { } // parseObject parses a single Go object file. -// The prefix is the bytes already read from the file, -// typically in order to detect that this is an object file. // The object file consists of a textual header ending in "\n!\n" // and then the part we want to parse begins. // The format of that part is defined in a comment at the top // of src/liblink/objfile.c. -func (r *objReader) parseObject(prefix []byte) error { - r.p.MaxVersion++ +func (r *objReader) parseObject(o *GoObj, size int64) error { h := make([]byte, 0, 256) - h = append(h, prefix...) var c1, c2, c3 byte for { c1, c2, c3 = c2, c3, r.readByte() @@ -425,12 +310,9 @@ func (r *objReader) parseObject(prefix []byte) error { break } } - - hs := strings.Fields(string(h)) - if len(hs) >= 4 { - r.p.Arch = hs[3] - } - // TODO: extract OS + build ID if/when we need it + o.TextHeader = h + o.Offset = r.offset + o.Size = size - int64(len(h)) p, err := r.peek(8) if err != nil { @@ -439,21 +321,6 @@ func (r *objReader) parseObject(prefix []byte) error { if !bytes.Equal(p, []byte(goobj2.Magic)) { return r.error(errCorruptObject) } - r.readNew() + r.skip(o.Size) return nil } - -func (r *Reloc) String(insnOffset uint64) string { - delta := r.Offset - int64(insnOffset) - s := fmt.Sprintf("[%d:%d]%s", delta, delta+r.Size, r.Type) - if r.Sym.Name != "" { - if r.Add != 0 { - return fmt.Sprintf("%s:%s+%d", s, r.Sym.Name, r.Add) - } - return fmt.Sprintf("%s:%s", s, r.Sym.Name) - } - if r.Add != 0 { - return fmt.Sprintf("%s:%d", s, r.Add) - } - return s -} diff --git a/src/cmd/internal/archive/readnew.go b/src/cmd/internal/archive/readnew.go deleted file mode 100644 index 11847942e8..0000000000 --- a/src/cmd/internal/archive/readnew.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2019 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 goobj - -import ( - "cmd/internal/goobj2" - "cmd/internal/objabi" - "strings" -) - -// Read object file in new format. For now we still fill -// the data to the current goobj API. -func (r *objReader) readNew() { - start := uint32(r.offset) - - length := r.limit - r.offset - objbytes := make([]byte, length) - r.readFull(objbytes) - rr := goobj2.NewReaderFromBytes(objbytes, false) - if rr == nil { - panic("cannot read object file") - } - - // Imports - autolib := rr.Autolib() - for _, p := range autolib { - r.p.Imports = append(r.p.Imports, p.Pkg) - // Ignore fingerprint (for tools like objdump which only reads one object). - } - - // Name of referenced indexed symbols. - nrefName := rr.NRefName() - refNames := make(map[goobj2.SymRef]string, nrefName) - for i := 0; i < nrefName; i++ { - rn := rr.RefName(i) - refNames[rn.Sym()] = rn.Name(rr) - } - - abiToVer := func(abi uint16) int64 { - var vers int64 - if abi == goobj2.SymABIstatic { - // Static symbol - vers = r.p.MaxVersion - } - return vers - } - - resolveSymRef := func(s goobj2.SymRef) SymID { - var i uint32 - switch p := s.PkgIdx; p { - case goobj2.PkgIdxInvalid: - if s.SymIdx != 0 { - panic("bad sym ref") - } - return SymID{} - case goobj2.PkgIdxHashed64: - i = s.SymIdx + uint32(rr.NSym()) - case goobj2.PkgIdxHashed: - i = s.SymIdx + uint32(rr.NSym()+rr.NHashed64def()) - case goobj2.PkgIdxNone: - i = s.SymIdx + uint32(rr.NSym()+rr.NHashed64def()+rr.NHasheddef()) - case goobj2.PkgIdxBuiltin: - name, abi := goobj2.BuiltinName(int(s.SymIdx)) - return SymID{name, int64(abi)} - case goobj2.PkgIdxSelf: - i = s.SymIdx - default: - return SymID{refNames[s], 0} - } - sym := rr.Sym(i) - return SymID{sym.Name(rr), abiToVer(sym.ABI())} - } - - // Read things for the current goobj API for now. - - // File names - r.p.FileList = make([]string, rr.NFile()) - for i := range r.p.FileList { - r.p.FileList[i] = rr.File(i) - } - - // Symbols - pcdataBase := start + rr.PcdataBase() - ndef := uint32(rr.NSym() + rr.NHashed64def() + rr.NHasheddef() + rr.NNonpkgdef()) - n := ndef + uint32(rr.NNonpkgref()) - for i := uint32(0); i < n; i++ { - osym := rr.Sym(i) - if osym.Name(rr) == "" { - continue // not a real symbol - } - // In a symbol name in an object file, "". denotes the - // prefix for the package in which the object file has been found. - // Expand it. - name := strings.ReplaceAll(osym.Name(rr), `"".`, r.pkgprefix) - symID := SymID{Name: name, Version: abiToVer(osym.ABI())} - r.p.SymRefs = append(r.p.SymRefs, symID) - - if i >= ndef { - continue // not a defined symbol from here - } - - // Symbol data - dataOff := rr.DataOff(i) - siz := int64(rr.DataSize(i)) - - sym := Sym{ - SymID: symID, - Kind: objabi.SymKind(osym.Type()), - DupOK: osym.Dupok(), - Size: int64(osym.Siz()), - Data: Data{int64(start + dataOff), siz}, - } - r.p.Syms = append(r.p.Syms, &sym) - - // Reloc - relocs := rr.Relocs(i) - sym.Reloc = make([]Reloc, len(relocs)) - for j := range relocs { - rel := &relocs[j] - sym.Reloc[j] = Reloc{ - Offset: int64(rel.Off()), - Size: int64(rel.Siz()), - Type: objabi.RelocType(rel.Type()), - Add: rel.Add(), - Sym: resolveSymRef(rel.Sym()), - } - } - - // Aux symbol info - isym := ^uint32(0) - funcdata := make([]goobj2.SymRef, 0, 4) - auxs := rr.Auxs(i) - for j := range auxs { - a := &auxs[j] - switch a.Type() { - case goobj2.AuxGotype: - sym.Type = resolveSymRef(a.Sym()) - case goobj2.AuxFuncInfo: - if a.Sym().PkgIdx != goobj2.PkgIdxSelf { - panic("funcinfo symbol not defined in current package") - } - isym = a.Sym().SymIdx - case goobj2.AuxFuncdata: - funcdata = append(funcdata, a.Sym()) - case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines: - // nothing to do - default: - panic("unknown aux type") - } - } - - // Symbol Info - if isym == ^uint32(0) { - continue - } - b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym)) - info := goobj2.FuncInfo{} - info.Read(b) - - info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends - f := &Func{ - Args: int64(info.Args), - Frame: int64(info.Locals), - NoSplit: osym.NoSplit(), - Leaf: osym.Leaf(), - TopFrame: osym.TopFrame(), - PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)}, - PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)}, - PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)}, - PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)}, - PCData: make([]Data, len(info.Pcdata)-1), // -1 as we appended one above - FuncData: make([]FuncData, len(info.Funcdataoff)), - File: make(map[goobj2.CUFileIndex]struct{}, len(info.File)), - InlTree: make([]InlinedCall, len(info.InlTree)), - } - sym.Func = f - for k := range f.PCData { - f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])} - } - for k := range f.FuncData { - symID := resolveSymRef(funcdata[k]) - f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])} - } - for _, k := range info.File { - f.File[k] = struct{}{} - } - for k := range f.InlTree { - inl := &info.InlTree[k] - f.InlTree[k] = InlinedCall{ - Parent: int64(inl.Parent), - File: inl.File, - Line: int64(inl.Line), - Func: resolveSymRef(inl.Func), - ParentPC: int64(inl.ParentPC), - } - } - } -} |