1
2
3
4
5 package macho
6
7 import (
8 "encoding/binary"
9 "io"
10 "os"
11 )
12
13
14 type FatFile struct {
15 Magic uint32
16 Arches []FatArch
17 closer io.Closer
18 }
19
20
21 type FatArchHeader struct {
22 Cpu Cpu
23 SubCpu uint32
24 Offset uint32
25 Size uint32
26 Align uint32
27 }
28
29 const fatArchHeaderSize = 5 * 4
30
31
32 type FatArch struct {
33 FatArchHeader
34 *File
35 }
36
37
38
39
40 func NewFatFile(r io.ReaderAt) (*FatFile, error) {
41 var ff FatFile
42 sr := io.NewSectionReader(r, 0, 1<<63-1)
43
44
45
46 err := binary.Read(sr, binary.BigEndian, &ff.Magic)
47 if err != nil {
48 return nil, formatError(0, "error reading magic number, %v", err)
49 } else if ff.Magic != MagicFat {
50
51
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 nil, formatError(0, "not a fat Mach-O file, leMagic=0x%x", leMagic)
57 } else {
58 return nil, formatError(0, "invalid magic number, leMagic=0x%x", leMagic)
59 }
60 }
61 offset := int64(4)
62
63
64 var narch uint32
65 err = binary.Read(sr, binary.BigEndian, &narch)
66 if err != nil {
67 return nil, formatError(offset, "invalid fat_header %v", err)
68 }
69 offset += 4
70
71 if narch < 1 {
72 return nil, formatError(offset, "file contains no images, narch=%d", narch)
73 }
74
75
76
77 seenArches := make(map[uint64]bool, narch)
78
79 var machoType HdrType
80
81
82
83 ff.Arches = make([]FatArch, narch)
84 for i := uint32(0); i < narch; i++ {
85 fa := &ff.Arches[i]
86 err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
87 if err != nil {
88 return nil, formatError(offset, "invalid fat_arch header, %v", err)
89 }
90 offset += fatArchHeaderSize
91
92 fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
93 fa.File, err = NewFile(fr)
94 if err != nil {
95 return nil, err
96 }
97
98
99 seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
100 if o, k := seenArches[seenArch]; o || k {
101 return nil, formatError(offset, "duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu)
102 }
103 seenArches[seenArch] = true
104
105
106 if i == 0 {
107 machoType = HdrType(fa.Type)
108 } else {
109 if HdrType(fa.Type) != machoType {
110 return nil, formatError(offset, "Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType)
111 }
112 }
113 }
114
115 return &ff, nil
116 }
117
118
119
120 func OpenFat(name string) (*FatFile, error) {
121 f, err := os.Open(name)
122 if err != nil {
123 return nil, err
124 }
125 ff, err := NewFatFile(f)
126 if err != nil {
127 f.Close()
128 return nil, err
129 }
130 ff.closer = f
131 return ff, nil
132 }
133
134 func (ff *FatFile) Close() 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
View as plain text