Commit c90df0d2 by Ian Lance Taylor

debug/xcoff,cmd: add XCOFF support

    
    Reviewed-on: https://go-review.googlesource.com/64592

From-SVN: r253105
parent f25afa93
1fcb9bb3cefb97cfab1e623826a1cc3f6aadd5f7 e0c1f0b645b12a544b484c0f477f8fb6f5980550
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -217,7 +217,8 @@ toolexeclibgodebug_DATA = \ ...@@ -217,7 +217,8 @@ toolexeclibgodebug_DATA = \
debug/gosym.gox \ debug/gosym.gox \
debug/macho.gox \ debug/macho.gox \
debug/pe.gox \ debug/pe.gox \
debug/plan9obj.gox debug/plan9obj.gox \
debug/xcoff.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
...@@ -722,6 +723,7 @@ PACKAGES = \ ...@@ -722,6 +723,7 @@ PACKAGES = \
debug/macho \ debug/macho \
debug/pe \ debug/pe \
debug/plan9obj \ debug/plan9obj \
debug/xcoff \
encoding \ encoding \
encoding/ascii85 \ encoding/ascii85 \
encoding/asn1 \ encoding/asn1 \
...@@ -1293,6 +1295,7 @@ TEST_PACKAGES = \ ...@@ -1293,6 +1295,7 @@ TEST_PACKAGES = \
debug/macho/check \ debug/macho/check \
debug/pe/check \ debug/pe/check \
debug/plan9obj/check \ debug/plan9obj/check \
debug/xcoff/check \
encoding/ascii85/check \ encoding/ascii85/check \
encoding/asn1/check \ encoding/asn1/check \
encoding/base32/check \ encoding/base32/check \
......
...@@ -612,7 +612,8 @@ toolexeclibgodebug_DATA = \ ...@@ -612,7 +612,8 @@ toolexeclibgodebug_DATA = \
debug/gosym.gox \ debug/gosym.gox \
debug/macho.gox \ debug/macho.gox \
debug/pe.gox \ debug/pe.gox \
debug/plan9obj.gox debug/plan9obj.gox \
debug/xcoff.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
toolexeclibgoencoding_DATA = \ toolexeclibgoencoding_DATA = \
...@@ -873,6 +874,7 @@ PACKAGES = \ ...@@ -873,6 +874,7 @@ PACKAGES = \
debug/macho \ debug/macho \
debug/pe \ debug/pe \
debug/plan9obj \ debug/plan9obj \
debug/xcoff \
encoding \ encoding \
encoding/ascii85 \ encoding/ascii85 \
encoding/asn1 \ encoding/asn1 \
...@@ -1298,6 +1300,7 @@ TEST_PACKAGES = \ ...@@ -1298,6 +1300,7 @@ TEST_PACKAGES = \
debug/macho/check \ debug/macho/check \
debug/pe/check \ debug/pe/check \
debug/plan9obj/check \ debug/plan9obj/check \
debug/xcoff/check \
encoding/ascii85/check \ encoding/ascii85/check \
encoding/asn1/check \ encoding/asn1/check \
encoding/base32/check \ encoding/base32/check \
......
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"debug/elf" "debug/elf"
"debug/macho" "debug/macho"
"debug/pe" "debug/pe"
"debug/xcoff"
"encoding/binary" "encoding/binary"
"errors" "errors"
"flag" "flag"
...@@ -1289,6 +1290,10 @@ func (p *Package) gccMachine() []string { ...@@ -1289,6 +1290,10 @@ func (p *Package) gccMachine() []string {
return []string{"-mabi=64"} return []string{"-mabi=64"}
case "mips", "mipsle": case "mips", "mipsle":
return []string{"-mabi=32"} return []string{"-mabi=32"}
case "ppc64":
if goos == "aix" {
return []string{"-maix64"}
}
} }
return nil return nil
} }
...@@ -1616,7 +1621,79 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6 ...@@ -1616,7 +1621,79 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp()) if f, err := xcoff.Open(gccTmp()); err == nil {
defer f.Close()
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
bo := binary.BigEndian
for _, s := range f.Symbols {
switch {
case isDebugInts(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
ints = make([]int64, len(data)/8)
for i := range ints {
ints[i] = int64(bo.Uint64(data[i*8:]))
}
}
}
}
case isDebugFloats(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
floats = make([]float64, len(data)/8)
for i := range floats {
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
}
}
}
}
default:
if n := indexOfDebugStr(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
strdata[n] = string(data)
}
}
}
break
}
if n := indexOfDebugStrlen(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
strlen := bo.Uint64(data[:8])
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
fatalf("string literal too big")
}
strlens[n] = int(strlen)
}
}
}
break
}
}
}
buildStrings()
return d, ints, floats, strs
}
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
panic("not reached") panic("not reached")
} }
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"debug/elf" "debug/elf"
"debug/macho" "debug/macho"
"debug/pe" "debug/pe"
"debug/xcoff"
"fmt" "fmt"
"go/ast" "go/ast"
"go/printer" "go/printer"
...@@ -324,7 +325,25 @@ func dynimport(obj string) { ...@@ -324,7 +325,25 @@ func dynimport(obj string) {
return return
} }
fatalf("cannot parse %s as ELF, Mach-O or PE", obj) if f, err := xcoff.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
fatalf("cannot load imported symbols from XCOFF file %s: %v", obj, err)
}
for _, s := range sym {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from XCOFF file %s: %v", obj, err)
}
for _, l := range lib {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
return
}
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
} }
// Construct a gcc struct matching the gc argument frame. // Construct a gcc struct matching the gc argument frame.
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"bytes" "bytes"
"container/heap" "container/heap"
"debug/elf" "debug/elf"
"debug/xcoff"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
...@@ -745,9 +746,13 @@ func (b *Builder) Init() { ...@@ -745,9 +746,13 @@ func (b *Builder) Init() {
func readpkglist(shlibpath string) (pkgs []*load.Package) { func readpkglist(shlibpath string) (pkgs []*load.Package) {
var stk load.ImportStack var stk load.ImportStack
if cfg.BuildToolchainName == "gccgo" { if cfg.BuildToolchainName == "gccgo" {
f, _ := elf.Open(shlibpath) var data []byte
sect := f.Section(".go_export") if f, err := elf.Open(shlibpath); err == nil {
data, _ := sect.Data() sect := f.Section(".go_export")
data, _ = sect.Data()
} else if f, err := xcoff.Open(shlibpath); err == nil {
data = f.CSect(".go_export")
}
scanner := bufio.NewScanner(bytes.NewBuffer(data)) scanner := bufio.NewScanner(bytes.NewBuffer(data))
for scanner.Scan() { for scanner.Scan() {
t := scanner.Text() t := scanner.Text()
...@@ -1815,6 +1820,7 @@ func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName st ...@@ -1815,6 +1820,7 @@ func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName st
var objectMagic = [][]byte{ var objectMagic = [][]byte{
{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
{'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package archive (AIX format)
{'\x7F', 'E', 'L', 'F'}, // ELF {'\x7F', 'E', 'L', 'F'}, // ELF
{0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit
{0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit
...@@ -1824,6 +1830,8 @@ var objectMagic = [][]byte{ ...@@ -1824,6 +1830,8 @@ var objectMagic = [][]byte{
{0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386
{0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64
{0x00, 0x00, 0x06, 0x47}, // Plan 9 arm {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm
{0x01, 0xDF}, // XCOFF32
{0x01, 0xF7}, // XCOFF64
} }
func isObject(s string) bool { func isObject(s string) bool {
...@@ -3308,6 +3316,10 @@ func (b *Builder) gccArchArgs() []string { ...@@ -3308,6 +3316,10 @@ func (b *Builder) gccArchArgs() []string {
return []string{"-mabi=64"} return []string{"-mabi=64"}
case "mips", "mipsle": case "mips", "mipsle":
return []string{"-mabi=32", "-march=mips32"} return []string{"-mabi=32", "-march=mips32"}
case "ppc64":
if cfg.Goos == "aix" {
return []string{"-maix64"}
}
} }
return nil return nil
} }
......
...@@ -33,7 +33,7 @@ type Data struct { ...@@ -33,7 +33,7 @@ type Data struct {
// New returns a new Data object initialized from the given parameters. // New returns a new Data object initialized from the given parameters.
// Rather than calling this function directly, clients should typically use // Rather than calling this function directly, clients should typically use
// the DWARF method of the File type of the appropriate package debug/elf, // the DWARF method of the File type of the appropriate package debug/elf,
// debug/macho, or debug/pe. // debug/macho, debug/pe, or debug/xcoff.
// //
// The []byte arguments are the data from the corresponding debug section // The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of // in the object file; for example, for an ELF object, abbrev is the contents of
......
// Copyright 2017 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 xcoff implements access to XCOFF (Extended Common Object File Format) files.
package xcoff
import (
"debug/dwarf"
"encoding/binary"
"fmt"
"io"
"os"
"strings"
)
// Information we store about an XCOFF section header.
type SectionHeader struct {
Name string
VirtualAddress uint64
Size uint64
Type uint32
}
type Section struct {
SectionHeader
io.ReaderAt
sr *io.SectionReader
}
// Information we store about an XCOFF symbol.
type AuxiliaryCSect struct {
Length int64
StorageMappingClass int
SymbolType int
}
type Symbol struct {
Name string
Value uint64
SectionNumber int
StorageClass int
AuxCSect AuxiliaryCSect
}
// Information we store about an imported XCOFF symbol.
type ImportedSymbol struct {
Name string
Library string
}
// A File represents an open XCOFF file.
type FileHeader struct {
TargetMachine uint16
}
type File struct {
FileHeader
Sections []*Section
Symbols []*Symbol
StringTable []byte
LibraryPaths []string
closer io.Closer
}
// Open opens the named file using os.Open and prepares it for use as an XCOFF binary.
func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
ff, err := NewFile(f)
if err != nil {
f.Close()
return nil, err
}
ff.closer = f
return ff, nil
}
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
}
return err
}
// SectionByType returns the first section in f with the
// given type, or nil if there is no such section.
func (f *File) SectionByType(typ uint32) *Section {
for _, s := range f.Sections {
if s.Type == typ {
return s
}
}
return nil
}
// cstring converts ASCII byte sequence b to string.
// It stops once it finds 0 or reaches end of b.
func cstring(b []byte) string {
var i int
for i = 0; i < len(b) && b[i] != 0; i++ {
}
return string(b[:i])
}
// getString extracts a string from an XCOFF string table.
func getString(st []byte, offset uint32) (string, bool) {
if offset < 4 || int(offset) >= len(st) {
return "", false
}
return cstring(st[offset:]), true
}
// NewFile creates a new File for accessing an XCOFF binary in an underlying reader.
func NewFile(r io.ReaderAt) (*File, error) {
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read XCOFF target machine
var magic uint16
if err := binary.Read(sr, binary.BigEndian, &magic); err != nil {
return nil, err
}
if magic != U802TOCMAGIC && magic != U64_TOCMAGIC {
return nil, fmt.Errorf("unrecognised XCOFF magic", magic)
}
f := new(File)
f.TargetMachine = magic
// Read XCOFF file header
sr.Seek(0, io.SeekStart)
var nscns uint16
var symptr uint64
var nsyms int32
var opthdr uint16
var hdrsz int
switch f.TargetMachine {
case U802TOCMAGIC:
fhdr := new(FileHeader32)
if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
return nil, err
}
nscns = fhdr.Fnscns
symptr = uint64(fhdr.Fsymptr)
nsyms = fhdr.Fnsyms
opthdr = fhdr.Fopthdr
hdrsz = FILHSZ_32
case U64_TOCMAGIC:
fhdr := new(FileHeader64)
if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
return nil, err
}
nscns = fhdr.Fnscns
symptr = fhdr.Fsymptr
nsyms = fhdr.Fnsyms
opthdr = fhdr.Fopthdr
hdrsz = FILHSZ_64
}
if symptr == 0 || nsyms <= 0 {
return nil, fmt.Errorf("no symbol table")
}
// Read string table (located right after symbol table).
offset := symptr + uint64(nsyms)*SYMESZ
sr.Seek(int64(offset), io.SeekStart)
// The first 4 bytes contain the length (in bytes).
var l uint32
binary.Read(sr, binary.BigEndian, &l)
if l > 4 {
sr.Seek(int64(offset), io.SeekStart)
f.StringTable = make([]byte, l)
io.ReadFull(sr, f.StringTable)
}
// Read section headers
sr.Seek(int64(hdrsz)+int64(opthdr), io.SeekStart)
f.Sections = make([]*Section, nscns)
for i := 0; i < int(nscns); i++ {
var scnptr uint64
s := new(Section)
switch f.TargetMachine {
case U802TOCMAGIC:
shdr := new(SectionHeader32)
if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
return nil, err
}
s.Name = cstring(shdr.Sname[:])
s.VirtualAddress = uint64(shdr.Svaddr)
s.Size = uint64(shdr.Ssize)
scnptr = uint64(shdr.Sscnptr)
s.Type = shdr.Sflags
case U64_TOCMAGIC:
shdr := new(SectionHeader64)
if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
return nil, err
}
s.Name = cstring(shdr.Sname[:])
s.VirtualAddress = shdr.Svaddr
s.Size = shdr.Ssize
scnptr = shdr.Sscnptr
s.Type = shdr.Sflags
}
r2 := r
if scnptr == 0 { // .bss must have all 0s
r2 = zeroReaderAt{}
}
s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size))
s.ReaderAt = s.sr
f.Sections[i] = s
}
// Read symbol table
sr.Seek(int64(symptr), io.SeekStart)
f.Symbols = make([]*Symbol, 0)
for i := 0; i < int(nsyms); i++ {
var numaux int
var ok bool
sym := new(Symbol)
switch f.TargetMachine {
case U802TOCMAGIC:
se := new(SymEnt32)
if err := binary.Read(sr, binary.BigEndian, se); err != nil {
return nil, err
}
numaux = int(se.Nnumaux)
sym.SectionNumber = int(se.Nscnum)
sym.StorageClass = int(se.Nsclass)
sym.Value = uint64(se.Nvalue)
zeroes := binary.BigEndian.Uint32(se.Nname[:4])
if zeroes != 0 {
sym.Name = cstring(se.Nname[:])
} else {
offset := binary.BigEndian.Uint32(se.Nname[4:])
sym.Name, ok = getString(f.StringTable, offset)
if !ok {
goto skip
}
}
case U64_TOCMAGIC:
se := new(SymEnt64)
if err := binary.Read(sr, binary.BigEndian, se); err != nil {
return nil, err
}
numaux = int(se.Nnumaux)
sym.SectionNumber = int(se.Nscnum)
sym.StorageClass = int(se.Nsclass)
sym.Value = se.Nvalue
sym.Name, ok = getString(f.StringTable, se.Noffset)
if !ok {
goto skip
}
}
if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT {
goto skip
}
// Must have at least one csect auxiliary entry.
if numaux < 1 || i+numaux >= int(nsyms) {
goto skip
}
if sym.SectionNumber < 1 || sym.SectionNumber > int(nscns) {
goto skip
}
sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress
// Read csect auxiliary entry (by convention, it is the last).
sr.Seek(int64((numaux-1)*SYMESZ), io.SeekCurrent)
i += numaux
numaux = 0
switch f.TargetMachine {
case U802TOCMAGIC:
aux := new(AuxCSect32)
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
return nil, err
}
sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
sym.AuxCSect.Length = int64(aux.Xscnlen)
case U64_TOCMAGIC:
aux := new(AuxCSect64)
if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
return nil, err
}
sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo)
}
f.Symbols = append(f.Symbols, sym)
skip:
i += numaux // Skip auxiliary entries
sr.Seek(int64(numaux)*SYMESZ, io.SeekCurrent)
}
return f, nil
}
// zeroReaderAt is ReaderAt that reads 0s.
type zeroReaderAt struct{}
// ReadAt writes len(p) 0s into p.
func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
for i := range p {
p[i] = 0
}
return len(p), nil
}
// Data reads and returns the contents of the XCOFF section s.
func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
if n == len(dat) {
err = nil
}
return dat[0:n], err
}
// CSect reads and returns the contents of a csect.
func (f *File) CSect(name string) []byte {
for _, sym := range f.Symbols {
if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD {
if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
s := f.Sections[i]
if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size {
dat := make([]byte, sym.AuxCSect.Length)
_, err := s.sr.ReadAt(dat, int64(sym.Value))
if err != nil {
return nil
}
return dat
}
}
break
}
}
return nil
}
func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the ones the debug/dwarf package uses.
// Don't bother loading others.
var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWARNGE, SSUBTYP_DWSTR}
var dat [len(subtypes)][]byte
for i, subtype := range subtypes {
s := f.SectionByType(STYP_DWARF | subtype)
if s != nil {
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
return nil, err
}
dat[i] = b
}
}
abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
}
// Read a loader section import file IDs.
func (f *File) readImportIDs(s *Section) ([]string, error) {
// Read loader header
s.sr.Seek(0, io.SeekStart)
var istlen uint32
var nimpid int32
var impoff uint64
switch f.TargetMachine {
case U802TOCMAGIC:
lhdr := new(LoaderHeader32)
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
return nil, err
}
istlen = lhdr.Listlen
nimpid = lhdr.Lnimpid
impoff = uint64(lhdr.Limpoff)
case U64_TOCMAGIC:
lhdr := new(LoaderHeader64)
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
return nil, err
}
istlen = lhdr.Listlen
nimpid = lhdr.Lnimpid
impoff = lhdr.Limpoff
}
// Read loader import file ID table
s.sr.Seek(int64(impoff), io.SeekStart)
table := make([]byte, istlen)
io.ReadFull(s.sr, table)
offset := 0
// First import file ID is the default LIBPATH value
libpath := cstring(table[offset:])
f.LibraryPaths = strings.Split(libpath, ":")
offset += len(libpath) + 3 // 3 null bytes
all := make([]string, 0)
for i := 1; i < int(nimpid); i++ {
impidpath := cstring(table[offset:])
offset += len(impidpath) + 1
impidbase := cstring(table[offset:])
offset += len(impidbase) + 1
impidmem := cstring(table[offset:])
offset += len(impidmem) + 1
var path string
if len(impidpath) > 0 {
path = impidpath + "/" + impidbase
} else {
path = impidbase
}
all = append(all, path)
}
return all, nil
}
// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
s := f.SectionByType(STYP_LOADER)
if s == nil {
return nil, nil
}
// Read loader header
s.sr.Seek(0, io.SeekStart)
var stlen uint32
var stoff uint64
var nsyms int32
var symoff uint64
switch f.TargetMachine {
case U802TOCMAGIC:
lhdr := new(LoaderHeader32)
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
return nil, err
}
stlen = lhdr.Lstlen
stoff = uint64(lhdr.Lstoff)
nsyms = lhdr.Lnsyms
symoff = LDHDRSZ_32
case U64_TOCMAGIC:
lhdr := new(LoaderHeader64)
if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
return nil, err
}
stlen = lhdr.Lstlen
stoff = lhdr.Lstoff
nsyms = lhdr.Lnsyms
symoff = lhdr.Lsymoff
}
// Read loader section string table
s.sr.Seek(int64(stoff), io.SeekStart)
st := make([]byte, stlen)
io.ReadFull(s.sr, st)
// Read imported libraries
libs, err := f.readImportIDs(s)
if err != nil {
return nil, err
}
// Read loader symbol table
s.sr.Seek(int64(symoff), io.SeekStart)
all := make([]ImportedSymbol, 0)
for i := 0; i < int(nsyms); i++ {
var name string
var ifile int32
var ok bool
switch f.TargetMachine {
case U802TOCMAGIC:
ldsym := new(LoaderSymbol32)
if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
return nil, err
}
if ldsym.Lsmtype&0x40 == 0 {
continue // Imported symbols only
}
zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4])
if zeroes != 0 {
name = cstring(ldsym.Lname[:])
} else {
offset := binary.BigEndian.Uint32(ldsym.Lname[4:])
name, ok = getString(st, offset)
if !ok {
continue
}
}
ifile = ldsym.Lifile
case U64_TOCMAGIC:
ldsym := new(LoaderSymbol64)
if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
return nil, err
}
if ldsym.Lsmtype&0x40 == 0 {
continue // Imported symbols only
}
name, ok = getString(st, ldsym.Loffset)
if !ok {
continue
}
ifile = ldsym.Lifile
}
var sym ImportedSymbol
sym.Name = name
if ifile >= 1 && int(ifile) <= len(libs) {
sym.Library = libs[ifile-1]
}
all = append(all, sym)
}
return all, nil
}
// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
func (f *File) ImportedLibraries() ([]string, error) {
s := f.SectionByType(STYP_LOADER)
if s == nil {
return nil, nil
}
all, err := f.readImportIDs(s)
return all, err
}
// FormatError is unused.
// The type is retained for compatibility.
type FormatError struct {
}
func (e *FormatError) Error() string {
return "unknown error"
}
// Copyright 2014 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 xcoff
import (
"reflect"
"testing"
)
type fileTest struct {
file string
hdr FileHeader
sections []*SectionHeader
needed []string
}
var fileTests = []fileTest{
{
"testdata/gcc-ppc32-aix-exec",
FileHeader{U802TOCMAGIC},
[]*SectionHeader{
{".text", 0x10000150, 0x00000bbd, STYP_TEXT},
{".data", 0x20000d0d, 0x0000042b, STYP_DATA},
{".bss", 0x20001138, 0x00000218, STYP_BSS},
{".loader", 0x00000000, 0x000004b3, STYP_LOADER},
{".debug", 0x00000000, 0x0000751e, STYP_DEBUG},
},
[]string{"libc.a"},
},
{
"testdata/gcc-ppc64-aix-exec",
FileHeader{U64_TOCMAGIC},
[]*SectionHeader{
{".text", 0x10000240, 0x00000afd, STYP_TEXT},
{".data", 0x20000d3d, 0x000002e3, STYP_DATA},
{".bss", 0x20001020, 0x00000428, STYP_BSS},
{".loader", 0x00000000, 0x00000535, STYP_LOADER},
{".debug", 0x00000000, 0x00008238, STYP_DEBUG},
},
[]string{"libc.a"},
},
{
"testdata/xlc-ppc32-aix-exec",
FileHeader{U802TOCMAGIC},
[]*SectionHeader{
{".text", 0x10000150, 0x00000372, STYP_TEXT},
{".data", 0x200004c2, 0x0000032e, STYP_DATA},
{".bss", 0x200007f0, 0x00000004, STYP_BSS},
{".loader", 0x00000000, 0x0000029d, STYP_LOADER},
{".debug", 0x00000000, 0x0000008f, STYP_DEBUG},
},
[]string{"libc.a"},
},
{
"testdata/xlc-ppc64-aix-exec",
FileHeader{U64_TOCMAGIC},
[]*SectionHeader{
{".text", 0x100000240, 0x00000326, STYP_TEXT},
{".data", 0x110000566, 0x00000182, STYP_DATA},
{".bss", 0x1100006e8, 0x00000008, STYP_BSS},
{".loader", 0x00000000, 0x0000029b, STYP_LOADER},
{".debug", 0x00000000, 0x000000ea, STYP_DEBUG},
},
[]string{"libc.a"},
},
{
"testdata/gcc-ppc32-aix-dwarf2-exec",
FileHeader{U802TOCMAGIC},
[]*SectionHeader{
{".text", 0x10000290, 0x00000bbd, STYP_TEXT},
{".data", 0x20000e4d, 0x00000437, STYP_DATA},
{".bss", 0x20001284, 0x0000021c, STYP_BSS},
{".loader", 0x00000000, 0x000004b3, STYP_LOADER},
{".dwline", 0x00000000, 0x000000df, STYP_DWARF | SSUBTYP_DWLINE},
{".dwinfo", 0x00000000, 0x00000314, STYP_DWARF | SSUBTYP_DWINFO},
{".dwabrev", 0x00000000, 0x000000d6, STYP_DWARF | SSUBTYP_DWABREV},
{".dwarnge", 0x00000000, 0x00000020, STYP_DWARF | SSUBTYP_DWARNGE},
{".dwloc", 0x00000000, 0x00000074, STYP_DWARF | SSUBTYP_DWLOC},
{".debug", 0x00000000, 0x00005e4f, STYP_DEBUG},
},
[]string{"libc.a"},
},
{
"testdata/gcc-ppc64-aix-dwarf2-exec",
FileHeader{U64_TOCMAGIC},
[]*SectionHeader{
{".text", 0x10000480, 0x00000afd, STYP_TEXT},
{".data", 0x20000f7d, 0x000002f3, STYP_DATA},
{".bss", 0x20001270, 0x00000428, STYP_BSS},
{".loader", 0x00000000, 0x00000535, STYP_LOADER},
{".dwline", 0x00000000, 0x000000b4, STYP_DWARF | SSUBTYP_DWLINE},
{".dwinfo", 0x00000000, 0x0000036a, STYP_DWARF | SSUBTYP_DWINFO},
{".dwabrev", 0x00000000, 0x000000b5, STYP_DWARF | SSUBTYP_DWABREV},
{".dwarnge", 0x00000000, 0x00000040, STYP_DWARF | SSUBTYP_DWARNGE},
{".dwloc", 0x00000000, 0x00000062, STYP_DWARF | SSUBTYP_DWLOC},
{".debug", 0x00000000, 0x00006605, STYP_DEBUG},
},
[]string{"libc.a"},
},
}
func TestOpen(t *testing.T) {
for i := range fileTests {
tt := &fileTests[i]
f, err := Open(tt.file)
if err != nil {
t.Error(err)
continue
}
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
continue
}
for i, sh := range f.Sections {
if i >= len(tt.sections) {
break
}
have := &sh.SectionHeader
want := tt.sections[i]
if !reflect.DeepEqual(have, want) {
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
}
}
tn := len(tt.sections)
fn := len(f.Sections)
if tn != fn {
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
}
tl := tt.needed
fl, err := f.ImportedLibraries()
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(tl, fl) {
t.Errorf("open %s: loader import = %v, want %v", tt.file, tl, fl)
}
}
}
func TestOpenFailure(t *testing.T) {
filename := "file.go" // not an XCOFF object file
_, err := Open(filename) // don't crash
if err == nil {
t.Errorf("open %s: succeeded unexpectedly", filename)
}
}
#include <stdio.h>
void
main(int argc, char *argv[])
{
printf("hello, world\n");
}
// Copyright 2017 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 xcoff
// File Header.
type FileHeader32 struct {
Fmagic uint16 // Target machine
Fnscns uint16 // Number of sections
Ftimedat int32 // Time and date of file creation
Fsymptr uint32 // Byte offset to symbol table start
Fnsyms int32 // Number of entries in symbol table
Fopthdr uint16 // Number of bytes in optional header
Fflags uint16 // Flags
}
type FileHeader64 struct {
Fmagic uint16 // Target machine
Fnscns uint16 // Number of sections
Ftimedat int32 // Time and date of file creation
Fsymptr uint64 // Byte offset to symbol table start
Fopthdr uint16 // Number of bytes in optional header
Fflags uint16 // Flags
Fnsyms int32 // Number of entries in symbol table
}
const (
FILHSZ_32 = 20
FILHSZ_64 = 24
)
const (
U802TOCMAGIC = 0737 // AIX 32-bit XCOFF
U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
)
// Flags that describe the type of the object file.
const (
F_RELFLG = 0x0001
F_EXEC = 0x0002
F_LNNO = 0x0004
F_FDPR_PROF = 0x0010
F_FDPR_OPTI = 0x0020
F_DSA = 0x0040
F_VARPG = 0x0100
F_DYNLOAD = 0x1000
F_SHROBJ = 0x2000
F_LOADONLY = 0x4000
)
// Section Header.
type SectionHeader32 struct {
Sname [8]byte // Section name
Spaddr uint32 // Physical address
Svaddr uint32 // Virtual address
Ssize uint32 // Section size
Sscnptr uint32 // Offset in file to raw data for section
Srelptr uint32 // Offset in file to relocation entries for section
Slnnoptr uint32 // Offset in file to line number entries for section
Snreloc uint16 // Number of relocation entries
Snlnno uint16 // Number of line number entries
Sflags uint32 // Flags to define the section type
}
type SectionHeader64 struct {
Sname [8]byte // Section name
Spaddr uint64 // Physical address
Svaddr uint64 // Virtual address
Ssize uint64 // Section size
Sscnptr uint64 // Offset in file to raw data for section
Srelptr uint64 // Offset in file to relocation entries for section
Slnnoptr uint64 // Offset in file to line number entries for section
Snreloc uint32 // Number of relocation entries
Snlnno uint32 // Number of line number entries
Sflags uint32 // Flags to define the section type
Spad uint32 // Needs to be 72 bytes long
}
// Flags defining the section type.
const (
STYP_DWARF = 0x0010
STYP_TEXT = 0x0020
STYP_DATA = 0x0040
STYP_BSS = 0x0080
STYP_EXCEPT = 0x0100
STYP_INFO = 0x0200
STYP_TDATA = 0x0400
STYP_TBSS = 0x0800
STYP_LOADER = 0x1000
STYP_DEBUG = 0x2000
STYP_TYPCHK = 0x4000
STYP_OVRFLO = 0x8000
)
const (
SSUBTYP_DWINFO = 0x10000 // DWARF info section
SSUBTYP_DWLINE = 0x20000 // DWARF line-number section
SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
SSUBTYP_DWSTR = 0x70000 // DWARF strings section
SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
SSUBTYP_DWLOC = 0x90000 // DWARF location lists section
SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
SSUBTYP_DWMAC = 0xB0000 // DWARF macros section
)
// Symbol Table Entry.
type SymEnt32 struct {
Nname [8]byte // Symbol name
Nvalue uint32 // Symbol value
Nscnum int16 // Section number of symbol
Ntype uint16 // Basic and derived type specification
Nsclass int8 // Storage class of symbol
Nnumaux int8 // Number of auxiliary entries
}
type SymEnt64 struct {
Nvalue uint64 // Symbol value
Noffset uint32 // Offset of the name in string table or .debug section
Nscnum int16 // Section number of symbol
Ntype uint16 // Basic and derived type specification
Nsclass int8 // Storage class of symbol
Nnumaux int8 // Number of auxiliary entries
}
const SYMESZ = 18
// Storage Class.
const (
C_NULL = 0 // Symbol table entry marked for deletion
C_EXT = 2 // External symbol
C_STAT = 3 // Static symbol
C_BLOCK = 100 // Beginning or end of inner block
C_FCN = 101 // Beginning or end of function
C_FILE = 103 // Source file name and compiler information
C_HIDEXT = 107 // Unnamed external symbol
C_BINCL = 108 // Beginning of include file
C_EINCL = 109 // End of include file
C_WEAKEXT = 111 // Weak external symbol
C_DWARF = 112 // DWARF symbol
C_GSYM = 128 // Global variable
C_LSYM = 129 // Automatic variable allocated on stack
C_PSYM = 130 // Argument to subroutine allocated on stack
C_RSYM = 131 // Register variable
C_RPSYM = 132 // Argument to function or procedure stored in register
C_STSYM = 133 // Statically allocated symbol
C_BCOMM = 135 // Beginning of common block
C_ECOML = 136 // Local member of common block
C_ECOMM = 137 // End of common block
C_DECL = 140 // Declaration of object
C_ENTRY = 141 // Alternate entry
C_FUN = 142 // Function or procedure
C_BSTAT = 143 // Beginning of static block
C_ESTAT = 144 // End of static block
C_GTLS = 145 // Global thread-local variable
C_STTLS = 146 // Static thread-local variable
)
// csect Auxiliary Entry.
type AuxCSect32 struct {
Xscnlen int32 // Length or symbol table index
Xparmhash uint32 // Offset of parameter type-check string
Xsnhash uint16 // .typchk section number
Xsmtyp uint8 // Symbol alignment and type
Xsmclas uint8 // Storage-mapping class
Xstab uint32 // Reserved
Xsnstab uint16 // Reserved
}
type AuxCSect64 struct {
Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
Xparmhash uint32 // Offset of parameter type-check string
Xsnhash uint16 // .typchk section number
Xsmtyp uint8 // Symbol alignment and type
Xsmclas uint8 // Storage-mapping class
Xscnlenhi int32 // Upper 4 bytes of length or symbol table index
Xpad uint8 // Unused
Xauxtype uint8 // Type of auxiliary entry
}
// Symbol type field.
const (
XTY_ER = 0 // External reference
XTY_SD = 1 // Section definition
XTY_LD = 2 // Label definition
XTY_CM = 3 // Common csect definition
)
// Storage-mapping class.
const (
XMC_PR = 0 // Program code
XMC_RO = 1 // Read-only constant
XMC_DB = 2 // Debug dictionary table
XMC_TC = 3 // TOC entry
XMC_UA = 4 // Unclassified
XMC_RW = 5 // Read/Write data
XMC_GL = 6 // Global linkage
XMC_XO = 7 // Extended operation
XMC_SV = 8 // 32-bit supervisor call descriptor
XMC_BS = 9 // BSS class
XMC_DS = 10 // Function descriptor
XMC_UC = 11 // Unnamed FORTRAN common
XMC_TC0 = 15 // TOC anchor
XMC_TD = 16 // Scalar data entry in the TOC
XMC_SV64 = 17 // 64-bit supervisor call descriptor
XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
XMC_TL = 20 // Read/Write thread-local data
XMC_UL = 21 // Read/Write thread-local data (.tbss)
XMC_TE = 22 // TOC entry
)
// Loader Header.
type LoaderHeader32 struct {
Lversion int32 // Loader section version number
Lnsyms int32 // Number of symbol table entries
Lnreloc int32 // Number of relocation table entries
Listlen uint32 // Length of import file ID string table
Lnimpid int32 // Number of import file IDs
Limpoff uint32 // Offset to start of import file IDs
Lstlen uint32 // Length of string table
Lstoff uint32 // Offset to start of string table
}
type LoaderHeader64 struct {
Lversion int32 // Loader section version number
Lnsyms int32 // Number of symbol table entries
Lnreloc int32 // Number of relocation table entries
Listlen uint32 // Length of import file ID string table
Lnimpid int32 // Number of import file IDs
Lstlen uint32 // Length of string table
Limpoff uint64 // Offset to start of import file IDs
Lstoff uint64 // Offset to start of string table
Lsymoff uint64 // Offset to start of symbol table
Lrldoff uint64 // Offset to start of relocation entries
}
const (
LDHDRSZ_32 = 32
LDHDRSZ_64 = 56
)
// Loader Symbol.
type LoaderSymbol32 struct {
Lname [8]byte // Symbol name or byte offset into string table
Lvalue uint32 // Address field
Lscnum int16 // Section number containing symbol
Lsmtype int8 // Symbol type, export, import flags
Lsmclas int8 // Symbol storage class
Lifile int32 // Import file ID; ordinal of import file IDs
Lparm uint32 // Parameter type-check field
}
type LoaderSymbol64 struct {
Lvalue uint64 // Address field
Loffset uint32 // Byte offset into string table of symbol name
Lscnum int16 // Section number containing symbol
Lsmtype int8 // Symbol type, export, import flags
Lsmclas int8 // Symbol storage class
Lifile int32 // Import file ID; ordinal of import file IDs
Lparm uint32 // Parameter type-check field
}
...@@ -221,7 +221,7 @@ var pkgDeps = map[string][]string{ ...@@ -221,7 +221,7 @@ var pkgDeps = map[string][]string{
"go/constant": {"L4", "go/token", "math/big"}, "go/constant": {"L4", "go/token", "math/big"},
"go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"}, "go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
"go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"}, "go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"}, "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "debug/xcoff", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/srcimporter": {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"}, "go/internal/srcimporter": {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
...@@ -243,6 +243,7 @@ var pkgDeps = map[string][]string{ ...@@ -243,6 +243,7 @@ var pkgDeps = map[string][]string{
"debug/macho": {"L4", "OS", "debug/dwarf"}, "debug/macho": {"L4", "OS", "debug/dwarf"},
"debug/pe": {"L4", "OS", "debug/dwarf"}, "debug/pe": {"L4", "OS", "debug/dwarf"},
"debug/plan9obj": {"L4", "OS"}, "debug/plan9obj": {"L4", "OS"},
"debug/xcoff": {"L4", "OS", "debug/dwarf"},
"encoding": {"L4"}, "encoding": {"L4"},
"encoding/ascii85": {"L4"}, "encoding/ascii85": {"L4"},
"encoding/asn1": {"L4", "math/big"}, "encoding/asn1": {"L4", "math/big"},
......
...@@ -8,12 +8,14 @@ package gccgoimporter // import "go/internal/gccgoimporter" ...@@ -8,12 +8,14 @@ package gccgoimporter // import "go/internal/gccgoimporter"
import ( import (
"bytes" "bytes"
"debug/elf" "debug/elf"
"debug/xcoff"
"fmt" "fmt"
"go/types" "go/types"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
) )
...@@ -66,11 +68,12 @@ const ( ...@@ -66,11 +68,12 @@ const (
gccgov2Magic = "v2;\n" gccgov2Magic = "v2;\n"
goimporterMagic = "\n$$ " goimporterMagic = "\n$$ "
archiveMagic = "!<ar" archiveMagic = "!<ar"
aixbigafMagic = "<big"
) )
// Opens the export data file at the given path. If this is an ELF file, // Opens the export data file at the given path. If this is an object file,
// searches for and opens the .go_export section. If this is an archive, // searches for and opens the .go_export section. If this is an archive,
// reads the export data from the first member, which is assumed to be an ELF file. // reads the export data from the first member, which is assumed to be an object file.
// This is intended to replicate the logic in gofrontend. // This is intended to replicate the logic in gofrontend.
func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) { func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
f, err := os.Open(fpath) f, err := os.Open(fpath)
...@@ -90,43 +93,58 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e ...@@ -90,43 +93,58 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e
return return
} }
var elfreader io.ReaderAt var objreader io.ReaderAt
switch string(magic[:]) { switch string(magic[:]) {
case gccgov1Magic, gccgov2Magic, goimporterMagic: case gccgov1Magic, gccgov2Magic, goimporterMagic:
// Raw export data. // Raw export data.
reader = f reader = f
return return
case archiveMagic: case archiveMagic, aixbigafMagic:
// TODO(pcc): Read the archive directly instead of using "ar". // TODO(pcc): Read the archive directly instead of using "ar".
f.Close() f.Close()
closer = nil closer = nil
cmd := exec.Command("ar", "p", fpath) cmd := exec.Command("ar", "p", fpath)
if runtime.GOOS == "aix" && runtime.GOARCH == "ppc64" {
// AIX puts both 32-bit and 64-bit objects in the same archive.
// Tell the AIX "ar" command to only care about 64-bit objects.
cmd.Env = append(os.Environ(), "OBJECT_MODE=64")
}
var out []byte var out []byte
out, err = cmd.Output() out, err = cmd.Output()
if err != nil { if err != nil {
return return
} }
elfreader = bytes.NewReader(out) objreader = bytes.NewReader(out)
default: default:
elfreader = f objreader = f
} }
ef, err := elf.NewFile(elfreader) ef, err := elf.NewFile(objreader)
if err != nil { if err == nil {
sec := ef.Section(".go_export")
if sec == nil {
err = fmt.Errorf("%s: .go_export section not found", fpath)
return
}
reader = sec.Open()
return return
} }
sec := ef.Section(".go_export") xf, err := xcoff.NewFile(objreader)
if sec == nil { if err == nil {
err = fmt.Errorf("%s: .go_export section not found", fpath) sdat := xf.CSect(".go_export")
if sdat == nil {
err = fmt.Errorf("%s: .go_export section not found", fpath)
return
}
reader = bytes.NewReader(sdat)
return return
} }
reader = sec.Open()
return return
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment