package  xcoffimport  (	"debug/dwarf" 	"encoding/binary" 	"errors" 	"fmt" 	"internal/saferio" 	"io" 	"os" 	"strings" )type  SectionHeader  struct  {	Name           string 	VirtualAddress uint64 	Size           uint64 	Type           uint32 	Relptr         uint64 	Nreloc         uint32 }type  Section  struct  {	SectionHeader 	Relocs []Reloc 	io .ReaderAt 	sr *io .SectionReader }type  AuxiliaryCSect  struct  {	Length              int64 	StorageMappingClass int 	SymbolType          int }type  AuxiliaryFcn  struct  {	Size int64 }type  Symbol  struct  {	Name          string 	Value         uint64 	SectionNumber int 	StorageClass  int 	AuxFcn        AuxiliaryFcn 	AuxCSect      AuxiliaryCSect }type  Reloc  struct  {	VirtualAddress   uint64 	Symbol           *Symbol 	Signed           bool 	InstructionFixed bool 	Length           uint8 	Type             uint8 }type  ImportedSymbol  struct  {	Name    string 	Library string }type  FileHeader  struct  {	TargetMachine uint16 }type  File  struct  {	FileHeader 	Sections     []*Section 	Symbols      []*Symbol 	StringTable  []byte 	LibraryPaths []string 	closer io .Closer }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 }func  (f  *File ) Close () error  {	var  err  error 	if  f .closer  != nil  {		err  = f .closer .Close ()		f .closer  = nil 	}	return  err }func  (f  *File ) Section (name  string ) *Section  {	for  _ , s  := range  f .Sections  {		if  s .Name  == name  || (len (name ) > 8  && s .Name  == name [:8 ]) {			return  s 		}	}	return  nil }func  (f  *File ) SectionByType (typ  uint32 ) *Section  {	for  _ , s  := range  f .Sections  {		if  s .Type  == typ  {			return  s 		}	}	return  nil }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 , bool ) {	if  offset  < 4  || int (offset ) >= len (st ) {		return  "" , false 	}	return  cstring (st [offset :]), true }func  NewFile r  io .ReaderAt ) (*File , error ) {	sr  := io .NewSectionReader (r , 0 , 1 <<63 -1 )		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: 0x%x" , magic )	}	f  := new (File )	f .TargetMachine  = magic 		if  _ , err  := sr .Seek (0 , io .SeekStart ); err  != nil  {		return  nil , err 	}	var  nscns  uint16 	var  symptr  uint64 	var  nsyms  uint32 	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" )	}		offset  := symptr  + uint64 (nsyms )*SYMESZ 	if  _ , err  := sr .Seek (int64 (offset ), io .SeekStart ); err  != nil  {		return  nil , err 	}		var  l  uint32 	if  err  := binary .Read (sr , binary .BigEndian , &l ); err  != nil  {		return  nil , err 	}	if  l  > 4  {		st , err  := saferio .ReadDataAt (sr , uint64 (l ), int64 (offset ))		if  err  != nil  {			return  nil , err 		}		f .StringTable  = st 	}		if  _ , err  := sr .Seek (int64 (hdrsz )+int64 (opthdr ), io .SeekStart ); err  != nil  {		return  nil , err 	}	c  := saferio .SliceCap [*Section ](uint64 (nscns ))	if  c  < 0  {		return  nil , fmt .Errorf ("too many XCOFF sections (%d)" , nscns )	}	f .Sections  = make ([]*Section , 0 , c )	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 			s .Relptr  = uint64 (shdr .Srelptr )			s .Nreloc  = uint32 (shdr .Snreloc )		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 			s .Relptr  = shdr .Srelptr 			s .Nreloc  = shdr .Snreloc 		}		r2  := r 		if  scnptr  == 0  { 			r2  = &nobitsSectionReader {}		}		s .sr  = io .NewSectionReader (r2 , int64 (scnptr ), int64 (s .Size ))		s .ReaderAt  = s .sr 		f .Sections  = append (f .Sections , s )	}		var  idxToSym  = make (map [int ]*Symbol )		if  _ , err  := sr .Seek (int64 (symptr ), io .SeekStart ); err  != nil  {		return  nil , err 	}	f .Symbols  = make ([]*Symbol , 0 )	for  i  := 0 ; i  < int (nsyms ); i ++ {		var  numaux  int 		var  ok , needAuxFcn  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 )			needAuxFcn  = se .Ntype &SYM_TYPE_FUNC  != 0  && numaux  > 1 			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 			needAuxFcn  = se .Ntype &SYM_TYPE_FUNC  != 0  && numaux  > 1 			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 		}				if  numaux  < 1  || i +numaux  >= int (nsyms ) {			goto  skip 		}		if  sym .SectionNumber  > int (nscns ) {			goto  skip 		}		if  sym .SectionNumber  == 0  {			sym .Value  = 0 		} else  {			sym .Value  -= f .Sections [sym .SectionNumber -1 ].VirtualAddress 		}		idxToSym [i ] = sym 				if  needAuxFcn  {			switch  f .TargetMachine  {			case  U802TOCMAGIC :				aux  := new (AuxFcn32 )				if  err  := binary .Read (sr , binary .BigEndian , aux ); err  != nil  {					return  nil , err 				}				sym .AuxFcn .Size  = int64 (aux .Xfsize )			case  U64_TOCMAGIC :				aux  := new (AuxFcn64 )				if  err  := binary .Read (sr , binary .BigEndian , aux ); err  != nil  {					return  nil , err 				}				sym .AuxFcn .Size  = int64 (aux .Xfsize )			}		}				if  !needAuxFcn  {			if  _ , err  := sr .Seek (int64 (numaux -1 )*SYMESZ , io .SeekCurrent ); err  != nil  {				return  nil , err 			}		}		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  		if  _ , err  := sr .Seek (int64 (numaux )*SYMESZ , io .SeekCurrent ); err  != nil  {			return  nil , err 		}	}		for  sectNum , sect  := range  f .Sections  {		if  sect .Type  != STYP_TEXT  && sect .Type  != STYP_DATA  {			continue 		}		if  sect .Relptr  == 0  {			continue 		}		c  := saferio .SliceCap [Reloc ](uint64 (sect .Nreloc ))		if  c  < 0  {			return  nil , fmt .Errorf ("too many relocs (%d) for section %d" , sect .Nreloc , sectNum )		}		sect .Relocs  = make ([]Reloc , 0 , c )		if  _ , err  := sr .Seek (int64 (sect .Relptr ), io .SeekStart ); err  != nil  {			return  nil , err 		}		for  i  := uint32 (0 ); i  < sect .Nreloc ; i ++ {			var  reloc  Reloc 			switch  f .TargetMachine  {			case  U802TOCMAGIC :				rel  := new (Reloc32 )				if  err  := binary .Read (sr , binary .BigEndian , rel ); err  != nil  {					return  nil , err 				}				reloc .VirtualAddress  = uint64 (rel .Rvaddr )				reloc .Symbol  = idxToSym [int (rel .Rsymndx )]				reloc .Type  = rel .Rtype 				reloc .Length  = rel .Rsize &0x3F  + 1 				if  rel .Rsize &0x80  != 0  {					reloc .Signed  = true 				}				if  rel .Rsize &0x40  != 0  {					reloc .InstructionFixed  = true 				}			case  U64_TOCMAGIC :				rel  := new (Reloc64 )				if  err  := binary .Read (sr , binary .BigEndian , rel ); err  != nil  {					return  nil , err 				}				reloc .VirtualAddress  = rel .Rvaddr 				reloc .Symbol  = idxToSym [int (rel .Rsymndx )]				reloc .Type  = rel .Rtype 				reloc .Length  = rel .Rsize &0x3F  + 1 				if  rel .Rsize &0x80  != 0  {					reloc .Signed  = true 				}				if  rel .Rsize &0x40  != 0  {					reloc .InstructionFixed  = true 				}			}			sect .Relocs  = append (sect .Relocs , reloc )		}	}	return  f , nil }type  nobitsSectionReader struct {}func  (*nobitsSectionReader ) ReadAt (p  []byte , off  int64 ) (n  int , err  error ) {	return  0 , errors .New ("unexpected read from section with uninitialized data" )}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 [:n ], err }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 ) {		var  subtypes  = [...]uint32 {SSUBTYP_DWABREV , SSUBTYP_DWINFO , SSUBTYP_DWLINE , SSUBTYP_DWRNGES , 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 )}func  (f  *File ) readImportIDs (s  *Section ) ([]string , error ) {		if  _ , err  := s .sr .Seek (0 , io .SeekStart ); err  != nil  {		return  nil , err 	}	var  istlen  uint32 	var  nimpid  uint32 	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 	}		if  _ , err  := s .sr .Seek (int64 (impoff ), io .SeekStart ); err  != nil  {		return  nil , err 	}	table  := make ([]byte , istlen )	if  _ , err  := io .ReadFull (s .sr , table ); err  != nil  {		return  nil , err 	}	offset  := 0 		libpath  := cstring (table [offset :])	f .LibraryPaths  = strings .Split (libpath , ":" )	offset  += len (libpath ) + 3  	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  + "/"  + impidmem 		} else  {			path  = impidbase  + "/"  + impidmem 		}		all  = append (all , path )	}	return  all , nil }func  (f  *File ) ImportedSymbols () ([]ImportedSymbol , error ) {	s  := f .SectionByType (STYP_LOADER )	if  s  == nil  {		return  nil , nil 	}		if  _ , err  := s .sr .Seek (0 , io .SeekStart ); err  != nil  {		return  nil , err 	}	var  stlen  uint32 	var  stoff  uint64 	var  nsyms  uint32 	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 	}		if  _ , err  := s .sr .Seek (int64 (stoff ), io .SeekStart ); err  != nil  {		return  nil , err 	}	st  := make ([]byte , stlen )	if  _ , err  := io .ReadFull (s .sr , st ); err  != nil  {		return  nil , err 	}		libs , err  := f .readImportIDs (s )	if  err  != nil  {		return  nil , err 	}		if  _ , err  := s .sr .Seek (int64 (symoff ), io .SeekStart ); err  != nil  {		return  nil , err 	}	all  := make ([]ImportedSymbol , 0 )	for  i  := 0 ; i  < int (nsyms ); i ++ {		var  name  string 		var  ifile  uint32 		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  			}			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  			}			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 }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 } The pages are generated with Golds v0.7.9-preview . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101  (reachable from the left QR code) to get the latest news of Golds .