Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / 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
5 package macho
6
7 import (
8         "encoding/binary"
9         "io"
10         "os"
11 )
12
13 // A FatFile is a Mach-O universal binary that contains at least one architecture.
14 type 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.
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 // A FatArch is a Mach-O File inside a FatFile.
32 type 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.
40 func NewFatFile(r io.ReaderAt) (*FatFile, error) {
41         var ff FatFile
42         sr := io.NewSectionReader(r, 0, 1<<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(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                 // 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 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         // Read the number of FatArchHeaders that come after the fat_header.
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         // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
76         // there are not duplicate architectures.
77         seenArches := make(map[uint64]bool, narch)
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([]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                 // Make sure the architecture for this image is not duplicate.
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                 // 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 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 // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
119 // universal binary.
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 }