diff mbox series

libgo patch committed: Add XCOFF support

Message ID CAOyqgcVgcXRT4CYNtW1UNvd9p3ebO+KESC5qHVz8gMgxBWXeBw@mail.gmail.com
State New
Headers show
Series libgo patch committed: Add XCOFF support | expand

Commit Message

Ian Lance Taylor Sept. 22, 2017, 6:49 p.m. UTC
This patch by Tony Reix adds XCOFF support to libgo and to the go and
cgo commands.  Bootstrapped and ran Go tests on x86_64-pc-linux-gnu.
Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 253042)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-1fcb9bb3cefb97cfab1e623826a1cc3f6aadd5f7
+e0c1f0b645b12a544b484c0f477f8fb6f5980550
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 253042)
+++ libgo/Makefile.am	(working copy)
@@ -217,7 +217,8 @@  toolexeclibgodebug_DATA = \
 	debug/gosym.gox \
 	debug/macho.gox \
 	debug/pe.gox \
-	debug/plan9obj.gox
+	debug/plan9obj.gox \
+	debug/xcoff.gox
 
 toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
 
@@ -722,6 +723,7 @@  PACKAGES = \
 	debug/macho \
 	debug/pe \
 	debug/plan9obj \
+	debug/xcoff \
 	encoding \
 	encoding/ascii85 \
 	encoding/asn1 \
@@ -1293,6 +1295,7 @@  TEST_PACKAGES = \
 	debug/macho/check \
 	debug/pe/check \
 	debug/plan9obj/check \
+	debug/xcoff/check \
 	encoding/ascii85/check \
 	encoding/asn1/check \
 	encoding/base32/check \
Index: libgo/go/cmd/cgo/gcc.go
===================================================================
--- libgo/go/cmd/cgo/gcc.go	(revision 253025)
+++ libgo/go/cmd/cgo/gcc.go	(working copy)
@@ -13,6 +13,7 @@  import (
 	"debug/elf"
 	"debug/macho"
 	"debug/pe"
+	"debug/xcoff"
 	"encoding/binary"
 	"errors"
 	"flag"
@@ -1289,6 +1290,10 @@  func (p *Package) gccMachine() []string
 		return []string{"-mabi=64"}
 	case "mips", "mipsle":
 		return []string{"-mabi=32"}
+	case "ppc64":
+		if goos == "aix" {
+			return []string{"-maix64"}
+		}
 	}
 	return nil
 }
@@ -1616,7 +1621,79 @@  func (p *Package) gccDebug(stdin []byte,
 		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")
 }
 
