debug/xcoff,cmd: add XCOFF support
Reviewed-on: https://go-review.googlesource.com/64592 From-SVN: r253105
This commit is contained in:
parent
f25afa93f7
commit
c90df0d293
19 changed files with 1113 additions and 22 deletions
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -612,7 +612,8 @@ toolexeclibgodebug_DATA = \
|
|||
debug/gosym.gox \
|
||||
debug/macho.gox \
|
||||
debug/pe.gox \
|
||||
debug/plan9obj.gox
|
||||
debug/plan9obj.gox \
|
||||
debug/xcoff.gox
|
||||
|
||||
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
|
||||
toolexeclibgoencoding_DATA = \
|
||||
|
@ -873,6 +874,7 @@ PACKAGES = \
|
|||
debug/macho \
|
||||
debug/pe \
|
||||
debug/plan9obj \
|
||||
debug/xcoff \
|
||||
encoding \
|
||||
encoding/ascii85 \
|
||||
encoding/asn1 \
|
||||
|
@ -1298,6 +1300,7 @@ TEST_PACKAGES = \
|
|||
debug/macho/check \
|
||||
debug/pe/check \
|
||||
debug/plan9obj/check \
|
||||
debug/xcoff/check \
|
||||
encoding/ascii85/check \
|
||||
encoding/asn1/check \
|
||||
encoding/base32/check \
|
||||
|
|
|
@ -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, nnames int) (d *dwarf.Data, ints []int6
|
|||
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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, src string, perm os.FileMode, varName st
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
539
libgo/go/debug/xcoff/file.go
Normal file
539
libgo/go/debug/xcoff/file.go
Normal file
|
@ -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"
|
||||
}
|
150
libgo/go/debug/xcoff/file_test.go
Normal file
150
libgo/go/debug/xcoff/file_test.go
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
vendored
Normal file
Binary file not shown.
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
vendored
Normal file
Binary file not shown.
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
vendored
Normal file
Binary file not shown.
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
vendored
Normal file
Binary file not shown.
7
libgo/go/debug/xcoff/testdata/hello.c
vendored
Normal file
7
libgo/go/debug/xcoff/testdata/hello.c
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
printf("hello, world\n");
|
||||
}
|
BIN
libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
vendored
Normal file
Binary file not shown.
BIN
libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
vendored
Normal file
BIN
libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
vendored
Normal file
Binary file not shown.
262
libgo/go/debug/xcoff/xcoff.go
Normal file
262
libgo/go/debug/xcoff/xcoff.go
Normal file
|
@ -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
|
||||
}
|
|
@ -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"},
|
||||
|
|
|
@ -8,12 +8,14 @@ package gccgoimporter // import "go/internal/gccgoimporter"
|
|||
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) (reader io.ReadSeeker, closer io.Closer, err e
|
|||
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
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue