...

Source file src/debug/macho/fat.go

Documentation: debug/macho

		 1  // Copyright 2014 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package macho
		 6  
		 7  import (
		 8  	"encoding/binary"
		 9  	"fmt"
		10  	"io"
		11  	"os"
		12  )
		13  
		14  // A FatFile is a Mach-O universal binary that contains at least one architecture.
		15  type FatFile struct {
		16  	Magic	uint32
		17  	Arches []FatArch
		18  	closer io.Closer
		19  }
		20  
		21  // A FatArchHeader represents a fat header for a specific image architecture.
		22  type FatArchHeader struct {
		23  	Cpu		Cpu
		24  	SubCpu uint32
		25  	Offset uint32
		26  	Size	 uint32
		27  	Align	uint32
		28  }
		29  
		30  const fatArchHeaderSize = 5 * 4
		31  
		32  // A FatArch is a Mach-O File inside a FatFile.
		33  type FatArch struct {
		34  	FatArchHeader
		35  	*File
		36  }
		37  
		38  // ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
		39  // universal binary but may be a thin binary, based on its magic number.
		40  var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
		41  
		42  // NewFatFile creates a new FatFile for accessing all the Mach-O images in a
		43  // universal binary. The Mach-O binary is expected to start at position 0 in
		44  // the ReaderAt.
		45  func NewFatFile(r io.ReaderAt) (*FatFile, error) {
		46  	var ff FatFile
		47  	sr := io.NewSectionReader(r, 0, 1<<63-1)
		48  
		49  	// Read the fat_header struct, which is always in big endian.
		50  	// Start with the magic number.
		51  	err := binary.Read(sr, binary.BigEndian, &ff.Magic)
		52  	if err != nil {
		53  		return nil, &FormatError{0, "error reading magic number", nil}
		54  	} else if ff.Magic != MagicFat {
		55  		// See if this is a Mach-O file via its magic number. The magic
		56  		// must be converted to little endian first though.
		57  		var buf [4]byte
		58  		binary.BigEndian.PutUint32(buf[:], ff.Magic)
		59  		leMagic := binary.LittleEndian.Uint32(buf[:])
		60  		if leMagic == Magic32 || leMagic == Magic64 {
		61  			return nil, ErrNotFat
		62  		} else {
		63  			return nil, &FormatError{0, "invalid magic number", nil}
		64  		}
		65  	}
		66  	offset := int64(4)
		67  
		68  	// Read the number of FatArchHeaders that come after the fat_header.
		69  	var narch uint32
		70  	err = binary.Read(sr, binary.BigEndian, &narch)
		71  	if err != nil {
		72  		return nil, &FormatError{offset, "invalid fat_header", nil}
		73  	}
		74  	offset += 4
		75  
		76  	if narch < 1 {
		77  		return nil, &FormatError{offset, "file contains no images", nil}
		78  	}
		79  
		80  	// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
		81  	// there are not duplicate architectures.
		82  	seenArches := make(map[uint64]bool, narch)
		83  	// Make sure that all images are for the same MH_ type.
		84  	var machoType Type
		85  
		86  	// Following the fat_header comes narch fat_arch structs that index
		87  	// Mach-O images further in the file.
		88  	ff.Arches = make([]FatArch, narch)
		89  	for i := uint32(0); i < narch; i++ {
		90  		fa := &ff.Arches[i]
		91  		err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
		92  		if err != nil {
		93  			return nil, &FormatError{offset, "invalid fat_arch header", nil}
		94  		}
		95  		offset += fatArchHeaderSize
		96  
		97  		fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
		98  		fa.File, err = NewFile(fr)
		99  		if err != nil {
	 100  			return nil, err
	 101  		}
	 102  
	 103  		// Make sure the architecture for this image is not duplicate.
	 104  		seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
	 105  		if o, k := seenArches[seenArch]; o || k {
	 106  			return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
	 107  		}
	 108  		seenArches[seenArch] = true
	 109  
	 110  		// Make sure the Mach-O type matches that of the first image.
	 111  		if i == 0 {
	 112  			machoType = fa.Type
	 113  		} else {
	 114  			if fa.Type != machoType {
	 115  				return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
	 116  			}
	 117  		}
	 118  	}
	 119  
	 120  	return &ff, nil
	 121  }
	 122  
	 123  // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
	 124  // universal binary.
	 125  func OpenFat(name string) (*FatFile, error) {
	 126  	f, err := os.Open(name)
	 127  	if err != nil {
	 128  		return nil, err
	 129  	}
	 130  	ff, err := NewFatFile(f)
	 131  	if err != nil {
	 132  		f.Close()
	 133  		return nil, err
	 134  	}
	 135  	ff.closer = f
	 136  	return ff, nil
	 137  }
	 138  
	 139  func (ff *FatFile) Close() error {
	 140  	var err error
	 141  	if ff.closer != nil {
	 142  		err = ff.closer.Close()
	 143  		ff.closer = nil
	 144  	}
	 145  	return err
	 146  }
	 147  

View as plain text