Index: libgo/go/cmd/cgo/out.go
===================================================================
--- libgo/go/cmd/cgo/out.go	(revision 253025)
+++ libgo/go/cmd/cgo/out.go	(working copy)
@@ -9,6 +9,7 @@  import (
 	"debug/elf"
 	"debug/macho"
 	"debug/pe"
+	"debug/xcoff"
 	"fmt"
 	"go/ast"
 	"go/printer"
@@ -324,7 +325,25 @@  func dynimport(obj string) {
 		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.
Index: libgo/go/cmd/go/internal/work/build.go
===================================================================
--- libgo/go/cmd/go/internal/work/build.go	(revision 253025)
+++ libgo/go/cmd/go/internal/work/build.go	(working copy)
@@ -9,6 +9,7 @@  import (
 	"bytes"
 	"container/heap"
 	"debug/elf"
+	"debug/xcoff"
 	"errors"
 	"flag"
 	"fmt"
@@ -745,9 +746,13 @@  func (b *Builder) Init() {
 func readpkglist(shlibpath string) (pkgs []*load.Package) {
 	var stk load.ImportStack
 	if cfg.BuildToolchainName == "gccgo" {
-		f, _ := elf.Open(shlibpath)
-		sect := f.Section(".go_export")
-		data, _ := sect.Data()
+		var data []byte
+		if f, err := elf.Open(shlibpath); err == nil {
+			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))
 		for scanner.Scan() {
 			t := scanner.Text()
@@ -1815,6 +1820,7 @@  func (b *Builder) cover(a *Action, dst,
 
 var objectMagic = [][]byte{
 	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
+	{'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package archive (AIX format)
 	{'\x7F', 'E', 'L', 'F'},                   // ELF
 	{0xFE, 0xED, 0xFA, 0xCE},                  // Mach-O big-endian 32-bit
 	{0xFE, 0xED, 0xFA, 0xCF},                  // Mach-O big-endian 64-bit
@@ -1824,6 +1830,8 @@  var objectMagic = [][]byte{
 	{0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
 	{0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
 	{0x00, 0x00, 0x06, 0x47},                  // Plan 9 arm
+	{0x01, 0xDF},                              // XCOFF32
+	{0x01, 0xF7},                              // XCOFF64
 }
 
 func isObject(s string) bool {
@@ -3308,6 +3316,10 @@  func (b *Builder) gccArchArgs() []string
 		return []string{"-mabi=64"}
 	case "mips", "mipsle":
 		return []string{"-mabi=32", "-march=mips32"}
+	case "ppc64":
+		if cfg.Goos == "aix" {
+			return []string{"-maix64"}
+		}
 	}
 	return nil
 }
Index: libgo/go/debug/dwarf/open.go
===================================================================
--- libgo/go/debug/dwarf/open.go	(revision 253025)
+++ libgo/go/debug/dwarf/open.go	(working copy)
@@ -33,7 +33,7 @@  type Data struct {
 // New returns a new Data object initialized from the given parameters.
 // Rather than calling this function directly, clients should typically use
 // 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
 // in the object file; for example, for an ELF object, abbrev is the contents of
Index: libgo/go/debug/xcoff/file.go
===================================================================
--- libgo/go/debug/xcoff/file.go	(revision 0)
+++ libgo/go/debug/xcoff/file.go	(working copy)
@@ -0,0 +1,539 @@ 
+// 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"
+}
Index: libgo/go/debug/xcoff/file_test.go
===================================================================
--- libgo/go/debug/xcoff/file_test.go	(revision 0)
+++ libgo/go/debug/xcoff/file_test.go	(working copy)
@@ -0,0 +1,150 @@ 
+// 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)
+	}
+}
Index: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/testdata/hello.c
===================================================================
--- libgo/go/debug/xcoff/testdata/hello.c	(revision 0)
+++ libgo/go/debug/xcoff/testdata/hello.c	(working copy)
@@ -0,0 +1,7 @@ 
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+	printf("hello, world\n");
+}
Index: libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
===================================================================
--- libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec	(revision 0)
+++ libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec	(working copy)

Property changes on: libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: libgo/go/debug/xcoff/xcoff.go
===================================================================
--- libgo/go/debug/xcoff/xcoff.go	(revision 0)
+++ libgo/go/debug/xcoff/xcoff.go	(working copy)
@@ -0,0 +1,262 @@ 
+// 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
+}
Index: libgo/go/go/build/deps_test.go
===================================================================
--- libgo/go/go/build/deps_test.go	(revision 253025)
+++ libgo/go/go/build/deps_test.go	(working copy)
@@ -221,7 +221,7 @@  var pkgDeps = map[string][]string{
 	"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/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/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
 
@@ -243,6 +243,7 @@  var pkgDeps = map[string][]string{
 	"debug/macho":              {"L4", "OS", "debug/dwarf"},
 	"debug/pe":                 {"L4", "OS", "debug/dwarf"},
 	"debug/plan9obj":           {"L4", "OS"},
+	"debug/xcoff":              {"L4", "OS", "debug/dwarf"},
 	"encoding":                 {"L4"},
 	"encoding/ascii85":         {"L4"},
 	"encoding/asn1":            {"L4", "math/big"},
Index: libgo/go/go/internal/gccgoimporter/importer.go
===================================================================
--- libgo/go/go/internal/gccgoimporter/importer.go	(revision 253025)
+++ libgo/go/go/internal/gccgoimporter/importer.go	(working copy)
@@ -8,12 +8,14 @@  package gccgoimporter // import "go/inte
 import (
 	"bytes"
 	"debug/elf"
+	"debug/xcoff"
 	"fmt"
 	"go/types"
 	"io"
 	"os"
 	"os/exec"
 	"path/filepath"
+	"runtime"
 	"strings"
 )
 
@@ -66,11 +68,12 @@  const (
 	gccgov2Magic    = "v2;\n"
 	goimporterMagic = "\n$$ "
 	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,
-// 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.
 func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
 	f, err := os.Open(fpath)
@@ -90,43 +93,58 @@  func openExportFile(fpath string) (reade
 		return
 	}
 
-	var elfreader io.ReaderAt
+	var objreader io.ReaderAt
 	switch string(magic[:]) {
 	case gccgov1Magic, gccgov2Magic, goimporterMagic:
 		// Raw export data.
 		reader = f
 		return
 
-	case archiveMagic:
+	case archiveMagic, aixbigafMagic:
 		// TODO(pcc): Read the archive directly instead of using "ar".
 		f.Close()
 		closer = nil
 
 		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
 		out, err = cmd.Output()
 		if err != nil {
 			return
 		}
 
-		elfreader = bytes.NewReader(out)
+		objreader = bytes.NewReader(out)
 
 	default:
-		elfreader = f
+		objreader = f
 	}
 
-	ef, err := elf.NewFile(elfreader)
-	if err != nil {
+	ef, err := elf.NewFile(objreader)
+	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
 	}
 
-	sec := ef.Section(".go_export")
-	if sec == nil {
-		err = fmt.Errorf("%s: .go_export section not found", fpath)
+	xf, err := xcoff.NewFile(objreader)
+	if err == nil {
+		sdat := xf.CSect(".go_export")
+		if sdat == nil {
+			err = fmt.Errorf("%s: .go_export section not found", fpath)
+			return
+		}
+		reader = bytes.NewReader(sdat)
 		return
 	}
 
-	reader = sec.Open()
 	return
 }