aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/objfile
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-07-30 20:49:29 -0400
committerCherry Zhang <cherryyz@google.com>2020-08-11 17:15:15 +0000
commit9559877543976f8e7b15ae02a7196c4f930fc371 (patch)
treecfb69dcc4a81d16d03664d8f578b7544712a42b7 /src/cmd/internal/objfile
parenta8463c32823d451800aae14226c1e36481d692bc (diff)
downloadgo-9559877543976f8e7b15ae02a7196c4f930fc371.tar.xz
[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/objfile')
-rw-r--r--src/cmd/internal/objfile/goobj.go283
1 files changed, 205 insertions, 78 deletions
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index a7e45b9ecb..6bf9d3bf21 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -7,95 +7,207 @@
package objfile
import (
- goobj "cmd/internal/archive"
+ "cmd/internal/archive"
+ "cmd/internal/goobj2"
"cmd/internal/objabi"
"cmd/internal/sys"
"debug/dwarf"
"debug/gosym"
"errors"
"fmt"
+ "io"
"os"
+ "strings"
)
type goobjFile struct {
- goobj *goobj.Package
- f *os.File // the underlying .o or .a file
+ goobj *archive.GoObj
+ r *goobj2.Reader
+ f *os.File
}
-func openGoFile(r *os.File) (*File, error) {
- f, err := goobj.Parse(r, `""`)
+func openGoFile(f *os.File) (*File, error) {
+ a, err := archive.Parse(f)
if err != nil {
return nil, err
}
- rf := &goobjFile{goobj: f, f: r}
- if len(f.Native) == 0 {
- return &File{r, []*Entry{{raw: rf}}}, nil
- }
- entries := make([]*Entry, len(f.Native)+1)
- entries[0] = &Entry{
- raw: rf,
- }
+ entries := make([]*Entry, 0, len(a.Entries))
L:
- for i, nr := range f.Native {
- for _, try := range openers {
- if raw, err := try(nr); err == nil {
- entries[i+1] = &Entry{
- name: nr.Name,
- raw: raw,
+ for _, e := range a.Entries {
+ switch e.Type {
+ case archive.EntryPkgDef:
+ continue
+ case archive.EntryGoObj:
+ o := e.Obj
+ b := make([]byte, o.Size)
+ _, err := f.ReadAt(b, o.Offset)
+ if err != nil {
+ return nil, err
+ }
+ r := goobj2.NewReaderFromBytes(b, false)
+ entries = append(entries, &Entry{
+ name: e.Name,
+ raw: &goobjFile{e.Obj, r, f},
+ })
+ continue
+ case archive.EntryNativeObj:
+ nr := io.NewSectionReader(f, e.Offset, e.Size)
+ for _, try := range openers {
+ if raw, err := try(nr); err == nil {
+ entries = append(entries, &Entry{
+ name: e.Name,
+ raw: raw,
+ })
+ continue L
}
- continue L
}
}
- return nil, fmt.Errorf("open %s: unrecognized archive member %s", r.Name(), nr.Name)
+ return nil, fmt.Errorf("open %s: unrecognized archive member %s", f.Name(), e.Name)
}
- return &File{r, entries}, nil
+ return &File{f, entries}, nil
}
-func goobjName(id goobj.SymID) string {
- if id.Version == 0 {
- return id.Name
+func goobjName(name string, ver int) string {
+ if ver == 0 {
+ return name
}
- return fmt.Sprintf("%s<%d>", id.Name, id.Version)
+ return fmt.Sprintf("%s<%d>", name, ver)
}
-func (f *goobjFile) symbols() ([]Sym, error) {
- seen := make(map[goobj.SymID]bool)
+type goobjReloc struct {
+ Off int32
+ Size uint8
+ Type objabi.RelocType
+ Add int64
+ Sym string
+}
+func (r goobjReloc) String(insnOffset uint64) string {
+ delta := int64(r.Off) - int64(insnOffset)
+ s := fmt.Sprintf("[%d:%d]%s", delta, delta+int64(r.Size), r.Type)
+ if r.Sym != "" {
+ if r.Add != 0 {
+ return fmt.Sprintf("%s:%s+%d", s, r.Sym, r.Add)
+ }
+ return fmt.Sprintf("%s:%s", s, r.Sym)
+ }
+ if r.Add != 0 {
+ return fmt.Sprintf("%s:%d", s, r.Add)
+ }
+ return s
+}
+
+func (f *goobjFile) symbols() ([]Sym, error) {
+ r := f.r
var syms []Sym
- for _, s := range f.goobj.Syms {
- seen[s.SymID] = true
- sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: s.Size, Type: s.Type.Name, Code: '?'}
- switch s.Kind {
+
+ // Name of referenced indexed symbols.
+ nrefName := r.NRefName()
+ refNames := make(map[goobj2.SymRef]string, nrefName)
+ for i := 0; i < nrefName; i++ {
+ rn := r.RefName(i)
+ refNames[rn.Sym()] = rn.Name(r)
+ }
+
+ abiToVer := func(abi uint16) int {
+ var ver int
+ if abi == goobj2.SymABIstatic {
+ // Static symbol
+ ver = 1
+ }
+ return ver
+ }
+
+ resolveSymRef := func(s goobj2.SymRef) string {
+ var i uint32
+ switch p := s.PkgIdx; p {
+ case goobj2.PkgIdxInvalid:
+ if s.SymIdx != 0 {
+ panic("bad sym ref")
+ }
+ return ""
+ case goobj2.PkgIdxHashed64:
+ i = s.SymIdx + uint32(r.NSym())
+ case goobj2.PkgIdxHashed:
+ i = s.SymIdx + uint32(r.NSym()+r.NHashed64def())
+ case goobj2.PkgIdxNone:
+ i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()+r.NHasheddef())
+ case goobj2.PkgIdxBuiltin:
+ name, abi := goobj2.BuiltinName(int(s.SymIdx))
+ return goobjName(name, abi)
+ case goobj2.PkgIdxSelf:
+ i = s.SymIdx
+ default:
+ return refNames[s]
+ }
+ sym := r.Sym(i)
+ return goobjName(sym.Name(r), abiToVer(sym.ABI()))
+ }
+
+ // Defined symbols
+ ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
+ for i := uint32(0); i < ndef; i++ {
+ osym := r.Sym(i)
+ if osym.Name(r) == "" {
+ continue // not a real symbol
+ }
+ name := osym.Name(r)
+ ver := osym.ABI()
+ name = goobjName(name, abiToVer(ver))
+ typ := objabi.SymKind(osym.Type())
+ var code rune = '?'
+ switch typ {
case objabi.STEXT:
- sym.Code = 'T'
+ code = 'T'
case objabi.SRODATA:
- sym.Code = 'R'
+ code = 'R'
case objabi.SDATA:
- sym.Code = 'D'
+ code = 'D'
case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
- sym.Code = 'B'
+ code = 'B'
}
- if s.Version != 0 {
- sym.Code += 'a' - 'A'
+ if ver >= goobj2.SymABIstatic {
+ code += 'a' - 'A'
}
- for i, r := range s.Reloc {
- sym.Relocs = append(sym.Relocs, Reloc{Addr: uint64(s.Data.Offset) + uint64(r.Offset), Size: uint64(r.Size), Stringer: &s.Reloc[i]})
+
+ sym := Sym{
+ Name: name,
+ Addr: uint64(r.DataOff(i)),
+ Size: int64(osym.Siz()),
+ Code: code,
}
- syms = append(syms, sym)
- }
- for _, s := range f.goobj.Syms {
- for _, r := range s.Reloc {
- if !seen[r.Sym] {
- seen[r.Sym] = true
- sym := Sym{Name: goobjName(r.Sym), Code: 'U'}
- if s.Version != 0 {
- // should not happen but handle anyway
- sym.Code = 'u'
- }
- syms = append(syms, sym)
+ relocs := r.Relocs(i)
+ sym.Relocs = make([]Reloc, len(relocs))
+ for j := range relocs {
+ rel := &relocs[j]
+ sym.Relocs[j] = Reloc{
+ Addr: uint64(r.DataOff(i)) + uint64(rel.Off()),
+ Size: uint64(rel.Siz()),
+ Stringer: goobjReloc{
+ Off: rel.Off(),
+ Size: rel.Siz(),
+ Type: objabi.RelocType(rel.Type()),
+ Add: rel.Add(),
+ Sym: resolveSymRef(rel.Sym()),
+ },
}
}
+
+ syms = append(syms, sym)
+ }
+
+ // Referenced symbols
+ n := ndef + uint32(r.NNonpkgref())
+ for i := ndef; i < n; i++ {
+ osym := r.Sym(i)
+ sym := Sym{Name: osym.Name(r), Code: 'U'}
+ syms = append(syms, sym)
+ }
+ for i := 0; i < nrefName; i++ {
+ rn := r.RefName(i)
+ sym := Sym{Name: rn.Name(r), Code: 'U'}
+ syms = append(syms, sym)
}
return syms, nil
@@ -112,9 +224,11 @@ func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error)
// This function implements the Liner interface in preference to pcln() above.
func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
// TODO: this is really inefficient. Binary search? Memoize last result?
+ r := f.r
var arch *sys.Arch
+ archname := f.goarch()
for _, a := range sys.Archs {
- if a.Name == f.goobj.Arch {
+ if a.Name == archname {
arch = a
break
}
@@ -122,29 +236,43 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
if arch == nil {
return "", 0, nil
}
- for _, s := range f.goobj.Syms {
- if pc < uint64(s.Data.Offset) || pc >= uint64(s.Data.Offset+s.Data.Size) {
+ pcdataBase := r.PcdataBase()
+ ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef())
+ for i := uint32(0); i < ndef; i++ {
+ osym := r.Sym(i)
+ addr := uint64(r.DataOff(i))
+ if pc < addr || pc >= addr+uint64(osym.Siz()) {
continue
}
- if s.Func == nil {
- return "", 0, nil
- }
- pcfile := make([]byte, s.Func.PCFile.Size)
- _, err := f.f.ReadAt(pcfile, s.Func.PCFile.Offset)
- if err != nil {
- return "", 0, nil
+ isym := ^uint32(0)
+ auxs := r.Auxs(i)
+ for j := range auxs {
+ a := &auxs[j]
+ if a.Type() != goobj2.AuxFuncInfo {
+ continue
+ }
+ if a.Sym().PkgIdx != goobj2.PkgIdxSelf {
+ panic("funcinfo symbol not defined in current package")
+ }
+ isym = a.Sym().SymIdx
}
- fileID := int(pcValue(pcfile, pc-uint64(s.Data.Offset), arch))
- fileName := f.goobj.FileList[fileID]
- pcline := make([]byte, s.Func.PCLine.Size)
- _, err = f.f.ReadAt(pcline, s.Func.PCLine.Offset)
- if err != nil {
- return "", 0, nil
+ if isym == ^uint32(0) {
+ continue
}
- line := int(pcValue(pcline, pc-uint64(s.Data.Offset), arch))
+ b := r.BytesAt(r.DataOff(isym), r.DataSize(isym))
+ var info *goobj2.FuncInfo
+ lengths := info.ReadFuncInfoLengths(b)
+ off, end := info.ReadPcline(b)
+ pcline := r.BytesAt(pcdataBase+off, int(end-off))
+ line := int(pcValue(pcline, pc-addr, arch))
+ off, end = info.ReadPcfile(b)
+ pcfile := r.BytesAt(pcdataBase+off, int(end-off))
+ fileID := pcValue(pcfile, pc-addr, arch)
+ globalFileID := info.ReadFile(b, lengths.FileOff, uint32(fileID))
+ fileName := r.File(int(globalFileID))
// Note: we provide only the name in the Func structure.
// We could provide more if needed.
- return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: s.Name}}
+ return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}}
}
return "", 0, nil
}
@@ -198,18 +326,17 @@ func readvarint(p *[]byte) uint32 {
// We treat the whole object file as the text section.
func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
- var info os.FileInfo
- info, err = f.f.Stat()
- if err != nil {
- return
- }
- text = make([]byte, info.Size())
- _, err = f.f.ReadAt(text, 0)
+ text = make([]byte, f.goobj.Size)
+ _, err = f.f.ReadAt(text, int64(f.goobj.Offset))
return
}
func (f *goobjFile) goarch() string {
- return f.goobj.Arch
+ hs := strings.Fields(string(f.goobj.TextHeader))
+ if len(hs) >= 4 {
+ return hs[3]
+ }
+ return ""
}
func (f *goobjFile) loadAddress() (uint64, error) {