Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / cmd / splitdwarf / internal / macho / file.go
1 // Copyright 2009 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 implements access to Mach-O object files.
6 package macho
7
8 // High level access to low level data structures.
9
10 import (
11         "bytes"
12         "compress/zlib"
13         "debug/dwarf"
14         "encoding/binary"
15         "fmt"
16         "io"
17         "os"
18         "strings"
19         "unsafe"
20 )
21
22 // A File represents an open Mach-O file.
23 type File struct {
24         FileTOC
25
26         Symtab   *Symtab
27         Dysymtab *Dysymtab
28
29         closer io.Closer
30 }
31
32 type FileTOC struct {
33         FileHeader
34         ByteOrder binary.ByteOrder
35         Loads     []Load
36         Sections  []*Section
37 }
38
39 func (t *FileTOC) AddLoad(l Load) {
40         t.Loads = append(t.Loads, l)
41         t.NCommands++
42         t.SizeCommands += l.LoadSize(t)
43 }
44
45 // AddSegment adds segment s to the file table of contents,
46 // and also zeroes out the segment information with the expectation
47 // that this will be added next.
48 func (t *FileTOC) AddSegment(s *Segment) {
49         t.AddLoad(s)
50         s.Nsect = 0
51         s.Firstsect = 0
52 }
53
54 // Adds section to the most recently added Segment
55 func (t *FileTOC) AddSection(s *Section) {
56         g := t.Loads[len(t.Loads)-1].(*Segment)
57         if g.Nsect == 0 {
58                 g.Firstsect = uint32(len(t.Sections))
59         }
60         g.Nsect++
61         t.Sections = append(t.Sections, s)
62         sectionsize := uint32(unsafe.Sizeof(Section32{}))
63         if g.Command() == LcSegment64 {
64                 sectionsize = uint32(unsafe.Sizeof(Section64{}))
65         }
66         t.SizeCommands += sectionsize
67         g.Len += sectionsize
68 }
69
70 // A Load represents any Mach-O load command.
71 type Load interface {
72         String() string
73         Command() LoadCmd
74         LoadSize(*FileTOC) uint32 // Need the TOC for alignment, sigh.
75         Put([]byte, binary.ByteOrder) int
76
77         // command LC_DYLD_INFO_ONLY contains offsets into __LINKEDIT
78         // e.g., from "otool -l a.out"
79         //
80         //      Load command 3
81         //       cmd LC_SEGMENT_64
82         //   cmdsize 72
83         //   segname __LINKEDIT
84         //    vmaddr 0x0000000100002000
85         //    vmsize 0x0000000000001000
86         //   fileoff 8192
87         //  filesize 520
88         //   maxprot 0x00000007
89         //  initprot 0x00000001
90         //    nsects 0
91         //     flags 0x0
92         // Load command 4
93         //             cmd LC_DYLD_INFO_ONLY
94         //         cmdsize 48
95         //      rebase_off 8192
96         //     rebase_size 8
97         //        bind_off 8200
98         //       bind_size 24
99         //   weak_bind_off 0
100         //  weak_bind_size 0
101         //   lazy_bind_off 8224
102         //  lazy_bind_size 16
103         //      export_off 8240
104         //     export_size 48
105 }
106
107 // LoadBytes is the uninterpreted bytes of a Mach-O load command.
108 type LoadBytes []byte
109
110 // A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
111 type SegmentHeader struct {
112         LoadCmd
113         Len       uint32
114         Name      string // 16 characters or fewer
115         Addr      uint64 // memory address
116         Memsz     uint64 // memory size
117         Offset    uint64 // file offset
118         Filesz    uint64 // number of bytes starting at that file offset
119         Maxprot   uint32
120         Prot      uint32
121         Nsect     uint32
122         Flag      SegFlags
123         Firstsect uint32
124 }
125
126 // A Segment represents a Mach-O 32-bit or 64-bit load segment command.
127 type Segment struct {
128         SegmentHeader
129
130         // Embed ReaderAt for ReadAt method.
131         // Do not embed SectionReader directly
132         // to avoid having Read and Seek.
133         // If a client wants Read and Seek it must use
134         // Open() to avoid fighting over the seek offset
135         // with other clients.
136         io.ReaderAt
137         sr *io.SectionReader
138 }
139
140 func (s *Segment) Put32(b []byte, o binary.ByteOrder) int {
141         o.PutUint32(b[0*4:], uint32(s.LoadCmd))
142         o.PutUint32(b[1*4:], s.Len)
143         putAtMost16Bytes(b[2*4:], s.Name)
144         o.PutUint32(b[6*4:], uint32(s.Addr))
145         o.PutUint32(b[7*4:], uint32(s.Memsz))
146         o.PutUint32(b[8*4:], uint32(s.Offset))
147         o.PutUint32(b[9*4:], uint32(s.Filesz))
148         o.PutUint32(b[10*4:], s.Maxprot)
149         o.PutUint32(b[11*4:], s.Prot)
150         o.PutUint32(b[12*4:], s.Nsect)
151         o.PutUint32(b[13*4:], uint32(s.Flag))
152         return 14 * 4
153 }
154
155 func (s *Segment) Put64(b []byte, o binary.ByteOrder) int {
156         o.PutUint32(b[0*4:], uint32(s.LoadCmd))
157         o.PutUint32(b[1*4:], s.Len)
158         putAtMost16Bytes(b[2*4:], s.Name)
159         o.PutUint64(b[6*4+0*8:], s.Addr)
160         o.PutUint64(b[6*4+1*8:], s.Memsz)
161         o.PutUint64(b[6*4+2*8:], s.Offset)
162         o.PutUint64(b[6*4+3*8:], s.Filesz)
163         o.PutUint32(b[6*4+4*8:], s.Maxprot)
164         o.PutUint32(b[7*4+4*8:], s.Prot)
165         o.PutUint32(b[8*4+4*8:], s.Nsect)
166         o.PutUint32(b[9*4+4*8:], uint32(s.Flag))
167         return 10*4 + 4*8
168 }
169
170 // LoadCmdBytes is a command-tagged sequence of bytes.
171 // This is used for Load Commands that are not (yet)
172 // interesting to us, and to common up this behavior for
173 // all those that are.
174 type LoadCmdBytes struct {
175         LoadCmd
176         LoadBytes
177 }
178
179 type SectionHeader struct {
180         Name      string
181         Seg       string
182         Addr      uint64
183         Size      uint64
184         Offset    uint32
185         Align     uint32
186         Reloff    uint32
187         Nreloc    uint32
188         Flags     SecFlags
189         Reserved1 uint32
190         Reserved2 uint32
191         Reserved3 uint32 // only present if original was 64-bit
192 }
193
194 // A Reloc represents a Mach-O relocation.
195 type Reloc struct {
196         Addr  uint32
197         Value uint32
198         // when Scattered == false && Extern == true, Value is the symbol number.
199         // when Scattered == false && Extern == false, Value is the section number.
200         // when Scattered == true, Value is the value that this reloc refers to.
201         Type      uint8
202         Len       uint8 // 0=byte, 1=word, 2=long, 3=quad
203         Pcrel     bool
204         Extern    bool // valid if Scattered == false
205         Scattered bool
206 }
207
208 type Section struct {
209         SectionHeader
210         Relocs []Reloc
211
212         // Embed ReaderAt for ReadAt method.
213         // Do not embed SectionReader directly
214         // to avoid having Read and Seek.
215         // If a client wants Read and Seek it must use
216         // Open() to avoid fighting over the seek offset
217         // with other clients.
218         io.ReaderAt
219         sr *io.SectionReader
220 }
221
222 func (s *Section) Put32(b []byte, o binary.ByteOrder) int {
223         putAtMost16Bytes(b[0:], s.Name)
224         putAtMost16Bytes(b[16:], s.Seg)
225         o.PutUint32(b[8*4:], uint32(s.Addr))
226         o.PutUint32(b[9*4:], uint32(s.Size))
227         o.PutUint32(b[10*4:], s.Offset)
228         o.PutUint32(b[11*4:], s.Align)
229         o.PutUint32(b[12*4:], s.Reloff)
230         o.PutUint32(b[13*4:], s.Nreloc)
231         o.PutUint32(b[14*4:], uint32(s.Flags))
232         o.PutUint32(b[15*4:], s.Reserved1)
233         o.PutUint32(b[16*4:], s.Reserved2)
234         a := 17 * 4
235         return a + s.PutRelocs(b[a:], o)
236 }
237
238 func (s *Section) Put64(b []byte, o binary.ByteOrder) int {
239         putAtMost16Bytes(b[0:], s.Name)
240         putAtMost16Bytes(b[16:], s.Seg)
241         o.PutUint64(b[8*4+0*8:], s.Addr)
242         o.PutUint64(b[8*4+1*8:], s.Size)
243         o.PutUint32(b[8*4+2*8:], s.Offset)
244         o.PutUint32(b[9*4+2*8:], s.Align)
245         o.PutUint32(b[10*4+2*8:], s.Reloff)
246         o.PutUint32(b[11*4+2*8:], s.Nreloc)
247         o.PutUint32(b[12*4+2*8:], uint32(s.Flags))
248         o.PutUint32(b[13*4+2*8:], s.Reserved1)
249         o.PutUint32(b[14*4+2*8:], s.Reserved2)
250         o.PutUint32(b[15*4+2*8:], s.Reserved3)
251         a := 16*4 + 2*8
252         return a + s.PutRelocs(b[a:], o)
253 }
254
255 func (s *Section) PutRelocs(b []byte, o binary.ByteOrder) int {
256         a := 0
257         for _, r := range s.Relocs {
258                 var ri relocInfo
259                 typ := uint32(r.Type) & (1<<4 - 1)
260                 len := uint32(r.Len) & (1<<2 - 1)
261                 pcrel := uint32(0)
262                 if r.Pcrel {
263                         pcrel = 1
264                 }
265                 ext := uint32(0)
266                 if r.Extern {
267                         ext = 1
268                 }
269                 switch {
270                 case r.Scattered:
271                         ri.Addr = r.Addr&(1<<24-1) | typ<<24 | len<<28 | 1<<31 | pcrel<<30
272                         ri.Symnum = r.Value
273                 case o == binary.LittleEndian:
274                         ri.Addr = r.Addr
275                         ri.Symnum = r.Value&(1<<24-1) | pcrel<<24 | len<<25 | ext<<27 | typ<<28
276                 case o == binary.BigEndian:
277                         ri.Addr = r.Addr
278                         ri.Symnum = r.Value<<8 | pcrel<<7 | len<<5 | ext<<4 | typ
279                 }
280                 o.PutUint32(b, ri.Addr)
281                 o.PutUint32(b[4:], ri.Symnum)
282                 a += 8
283                 b = b[8:]
284         }
285         return a
286 }
287
288 func putAtMost16Bytes(b []byte, n string) {
289         for i := range n { // at most 16 bytes
290                 if i == 16 {
291                         break
292                 }
293                 b[i] = n[i]
294         }
295 }
296
297 // A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
298 type Symbol struct {
299         Name  string
300         Type  uint8
301         Sect  uint8
302         Desc  uint16
303         Value uint64
304 }
305
306 /*
307  * Mach-O reader
308  */
309
310 // FormatError is returned by some operations if the data does
311 // not have the correct format for an object file.
312 type FormatError struct {
313         off int64
314         msg string
315 }
316
317 func formatError(off int64, format string, data ...interface{}) *FormatError {
318         return &FormatError{off, fmt.Sprintf(format, data...)}
319 }
320
321 func (e *FormatError) Error() string {
322         return e.msg + fmt.Sprintf(" in record at byte %#x", e.off)
323 }
324
325 func (e *FormatError) String() string {
326         return e.Error()
327 }
328
329 // DerivedCopy returns a modified copy of the TOC, with empty loads and sections,
330 // and with the specified header type and flags.
331 func (t *FileTOC) DerivedCopy(Type HdrType, Flags HdrFlags) *FileTOC {
332         h := t.FileHeader
333         h.NCommands, h.SizeCommands, h.Type, h.Flags = 0, 0, Type, Flags
334
335         return &FileTOC{FileHeader: h, ByteOrder: t.ByteOrder}
336 }
337
338 // TOCSize returns the size in bytes of the object file representation
339 // of the header and Load Commands (including Segments and Sections, but
340 // not their contents) at the beginning of a Mach-O file.  This typically
341 // overlaps the text segment in the object file.
342 func (t *FileTOC) TOCSize() uint32 {
343         return t.HdrSize() + t.LoadSize()
344 }
345
346 // LoadAlign returns the required alignment of Load commands in a binary.
347 // This is used to add padding for necessary alignment.
348 func (t *FileTOC) LoadAlign() uint64 {
349         if t.Magic == Magic64 {
350                 return 8
351         }
352         return 4
353 }
354
355 // SymbolSize returns the size in bytes of a Symbol (Nlist32 or Nlist64)
356 func (t *FileTOC) SymbolSize() uint32 {
357         if t.Magic == Magic64 {
358                 return uint32(unsafe.Sizeof(Nlist64{}))
359         }
360         return uint32(unsafe.Sizeof(Nlist32{}))
361 }
362
363 // HdrSize returns the size in bytes of the Macho header for a given
364 // magic number (where the magic number has been appropriately byte-swapped).
365 func (t *FileTOC) HdrSize() uint32 {
366         switch t.Magic {
367         case Magic32:
368                 return fileHeaderSize32
369         case Magic64:
370                 return fileHeaderSize64
371         case MagicFat:
372                 panic("MagicFat not handled yet")
373         default:
374                 panic(fmt.Sprintf("Unexpected magic number 0x%x, expected Mach-O object file", t.Magic))
375         }
376 }
377
378 // LoadSize returns the size of all the load commands in a file's table-of contents
379 // (but not their associated data, e.g., sections and symbol tables)
380 func (t *FileTOC) LoadSize() uint32 {
381         cmdsz := uint32(0)
382         for _, l := range t.Loads {
383                 s := l.LoadSize(t)
384                 cmdsz += s
385         }
386         return cmdsz
387 }
388
389 // FileSize returns the size in bytes of the header, load commands, and the
390 // in-file contents of all the segments and sections included in those
391 // load commands, accounting for their offsets within the file.
392 func (t *FileTOC) FileSize() uint64 {
393         sz := uint64(t.LoadSize()) // ought to be contained in text segment, but just in case.
394         for _, l := range t.Loads {
395                 if s, ok := l.(*Segment); ok {
396                         if m := s.Offset + s.Filesz; m > sz {
397                                 sz = m
398                         }
399                 }
400         }
401         return sz
402 }
403
404 // Put writes the header and all load commands to buffer, using
405 // the byte ordering specified in FileTOC t.  For sections, this
406 // writes the headers that come in-line with the segment Load commands,
407 // but does not write the reference data for those sections.
408 func (t *FileTOC) Put(buffer []byte) int {
409         next := t.FileHeader.Put(buffer, t.ByteOrder)
410         for _, l := range t.Loads {
411                 if s, ok := l.(*Segment); ok {
412                         switch t.Magic {
413                         case Magic64:
414                                 next += s.Put64(buffer[next:], t.ByteOrder)
415                                 for i := uint32(0); i < s.Nsect; i++ {
416                                         c := t.Sections[i+s.Firstsect]
417                                         next += c.Put64(buffer[next:], t.ByteOrder)
418                                 }
419                         case Magic32:
420                                 next += s.Put32(buffer[next:], t.ByteOrder)
421                                 for i := uint32(0); i < s.Nsect; i++ {
422                                         c := t.Sections[i+s.Firstsect]
423                                         next += c.Put32(buffer[next:], t.ByteOrder)
424                                 }
425                         default:
426                                 panic(fmt.Sprintf("Unexpected magic number 0x%x", t.Magic))
427                         }
428
429                 } else {
430                         next += l.Put(buffer[next:], t.ByteOrder)
431                 }
432         }
433         return next
434 }
435
436 // UncompressedSize returns the size of the segment with its sections uncompressed, ignoring
437 // its offset within the file.  The returned size is rounded up to the power of two in align.
438 func (s *Segment) UncompressedSize(t *FileTOC, align uint64) uint64 {
439         sz := uint64(0)
440         for j := uint32(0); j < s.Nsect; j++ {
441                 c := t.Sections[j+s.Firstsect]
442                 sz += c.UncompressedSize()
443         }
444         return (sz + align - 1) & uint64(-int64(align))
445 }
446
447 func (s *Section) UncompressedSize() uint64 {
448         if !strings.HasPrefix(s.Name, "__z") {
449                 return s.Size
450         }
451         b := make([]byte, 12)
452         n, err := s.sr.ReadAt(b, 0)
453         if err != nil {
454                 panic("Malformed object file")
455         }
456         if n != len(b) {
457                 return s.Size
458         }
459         if string(b[:4]) == "ZLIB" {
460                 return binary.BigEndian.Uint64(b[4:12])
461         }
462         return s.Size
463 }
464
465 func (s *Section) PutData(b []byte) {
466         bb := b[0:s.Size]
467         n, err := s.sr.ReadAt(bb, 0)
468         if err != nil || uint64(n) != s.Size {
469                 panic("Malformed object file (ReadAt error)")
470         }
471 }
472
473 func (s *Section) PutUncompressedData(b []byte) {
474         if strings.HasPrefix(s.Name, "__z") {
475                 bb := make([]byte, 12)
476                 n, err := s.sr.ReadAt(bb, 0)
477                 if err != nil {
478                         panic("Malformed object file")
479                 }
480                 if n == len(bb) && string(bb[:4]) == "ZLIB" {
481                         size := binary.BigEndian.Uint64(bb[4:12])
482                         // Decompress starting at b[12:]
483                         r, err := zlib.NewReader(io.NewSectionReader(s, 12, int64(size)-12))
484                         if err != nil {
485                                 panic("Malformed object file (zlib.NewReader error)")
486                         }
487                         n, err := io.ReadFull(r, b[0:size])
488                         if err != nil {
489                                 panic("Malformed object file (ReadFull error)")
490                         }
491                         if uint64(n) != size {
492                                 panic(fmt.Sprintf("PutUncompressedData, expected to read %d bytes, instead read %d", size, n))
493                         }
494                         if err := r.Close(); err != nil {
495                                 panic("Malformed object file (Close error)")
496                         }
497                         return
498                 }
499         }
500         // Not compressed
501         s.PutData(b)
502 }
503
504 func (b LoadBytes) String() string {
505         s := "["
506         for i, a := range b {
507                 if i > 0 {
508                         s += " "
509                         if len(b) > 48 && i >= 16 {
510                                 s += fmt.Sprintf("... (%d bytes)", len(b))
511                                 break
512                         }
513                 }
514                 s += fmt.Sprintf("%x", a)
515         }
516         s += "]"
517         return s
518 }
519
520 func (b LoadBytes) Raw() []byte                { return b }
521 func (b LoadBytes) Copy() LoadBytes            { return LoadBytes(append([]byte{}, b...)) }
522 func (b LoadBytes) LoadSize(t *FileTOC) uint32 { return uint32(len(b)) }
523
524 func (lc LoadCmd) Put(b []byte, o binary.ByteOrder) int {
525         panic(fmt.Sprintf("Put not implemented for %s", lc.String()))
526 }
527
528 func (s LoadCmdBytes) String() string {
529         return s.LoadCmd.String() + ": " + s.LoadBytes.String()
530 }
531 func (s LoadCmdBytes) Copy() LoadCmdBytes {
532         return LoadCmdBytes{LoadCmd: s.LoadCmd, LoadBytes: s.LoadBytes.Copy()}
533 }
534
535 func (s *SegmentHeader) String() string {
536         return fmt.Sprintf(
537                 "Seg %s, len=0x%x, addr=0x%x, memsz=0x%x, offset=0x%x, filesz=0x%x, maxprot=0x%x, prot=0x%x, nsect=%d, flag=0x%x, firstsect=%d",
538                 s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect)
539 }
540
541 func (s *Segment) String() string {
542         return fmt.Sprintf(
543                 "Seg %s, len=0x%x, addr=0x%x, memsz=0x%x, offset=0x%x, filesz=0x%x, maxprot=0x%x, prot=0x%x, nsect=%d, flag=0x%x, firstsect=%d",
544                 s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect)
545 }
546
547 // Data reads and returns the contents of the segment.
548 func (s *Segment) Data() ([]byte, error) {
549         dat := make([]byte, s.sr.Size())
550         n, err := s.sr.ReadAt(dat, 0)
551         if n == len(dat) {
552                 err = nil
553         }
554         return dat[0:n], err
555 }
556
557 func (s *Segment) Copy() *Segment {
558         r := &Segment{SegmentHeader: s.SegmentHeader}
559         return r
560 }
561 func (s *Segment) CopyZeroed() *Segment {
562         r := s.Copy()
563         r.Filesz = 0
564         r.Offset = 0
565         r.Nsect = 0
566         r.Firstsect = 0
567         if s.Command() == LcSegment64 {
568                 r.Len = uint32(unsafe.Sizeof(Segment64{}))
569         } else {
570                 r.Len = uint32(unsafe.Sizeof(Segment32{}))
571         }
572         return r
573 }
574
575 func (s *Segment) LoadSize(t *FileTOC) uint32 {
576         if s.Command() == LcSegment64 {
577                 return uint32(unsafe.Sizeof(Segment64{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section64{}))
578         }
579         return uint32(unsafe.Sizeof(Segment32{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section32{}))
580 }
581
582 // Open returns a new ReadSeeker reading the segment.
583 func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
584
585 // Data reads and returns the contents of the Mach-O section.
586 func (s *Section) Data() ([]byte, error) {
587         dat := make([]byte, s.sr.Size())
588         n, err := s.sr.ReadAt(dat, 0)
589         if n == len(dat) {
590                 err = nil
591         }
592         return dat[0:n], err
593 }
594
595 func (s *Section) Copy() *Section {
596         return &Section{SectionHeader: s.SectionHeader}
597 }
598
599 // Open returns a new ReadSeeker reading the Mach-O section.
600 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
601
602 // A Dylib represents a Mach-O load dynamic library command.
603 type Dylib struct {
604         DylibCmd
605         Name           string
606         Time           uint32
607         CurrentVersion uint32
608         CompatVersion  uint32
609 }
610
611 func (s *Dylib) String() string { return "Dylib " + s.Name }
612 func (s *Dylib) Copy() *Dylib {
613         r := *s
614         return &r
615 }
616 func (s *Dylib) LoadSize(t *FileTOC) uint32 {
617         return uint32(RoundUp(uint64(unsafe.Sizeof(DylibCmd{}))+uint64(len(s.Name)), t.LoadAlign()))
618 }
619
620 type Dylinker struct {
621         DylinkerCmd // shared by 3 commands, need the LoadCmd
622         Name        string
623 }
624
625 func (s *Dylinker) String() string { return s.DylinkerCmd.LoadCmd.String() + " " + s.Name }
626 func (s *Dylinker) Copy() *Dylinker {
627         return &Dylinker{DylinkerCmd: s.DylinkerCmd, Name: s.Name}
628 }
629 func (s *Dylinker) LoadSize(t *FileTOC) uint32 {
630         return uint32(RoundUp(uint64(unsafe.Sizeof(DylinkerCmd{}))+uint64(len(s.Name)), t.LoadAlign()))
631 }
632
633 // A Symtab represents a Mach-O symbol table command.
634 type Symtab struct {
635         SymtabCmd
636         Syms []Symbol
637 }
638
639 func (s *Symtab) Put(b []byte, o binary.ByteOrder) int {
640         o.PutUint32(b[0*4:], uint32(s.LoadCmd))
641         o.PutUint32(b[1*4:], s.Len)
642         o.PutUint32(b[2*4:], s.Symoff)
643         o.PutUint32(b[3*4:], s.Nsyms)
644         o.PutUint32(b[4*4:], s.Stroff)
645         o.PutUint32(b[5*4:], s.Strsize)
646         return 6 * 4
647 }
648
649 func (s *Symtab) String() string { return fmt.Sprintf("Symtab %#v", s.SymtabCmd) }
650 func (s *Symtab) Copy() *Symtab {
651         return &Symtab{SymtabCmd: s.SymtabCmd, Syms: append([]Symbol{}, s.Syms...)}
652 }
653 func (s *Symtab) LoadSize(t *FileTOC) uint32 {
654         return uint32(unsafe.Sizeof(SymtabCmd{}))
655 }
656
657 type LinkEditData struct {
658         LinkEditDataCmd
659 }
660
661 func (s *LinkEditData) String() string { return "LinkEditData " + s.LoadCmd.String() }
662 func (s *LinkEditData) Copy() *LinkEditData {
663         return &LinkEditData{LinkEditDataCmd: s.LinkEditDataCmd}
664 }
665 func (s *LinkEditData) LoadSize(t *FileTOC) uint32 {
666         return uint32(unsafe.Sizeof(LinkEditDataCmd{}))
667 }
668
669 type Uuid struct {
670         UuidCmd
671 }
672
673 func (s *Uuid) String() string {
674         return fmt.Sprintf("Uuid %X-%X-%X-%X-%X",
675                 s.Id[0:4], s.Id[4:6], s.Id[6:8], s.Id[8:10], s.Id[10:16])
676 } // 8-4-4-4-12
677 func (s *Uuid) Copy() *Uuid {
678         return &Uuid{UuidCmd: s.UuidCmd}
679 }
680 func (s *Uuid) LoadSize(t *FileTOC) uint32 {
681         return uint32(unsafe.Sizeof(UuidCmd{}))
682 }
683 func (s *Uuid) Put(b []byte, o binary.ByteOrder) int {
684         o.PutUint32(b[0*4:], uint32(s.LoadCmd))
685         o.PutUint32(b[1*4:], s.Len)
686         copy(b[2*4:], s.Id[0:])
687         return int(s.Len)
688 }
689
690 type DyldInfo struct {
691         DyldInfoCmd
692 }
693
694 func (s *DyldInfo) String() string { return "DyldInfo " + s.LoadCmd.String() }
695 func (s *DyldInfo) Copy() *DyldInfo {
696         return &DyldInfo{DyldInfoCmd: s.DyldInfoCmd}
697 }
698 func (s *DyldInfo) LoadSize(t *FileTOC) uint32 {
699         return uint32(unsafe.Sizeof(DyldInfoCmd{}))
700 }
701
702 type EncryptionInfo struct {
703         EncryptionInfoCmd
704 }
705
706 func (s *EncryptionInfo) String() string { return "EncryptionInfo " + s.LoadCmd.String() }
707 func (s *EncryptionInfo) Copy() *EncryptionInfo {
708         return &EncryptionInfo{EncryptionInfoCmd: s.EncryptionInfoCmd}
709 }
710 func (s *EncryptionInfo) LoadSize(t *FileTOC) uint32 {
711         return uint32(unsafe.Sizeof(EncryptionInfoCmd{}))
712 }
713
714 // A Dysymtab represents a Mach-O dynamic symbol table command.
715 type Dysymtab struct {
716         DysymtabCmd
717         IndirectSyms []uint32 // indices into Symtab.Syms
718 }
719
720 func (s *Dysymtab) String() string { return fmt.Sprintf("Dysymtab %#v", s.DysymtabCmd) }
721 func (s *Dysymtab) Copy() *Dysymtab {
722         return &Dysymtab{DysymtabCmd: s.DysymtabCmd, IndirectSyms: append([]uint32{}, s.IndirectSyms...)}
723 }
724 func (s *Dysymtab) LoadSize(t *FileTOC) uint32 {
725         return uint32(unsafe.Sizeof(DysymtabCmd{}))
726 }
727
728 // A Rpath represents a Mach-O rpath command.
729 type Rpath struct {
730         LoadCmd
731         Path string
732 }
733
734 func (s *Rpath) String() string   { return "Rpath " + s.Path }
735 func (s *Rpath) Command() LoadCmd { return LcRpath }
736 func (s *Rpath) Copy() *Rpath {
737         return &Rpath{Path: s.Path}
738 }
739 func (s *Rpath) LoadSize(t *FileTOC) uint32 {
740         return uint32(RoundUp(uint64(unsafe.Sizeof(RpathCmd{}))+uint64(len(s.Path)), t.LoadAlign()))
741 }
742
743 // Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
744 func Open(name string) (*File, error) {
745         f, err := os.Open(name)
746         if err != nil {
747                 return nil, err
748         }
749         ff, err := NewFile(f)
750         if err != nil {
751                 f.Close()
752                 return nil, err
753         }
754         ff.closer = f
755         return ff, nil
756 }
757
758 // Close closes the File.
759 // If the File was created using NewFile directly instead of Open,
760 // Close has no effect.
761 func (f *File) Close() error {
762         var err error
763         if f.closer != nil {
764                 err = f.closer.Close()
765                 f.closer = nil
766         }
767         return err
768 }
769
770 // NewFile creates a new File for accessing a Mach-O binary in an underlying reader.
771 // The Mach-O binary is expected to start at position 0 in the ReaderAt.
772 func NewFile(r io.ReaderAt) (*File, error) {
773         f := new(File)
774         sr := io.NewSectionReader(r, 0, 1<<63-1)
775
776         // Read and decode Mach magic to determine byte order, size.
777         // Magic32 and Magic64 differ only in the bottom bit.
778         var ident [4]byte
779         if _, err := r.ReadAt(ident[0:], 0); err != nil {
780                 return nil, err
781         }
782         be := binary.BigEndian.Uint32(ident[0:])
783         le := binary.LittleEndian.Uint32(ident[0:])
784         switch Magic32 &^ 1 {
785         case be &^ 1:
786                 f.ByteOrder = binary.BigEndian
787                 f.Magic = be
788         case le &^ 1:
789                 f.ByteOrder = binary.LittleEndian
790                 f.Magic = le
791         default:
792                 return nil, formatError(0, "invalid magic number be=0x%x, le=0x%x", be, le)
793         }
794
795         // Read entire file header.
796         if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
797                 return nil, err
798         }
799
800         // Then load commands.
801         offset := int64(fileHeaderSize32)
802         if f.Magic == Magic64 {
803                 offset = fileHeaderSize64
804         }
805         dat := make([]byte, f.SizeCommands)
806         if _, err := r.ReadAt(dat, offset); err != nil {
807                 return nil, err
808         }
809         f.Loads = make([]Load, f.NCommands)
810         bo := f.ByteOrder
811         for i := range f.Loads {
812                 // Each load command begins with uint32 command and length.
813                 if len(dat) < 8 {
814                         return nil, formatError(offset, "command block too small, len(dat) = %d", len(dat))
815                 }
816                 cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
817                 if siz < 8 || siz > uint32(len(dat)) {
818                         return nil, formatError(offset, "invalid command block size, len(dat)=%d, size=%d", len(dat), siz)
819                 }
820                 var cmddat []byte
821                 cmddat, dat = dat[0:siz], dat[siz:]
822                 offset += int64(siz)
823                 var s *Segment
824                 switch cmd {
825                 default:
826                         f.Loads[i] = LoadCmdBytes{LoadCmd(cmd), LoadBytes(cmddat)}
827
828                 case LcUuid:
829                         var hdr UuidCmd
830                         b := bytes.NewReader(cmddat)
831                         if err := binary.Read(b, bo, &hdr); err != nil {
832                                 return nil, err
833                         }
834                         l := &Uuid{UuidCmd: hdr}
835
836                         f.Loads[i] = l
837
838                 case LcRpath:
839                         var hdr RpathCmd
840                         b := bytes.NewReader(cmddat)
841                         if err := binary.Read(b, bo, &hdr); err != nil {
842                                 return nil, err
843                         }
844                         l := &Rpath{LoadCmd: hdr.LoadCmd}
845                         if hdr.Path >= uint32(len(cmddat)) {
846                                 return nil, formatError(offset, "invalid path in rpath command, len(cmddat)=%d, hdr.Path=%d", len(cmddat), hdr.Path)
847                         }
848                         l.Path = cstring(cmddat[hdr.Path:])
849                         f.Loads[i] = l
850
851                 case LcLoadDylinker, LcIdDylinker, LcDyldEnvironment:
852                         var hdr DylinkerCmd
853                         b := bytes.NewReader(cmddat)
854                         if err := binary.Read(b, bo, &hdr); err != nil {
855                                 return nil, err
856                         }
857                         l := new(Dylinker)
858                         if hdr.Name >= uint32(len(cmddat)) {
859                                 return nil, formatError(offset, "invalid name in dynamic linker command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat))
860                         }
861                         l.Name = cstring(cmddat[hdr.Name:])
862                         l.DylinkerCmd = hdr
863                         f.Loads[i] = l
864
865                 case LcDylib:
866                         var hdr DylibCmd
867                         b := bytes.NewReader(cmddat)
868                         if err := binary.Read(b, bo, &hdr); err != nil {
869                                 return nil, err
870                         }
871                         l := new(Dylib)
872                         if hdr.Name >= uint32(len(cmddat)) {
873                                 return nil, formatError(offset, "invalid name in dynamic library command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat))
874                         }
875                         l.Name = cstring(cmddat[hdr.Name:])
876                         l.Time = hdr.Time
877                         l.CurrentVersion = hdr.CurrentVersion
878                         l.CompatVersion = hdr.CompatVersion
879                         f.Loads[i] = l
880
881                 case LcSymtab:
882                         var hdr SymtabCmd
883                         b := bytes.NewReader(cmddat)
884                         if err := binary.Read(b, bo, &hdr); err != nil {
885                                 return nil, err
886                         }
887                         strtab := make([]byte, hdr.Strsize)
888                         if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
889                                 return nil, err
890                         }
891                         var symsz int
892                         if f.Magic == Magic64 {
893                                 symsz = 16
894                         } else {
895                                 symsz = 12
896                         }
897                         symdat := make([]byte, int(hdr.Nsyms)*symsz)
898                         if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
899                                 return nil, err
900                         }
901                         st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
902                         st.SymtabCmd = hdr
903                         if err != nil {
904                                 return nil, err
905                         }
906                         f.Loads[i] = st
907                         f.Symtab = st
908
909                 case LcDysymtab:
910                         var hdr DysymtabCmd
911                         b := bytes.NewReader(cmddat)
912                         if err := binary.Read(b, bo, &hdr); err != nil {
913                                 return nil, err
914                         }
915                         dat := make([]byte, hdr.Nindirectsyms*4)
916                         if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
917                                 return nil, err
918                         }
919                         x := make([]uint32, hdr.Nindirectsyms)
920                         if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
921                                 return nil, err
922                         }
923                         st := new(Dysymtab)
924                         st.DysymtabCmd = hdr
925                         st.IndirectSyms = x
926                         f.Loads[i] = st
927                         f.Dysymtab = st
928
929                 case LcSegment:
930                         var seg32 Segment32
931                         b := bytes.NewReader(cmddat)
932                         if err := binary.Read(b, bo, &seg32); err != nil {
933                                 return nil, err
934                         }
935                         s = new(Segment)
936                         s.LoadCmd = cmd
937                         s.Len = siz
938                         s.Name = cstring(seg32.Name[0:])
939                         s.Addr = uint64(seg32.Addr)
940                         s.Memsz = uint64(seg32.Memsz)
941                         s.Offset = uint64(seg32.Offset)
942                         s.Filesz = uint64(seg32.Filesz)
943                         s.Maxprot = seg32.Maxprot
944                         s.Prot = seg32.Prot
945                         s.Nsect = seg32.Nsect
946                         s.Flag = seg32.Flag
947                         s.Firstsect = uint32(len(f.Sections))
948                         f.Loads[i] = s
949                         for i := 0; i < int(s.Nsect); i++ {
950                                 var sh32 Section32
951                                 if err := binary.Read(b, bo, &sh32); err != nil {
952                                         return nil, err
953                                 }
954                                 sh := new(Section)
955                                 sh.Name = cstring(sh32.Name[0:])
956                                 sh.Seg = cstring(sh32.Seg[0:])
957                                 sh.Addr = uint64(sh32.Addr)
958                                 sh.Size = uint64(sh32.Size)
959                                 sh.Offset = sh32.Offset
960                                 sh.Align = sh32.Align
961                                 sh.Reloff = sh32.Reloff
962                                 sh.Nreloc = sh32.Nreloc
963                                 sh.Flags = sh32.Flags
964                                 sh.Reserved1 = sh32.Reserve1
965                                 sh.Reserved2 = sh32.Reserve2
966                                 if err := f.pushSection(sh, r); err != nil {
967                                         return nil, err
968                                 }
969                         }
970
971                 case LcSegment64:
972                         var seg64 Segment64
973                         b := bytes.NewReader(cmddat)
974                         if err := binary.Read(b, bo, &seg64); err != nil {
975                                 return nil, err
976                         }
977                         s = new(Segment)
978                         s.LoadCmd = cmd
979                         s.Len = siz
980                         s.Name = cstring(seg64.Name[0:])
981                         s.Addr = seg64.Addr
982                         s.Memsz = seg64.Memsz
983                         s.Offset = seg64.Offset
984                         s.Filesz = seg64.Filesz
985                         s.Maxprot = seg64.Maxprot
986                         s.Prot = seg64.Prot
987                         s.Nsect = seg64.Nsect
988                         s.Flag = seg64.Flag
989                         s.Firstsect = uint32(len(f.Sections))
990                         f.Loads[i] = s
991                         for i := 0; i < int(s.Nsect); i++ {
992                                 var sh64 Section64
993                                 if err := binary.Read(b, bo, &sh64); err != nil {
994                                         return nil, err
995                                 }
996                                 sh := new(Section)
997                                 sh.Name = cstring(sh64.Name[0:])
998                                 sh.Seg = cstring(sh64.Seg[0:])
999                                 sh.Addr = sh64.Addr
1000                                 sh.Size = sh64.Size
1001                                 sh.Offset = sh64.Offset
1002                                 sh.Align = sh64.Align
1003                                 sh.Reloff = sh64.Reloff
1004                                 sh.Nreloc = sh64.Nreloc
1005                                 sh.Flags = sh64.Flags
1006                                 sh.Reserved1 = sh64.Reserve1
1007                                 sh.Reserved2 = sh64.Reserve2
1008                                 sh.Reserved3 = sh64.Reserve3
1009                                 if err := f.pushSection(sh, r); err != nil {
1010                                         return nil, err
1011                                 }
1012                         }
1013
1014                 case LcCodeSignature, LcSegmentSplitInfo, LcFunctionStarts,
1015                         LcDataInCode, LcDylibCodeSignDrs:
1016                         var hdr LinkEditDataCmd
1017                         b := bytes.NewReader(cmddat)
1018
1019                         if err := binary.Read(b, bo, &hdr); err != nil {
1020                                 return nil, err
1021                         }
1022                         l := new(LinkEditData)
1023
1024                         l.LinkEditDataCmd = hdr
1025                         f.Loads[i] = l
1026
1027                 case LcEncryptionInfo, LcEncryptionInfo64:
1028                         var hdr EncryptionInfoCmd
1029                         b := bytes.NewReader(cmddat)
1030
1031                         if err := binary.Read(b, bo, &hdr); err != nil {
1032                                 return nil, err
1033                         }
1034                         l := new(EncryptionInfo)
1035
1036                         l.EncryptionInfoCmd = hdr
1037                         f.Loads[i] = l
1038
1039                 case LcDyldInfo, LcDyldInfoOnly:
1040                         var hdr DyldInfoCmd
1041                         b := bytes.NewReader(cmddat)
1042
1043                         if err := binary.Read(b, bo, &hdr); err != nil {
1044                                 return nil, err
1045                         }
1046                         l := new(DyldInfo)
1047
1048                         l.DyldInfoCmd = hdr
1049                         f.Loads[i] = l
1050                 }
1051                 if s != nil {
1052                         s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
1053                         s.ReaderAt = s.sr
1054                 }
1055                 if f.Loads[i].LoadSize(&f.FileTOC) != siz {
1056                         fmt.Printf("Oops, actual size was %d, calculated was %d, load was %s\n", siz, f.Loads[i].LoadSize(&f.FileTOC), f.Loads[i].String())
1057                         panic("oops")
1058                 }
1059         }
1060         return f, nil
1061 }
1062
1063 func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
1064         bo := f.ByteOrder
1065         symtab := make([]Symbol, hdr.Nsyms)
1066         b := bytes.NewReader(symdat)
1067         for i := range symtab {
1068                 var n Nlist64
1069                 if f.Magic == Magic64 {
1070                         if err := binary.Read(b, bo, &n); err != nil {
1071                                 return nil, err
1072                         }
1073                 } else {
1074                         var n32 Nlist32
1075                         if err := binary.Read(b, bo, &n32); err != nil {
1076                                 return nil, err
1077                         }
1078                         n.Name = n32.Name
1079                         n.Type = n32.Type
1080                         n.Sect = n32.Sect
1081                         n.Desc = n32.Desc
1082                         n.Value = uint64(n32.Value)
1083                 }
1084                 sym := &symtab[i]
1085                 if n.Name >= uint32(len(strtab)) {
1086                         return nil, formatError(offset, "invalid name in symbol table, n.Name=%d, len(strtab)=%d", n.Name, len(strtab))
1087                 }
1088                 sym.Name = cstring(strtab[n.Name:])
1089                 sym.Type = n.Type
1090                 sym.Sect = n.Sect
1091                 sym.Desc = n.Desc
1092                 sym.Value = n.Value
1093         }
1094         st := new(Symtab)
1095         st.Syms = symtab
1096         return st, nil
1097 }
1098
1099 type relocInfo struct {
1100         Addr   uint32
1101         Symnum uint32
1102 }
1103
1104 func (f *File) pushSection(sh *Section, r io.ReaderAt) error {
1105         f.Sections = append(f.Sections, sh)
1106         sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
1107         sh.ReaderAt = sh.sr
1108
1109         if sh.Nreloc > 0 {
1110                 reldat := make([]byte, int(sh.Nreloc)*8)
1111                 if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil {
1112                         return err
1113                 }
1114                 b := bytes.NewReader(reldat)
1115
1116                 bo := f.ByteOrder
1117
1118                 sh.Relocs = make([]Reloc, sh.Nreloc)
1119                 for i := range sh.Relocs {
1120                         rel := &sh.Relocs[i]
1121
1122                         var ri relocInfo
1123                         if err := binary.Read(b, bo, &ri); err != nil {
1124                                 return err
1125                         }
1126
1127                         if ri.Addr&(1<<31) != 0 { // scattered
1128                                 rel.Addr = ri.Addr & (1<<24 - 1)
1129                                 rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1))
1130                                 rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1))
1131                                 rel.Pcrel = ri.Addr&(1<<30) != 0
1132                                 rel.Value = ri.Symnum
1133                                 rel.Scattered = true
1134                         } else {
1135                                 switch bo {
1136                                 case binary.LittleEndian:
1137                                         rel.Addr = ri.Addr
1138                                         rel.Value = ri.Symnum & (1<<24 - 1)
1139                                         rel.Pcrel = ri.Symnum&(1<<24) != 0
1140                                         rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1))
1141                                         rel.Extern = ri.Symnum&(1<<27) != 0
1142                                         rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1))
1143                                 case binary.BigEndian:
1144                                         rel.Addr = ri.Addr
1145                                         rel.Value = ri.Symnum >> 8
1146                                         rel.Pcrel = ri.Symnum&(1<<7) != 0
1147                                         rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1))
1148                                         rel.Extern = ri.Symnum&(1<<4) != 0
1149                                         rel.Type = uint8(ri.Symnum & (1<<4 - 1))
1150                                 default:
1151                                         panic("unreachable")
1152                                 }
1153                         }
1154                 }
1155         }
1156
1157         return nil
1158 }
1159
1160 func cstring(b []byte) string {
1161         i := bytes.IndexByte(b, 0)
1162         if i == -1 {
1163                 i = len(b)
1164         }
1165         return string(b[0:i])
1166 }
1167
1168 // Segment returns the first Segment with the given name, or nil if no such segment exists.
1169 func (f *File) Segment(name string) *Segment {
1170         for _, l := range f.Loads {
1171                 if s, ok := l.(*Segment); ok && s.Name == name {
1172                         return s
1173                 }
1174         }
1175         return nil
1176 }
1177
1178 // Section returns the first section with the given name, or nil if no such
1179 // section exists.
1180 func (f *File) Section(name string) *Section {
1181         for _, s := range f.Sections {
1182                 if s.Name == name {
1183                         return s
1184                 }
1185         }
1186         return nil
1187 }
1188
1189 // DWARF returns the DWARF debug information for the Mach-O file.
1190 func (f *File) DWARF() (*dwarf.Data, error) {
1191         dwarfSuffix := func(s *Section) string {
1192                 switch {
1193                 case strings.HasPrefix(s.Name, "__debug_"):
1194                         return s.Name[8:]
1195                 case strings.HasPrefix(s.Name, "__zdebug_"):
1196                         return s.Name[9:]
1197                 default:
1198                         return ""
1199                 }
1200
1201         }
1202         sectionData := func(s *Section) ([]byte, error) {
1203                 b, err := s.Data()
1204                 if err != nil && uint64(len(b)) < s.Size {
1205                         return nil, err
1206                 }
1207
1208                 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1209                         dlen := binary.BigEndian.Uint64(b[4:12])
1210                         dbuf := make([]byte, dlen)
1211                         r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1212                         if err != nil {
1213                                 return nil, err
1214                         }
1215                         if _, err := io.ReadFull(r, dbuf); err != nil {
1216                                 return nil, err
1217                         }
1218                         if err := r.Close(); err != nil {
1219                                 return nil, err
1220                         }
1221                         b = dbuf
1222                 }
1223                 return b, nil
1224         }
1225
1226         // There are many other DWARF sections, but these
1227         // are the ones the debug/dwarf package uses.
1228         // Don't bother loading others.
1229         var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1230         for _, s := range f.Sections {
1231                 suffix := dwarfSuffix(s)
1232                 if suffix == "" {
1233                         continue
1234                 }
1235                 if _, ok := dat[suffix]; !ok {
1236                         continue
1237                 }
1238                 b, err := sectionData(s)
1239                 if err != nil {
1240                         return nil, err
1241                 }
1242                 dat[suffix] = b
1243         }
1244
1245         d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1246         if err != nil {
1247                 return nil, err
1248         }
1249
1250         // Look for DWARF4 .debug_types sections.
1251         for i, s := range f.Sections {
1252                 suffix := dwarfSuffix(s)
1253                 if suffix != "types" {
1254                         continue
1255                 }
1256
1257                 b, err := sectionData(s)
1258                 if err != nil {
1259                         return nil, err
1260                 }
1261
1262                 err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
1263                 if err != nil {
1264                         return nil, err
1265                 }
1266         }
1267
1268         return d, nil
1269 }
1270
1271 // ImportedSymbols returns the names of all symbols
1272 // referred to by the binary f that are expected to be
1273 // satisfied by other libraries at dynamic load time.
1274 func (f *File) ImportedSymbols() ([]string, error) {
1275         if f.Dysymtab == nil || f.Symtab == nil {
1276                 return nil, formatError(0, "missing symbol table, f.Dsymtab=%v, f.Symtab=%v", f.Dysymtab, f.Symtab)
1277         }
1278
1279         st := f.Symtab
1280         dt := f.Dysymtab
1281         var all []string
1282         for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
1283                 all = append(all, s.Name)
1284         }
1285         return all, nil
1286 }
1287
1288 // ImportedLibraries returns the paths of all libraries
1289 // referred to by the binary f that are expected to be
1290 // linked with the binary at dynamic link time.
1291 func (f *File) ImportedLibraries() ([]string, error) {
1292         var all []string
1293         for _, l := range f.Loads {
1294                 if lib, ok := l.(*Dylib); ok {
1295                         all = append(all, lib.Name)
1296                 }
1297         }
1298         return all, nil
1299 }
1300
1301 func RoundUp(x, align uint64) uint64 {
1302         return uint64((x + align - 1) & -align)
1303 }