diff mbox

[AIX] 2nd part of support for DWARF debug sections in XCOFF.

Message ID B37989F2852398498001550C29155BE5178ABEA8@FRCRPVV9EX3MSX.ww931.my-it-solutions.net
State New
Headers show

Commit Message

REIX, Tony Aug. 3, 2017, 3:05 p.m. UTC
Description:
 * This patch provides the 2nd part of the support for DWARF debug sections in XCOFF.
     ImportedSymbols() and ImportedLibraries() functions are not implemented.

Tests:
 * AIX: Build: SUCCESS
   - build made by means of gmake in trunk.
   - patch generated by: 
        cd gcc-svn-trunk/
        svn diff libgo

ChangeLog:
  * libgo/Makefile.am
  * libgo/Makefile.in
  * libgo/go/cmd/cgo/gcc.go
  * libgo/go/cmd/cgo/out.go
  * libgo/go/debug/dwarf/open.go
  * libgo/go/debug/xcoff/file.go
  * libgo/go/debug/xcoff/xcoff.go
  * libgo/go/go/build/deps_test.go


Cordialement,

Tony Reix
Bull - ATOS
IBM Coop Architect & Technical Leader

Office : +33 (0) 4 76 29 72 67
1 rue de Provence - 38432 Échirolles - France
www.atos.net
diff mbox

Patch

Index: libgo/Makefile.am
===================================================================
--- ./libgo/Makefile.am	(revision 250630)
+++ ./libgo/Makefile.am	(working copy)
@@ -215,7 +215,8 @@  toolexeclibgodebug_DATA = \
 	debug/gosym.gox \
 	debug/macho.gox \
 	debug/pe.gox \
-	debug/plan9obj.gox
+	debug/plan9obj.gox \
+	debug/xcoff.gox
 
 toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
 
@@ -698,6 +699,7 @@  PACKAGES = \
 	debug/macho \
 	debug/pe \
 	debug/plan9obj \
+	debug/xcoff \
 	encoding \
 	encoding/ascii85 \
 	encoding/asn1 \
@@ -1209,6 +1211,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/Makefile.in
===================================================================
--- ./libgo/Makefile.in	(revision 250630)
+++ ./libgo/Makefile.in	(working copy)
@@ -608,7 +608,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 = \
@@ -861,6 +862,7 @@  PACKAGES = \
 	debug/macho \
 	debug/pe \
 	debug/plan9obj \
+	debug/xcoff \
 	encoding \
 	encoding/ascii85 \
 	encoding/asn1 \
@@ -1239,6 +1241,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 250630)
+++ ./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"
@@ -1230,6 +1231,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
 }
@@ -1360,7 +1365,29 @@  func (p *Package) gccDebug(stdin []byte) (*dwarf.D
 		return d, binary.LittleEndian, data
 	}
 
