]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/internal/goobj: support parsing new object file
authorCherry Zhang <cherryyz@google.com>
Wed, 11 Sep 2019 19:57:39 +0000 (15:57 -0400)
committerCherry Zhang <cherryyz@google.com>
Thu, 3 Oct 2019 21:25:48 +0000 (21:25 +0000)
Add support of parsing new object file format. We use the new
parser if the magic string matches the new one, otherwise use the
old one.

The parsed data are still filled into the current goobj API. In
the future we may consider to change the goobj API to a close
match of the object file data.

Now objdump and nm commands support new object file format.

For a reference to a symbol defined in another package, with the
new object file format we don't know its name. Write it as
pkg.<#nn> for now, where nn is its symbol index.

Change-Id: I06d05b2ca834ba36980da3c5d76aee16c3b0a483
Reviewed-on: https://go-review.googlesource.com/c/go/+/196031
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/internal/goobj/read.go
src/cmd/internal/goobj/readnew.go [new file with mode: 0644]

index 0c70b8cd9ffb3bf699c40395bc9b512be1abb736..2a3afffeb071b20898ead36f2832bcca3231317c 100644 (file)
@@ -503,6 +503,11 @@ func (r *objReader) parseObject(prefix []byte) error {
        // TODO: extract OS + build ID if/when we need it
 
        r.readFull(r.tmp[:8])
+       if bytes.Equal(r.tmp[:8], []byte("\x00go114LD")) {
+               r.offset -= 8
+               r.readNew()
+               return nil
+       }
        if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
                return r.error(errCorruptObject)
        }
diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go
new file mode 100644 (file)
index 0000000..442784d
--- /dev/null
@@ -0,0 +1,163 @@
+// 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"
+       "fmt"
+)
+
+// 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)
+       rr := goobj2.NewReader(r.f, start)
+       if rr == nil {
+               panic("cannot read object file")
+       }
+
+       // Imports
+       pkglist := rr.Pkglist()
+       r.p.Imports = pkglist[1:] // index 0 is a dummy invalid package
+
+       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 int
+               switch p := s.PkgIdx; p {
+               case goobj2.PkgIdxInvalid:
+                       if s.SymIdx != 0 {
+                               panic("bad sym ref")
+                       }
+                       return SymID{}
+               case goobj2.PkgIdxNone:
+                       i = int(s.SymIdx) + rr.NSym()
+               case goobj2.PkgIdxBuiltin:
+                       panic("PkgIdxBuiltin is unused")
+               case goobj2.PkgIdxSelf:
+                       i = int(s.SymIdx)
+               default:
+                       pkg := pkglist[p]
+                       return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0}
+               }
+               sym := goobj2.Sym{}
+               sym.Read(rr, rr.SymOff(i))
+               return SymID{sym.Name, abiToVer(sym.ABI)}
+       }
+
+       // Read things for the current goobj API for now.
+
+       // Symbols
+       pcdataBase := start + rr.PcdataBase()
+       n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
+       ndef := rr.NSym() + rr.NNonpkgdef()
+       for i := 0; i < n; i++ {
+               osym := goobj2.Sym{}
+               osym.Read(rr, rr.SymOff(i))
+               if osym.Name == "" {
+                       continue // not a real symbol
+               }
+               symID := SymID{Name: osym.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.Flag&goobj2.SymFlagDupok != 0,
+                       Size:  int64(osym.Siz),
+                       Data:  Data{int64(start + dataOff), siz},
+               }
+               r.p.Syms = append(r.p.Syms, &sym)
+
+               // Reloc
+               nreloc := rr.NReloc(i)
+               sym.Reloc = make([]Reloc, nreloc)
+               for j := 0; j < nreloc; j++ {
+                       rel := goobj2.Reloc{}
+                       rel.Read(rr, rr.RelocOff(i, 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 := -1
+               funcdata := make([]goobj2.SymRef, 0, 4)
+               naux := rr.NAux(i)
+               for j := 0; j < naux; j++ {
+                       a := goobj2.Aux{}
+                       a.Read(rr, rr.AuxOff(i, 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 = int(a.Sym.SymIdx)
+                       case goobj2.AuxFuncdata:
+                               funcdata = append(funcdata, a.Sym)
+                       default:
+                               panic("unknown aux type")
+                       }
+               }
+
+               // Symbol Info
+               if isym == -1 {
+                       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:  info.NoSplit != 0,
+                       Leaf:     info.Flags&goobj2.FuncFlagLeaf != 0,
+                       TopFrame: info.Flags&goobj2.FuncFlagTopFrame != 0,
+                       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([]string, len(info.File)),
+               }
+               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 f.File {
+                       symID := resolveSymRef(info.File[k])
+                       f.File[k] = symID.Name
+               }
+       }
+}