GoPLS Viewer

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