-	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)
+		}
+		var data []byte
+		for _, s := range f.Symbols {
+			if isDebugData(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:]
+						}
+					}
+				}
+			}
+		}
+		return d, binary.BigEndian, data
+	}
+
+	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 250630)
+++ ./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,28 @@  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 {
+			if len(s) > 0 && s[0] == '.' {
+				s = s[1:]
+			}
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
+		}
+		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/debug/dwarf/open.go
===================================================================
--- ./libgo/go/debug/dwarf/open.go	(revision 250630)
+++ ./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	(nonexistent)
+++ ./libgo/go/debug/xcoff/file.go	(working copy)
@@ -0,0 +1,294 @@ 
+// 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"
+)
+
+// Information we store about an XCOFF section header.
+type Section struct {
+	Name           string
+	Size           uint64
+	Flags          uint32
+	VirtualAddress uint64
+
+	io.ReaderAt
+	sr *io.SectionReader
+}
+
+// Information we store about an XCOFF symbol.
+type Symbol struct {
+	Name          string
+	Value	      uint64
+	SectionNumber int
+}
+
+// A File represents an open XCOFF file.
+type File struct {
+	TargetMachine  uint16
+	Sections       []*Section
+	Symbols        []*Symbol
+	StringTable    []byte
+
+	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
+}
+
+// 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])
+}
+
+func getString(st []byte, offset uint32) string {
+	return cstring(st[offset:])
+}
+
+// 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
+	var nscns uint16
+	var symptr uint64
+	var nsyms uint32
+	var opthdr uint16
+	var hdrsz int
+	switch f.TargetMachine {
+	case U802TOCMAGIC:
+		fhdr := new(FileHeader32)
+		sr.Seek(0, io.SeekStart)
+		if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+			return nil, err
+		}
+		nscns = uint16(fhdr.Fnscns)
+		symptr = uint64(fhdr.Fsymptr)
+		nsyms = uint32(fhdr.Fnsyms)
+		opthdr = uint16(fhdr.Fopthdr)
+		hdrsz = FILHSZ_32
+	case U64_TOCMAGIC:
+		fhdr := new(FileHeader64)
+		sr.Seek(0, io.SeekStart)
+		if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+			return nil, err
+		}
+		nscns = uint16(fhdr.Fnscns)
+		symptr = uint64(fhdr.Fsymptr)
+		nsyms = uint32(fhdr.Fnsyms)
+		opthdr = uint16(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
+			}
+			scnptr = uint64(shdr.Sscnptr)
+			s.Size = uint64(shdr.Ssize)
+			s.Flags = shdr.Sflags
+			s.VirtualAddress = uint64(shdr.Svaddr)
+		case U64_TOCMAGIC:
+			shdr := new(SectionHeader64)
+			if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
+				return nil, err
+			}
+			scnptr = uint64(shdr.Sscnptr)
+			s.Size = uint64(shdr.Ssize)
+			s.Flags = shdr.Sflags
+			s.VirtualAddress = shdr.Svaddr
+		}
+		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)
+	var numaux int
+	for i := 0; i < int(nsyms); i++ {
+		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)
+			if se.Nscnum <= 0 || (se.Nsclass != C_EXT && se.Nsclass != C_WEAKEXT && se.Nsclass != C_HIDEXT) {
+				i += numaux // Skip auxiliary entries
+				continue
+			}
+			sym.SectionNumber = int(se.Nscnum)
+			sym.Value = uint64(se.Nvalue) - f.Sections[se.Nscnum - 1].VirtualAddress
+			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 = getString(f.StringTable, offset)
+			}
+		case U64_TOCMAGIC:
+			se := new(SymEnt64)
+			if err := binary.Read(sr, binary.BigEndian, se); err != nil {
+				return nil, err
+			}
+			numaux = int(se.Nnumaux)
+			if se.Nscnum <= 0 || (se.Nsclass != C_EXT && se.Nsclass != C_WEAKEXT && se.Nsclass != C_HIDEXT) {
+				i += numaux // Skip auxiliary entries
+				continue
+			}
+			sym.SectionNumber = int(se.Nscnum)
+			sym.Value = uint64(se.Nvalue) - f.Sections[se.Nscnum - 1].VirtualAddress
+			sym.Name = getString(f.StringTable, se.Noffset)
+		}
+		i += numaux // Skip auxiliary entries
+		f.Symbols = append(f.Symbols, sym)
+	}
+
+	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 PE 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
+}
+
+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 {
+		for _, s := range f.Sections {
+			if s.Flags == STYP_DWARF|subtype {
+				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)
+}
+
+// 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() ([]string, error) {
+	return nil, 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) {
+	// TODO
+	return nil, nil
+}
+
+// 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/xcoff.go
===================================================================
--- ./libgo/go/debug/xcoff/xcoff.go	(nonexistent)
+++ ./libgo/go/debug/xcoff/xcoff.go	(working copy)
@@ -0,0 +1,151 @@ 
+// 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
+
+type FileHeader32 struct {
+	Fmagic   uint16  // Target machine
+	Fnscns   uint16  // Number of sections
+	Ftimedat uint32  // Time and date of file creation
+	Fsymptr  uint32  // Byte offset to symbol table start
+	Fnsyms   uint32  // 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 uint32  // 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   uint32  // 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
+)
+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
+)
+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
+)
+
+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
+}
+
+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
+)
+
+const SYMESZ = 18
+
+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 uint8    // Storage class of symbol
+	Nnumaux uint8    // 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 uint8    // Storage class of symbol
+	Nnumaux uint8    // Number of auxiliary entries
+}
+
Index: libgo/go/go/build/deps_test.go
===================================================================
--- ./libgo/go/go/build/deps_test.go	(revision 250630)
+++ ./libgo/go/go/build/deps_test.go	(working copy)
@@ -238,6 +238,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"},