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.
6package macho
7
8// High level access to low level data structures.
9
10import (
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.
23type File struct {
24	FileTOC
25
26	Symtab   *Symtab
27	Dysymtab *Dysymtab
28
29	closer io.Closer
30}
31
32type FileTOC struct {
33	FileHeader
34	ByteOrder binary.ByteOrder
35	Loads     []Load
36	Sections  []*Section
37}
38
39func (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.
48func (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
55func (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.
71type 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.
108type LoadBytes []byte
109
110// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
111type 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.
127type 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
140func (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
155func (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.
174type LoadCmdBytes struct {
175	LoadCmd
176	LoadBytes
177}
178
179type 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.
195type 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
208type 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
222func (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
238func (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
255func (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
288func 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.
298type 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.
312type FormatError struct {
313	off int64
314	msg string
315}
316
317func formatError(off int64, format string, data ...interface{}) *FormatError {
318	return &FormatError{off, fmt.Sprintf(format, data...)}
319}
320
321func (e *FormatError) Error() string {
322	return e.msg + fmt.Sprintf(" in record at byte %#x", e.off)
323}
324
325func (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.
331func (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.
342func (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.
348func (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)
356func (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).
365func (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)
380func (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.
392func (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.
408func (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.
438func (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
447func (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
465func (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
473func (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
504func (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
520func (b LoadBytes) Raw() []byte                { return b }
521func (b LoadBytes) Copy() LoadBytes            { return LoadBytes(append([]byte{}, b...)) }
522func (b LoadBytes) LoadSize(t *FileTOC) uint32 { return uint32(len(b)) }
523
524func (lc LoadCmd) Put(b []byte, o binary.ByteOrder) int {
525	panic(fmt.Sprintf("Put not implemented for %s", lc.String()))
526}
527
528func (s LoadCmdBytes) String() string {
529	return s.LoadCmd.String() + ": " + s.LoadBytes.String()
530}
531func (s LoadCmdBytes) Copy() LoadCmdBytes {
532	return LoadCmdBytes{LoadCmd: s.LoadCmd, LoadBytes: s.LoadBytes.Copy()}
533}
534
535func (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
541func (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.
548func (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
557func (s *Segment) Copy() *Segment {
558	r := &Segment{SegmentHeader: s.SegmentHeader}
559	return r
560}
561func (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
575func (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.
583func (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.
586func (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
595func (s *Section) Copy() *Section {
596	return &Section{SectionHeader: s.SectionHeader}
597}
598
599// Open returns a new ReadSeeker reading the Mach-O section.
600func (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.
603type Dylib struct {
604	DylibCmd
605	Name           string
606	Time           uint32
607	CurrentVersion uint32
608	CompatVersion  uint32
609}
610
611func (s *Dylib) String() string { return "Dylib " + s.Name }
612func (s *Dylib) Copy() *Dylib {
613	r := *s
614	return &r
615}
616func (s *Dylib) LoadSize(t *FileTOC) uint32 {
617	return uint32(RoundUp(uint64(unsafe.Sizeof(DylibCmd{}))+uint64(len(s.Name)), t.LoadAlign()))
618}
619
620type Dylinker struct {
621	DylinkerCmd // shared by 3 commands, need the LoadCmd
622	Name        string
623}
624
625func (s *Dylinker) String() string { return s.DylinkerCmd.LoadCmd.String() + " " + s.Name }
626func (s *Dylinker) Copy() *Dylinker {
627	return &Dylinker{DylinkerCmd: s.DylinkerCmd, Name: s.Name}
628}
629func (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.
634type Symtab struct {
635	SymtabCmd
636	Syms []Symbol
637}
638
639func (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
649func (s *Symtab) String() string { return fmt.Sprintf("Symtab %#v", s.SymtabCmd) }
650func (s *Symtab) Copy() *Symtab {
651	return &Symtab{SymtabCmd: s.SymtabCmd, Syms: append([]Symbol{}, s.Syms...)}
652}
653func (s *Symtab) LoadSize(t *FileTOC) uint32 {
654	return uint32(unsafe.Sizeof(SymtabCmd{}))
655}
656
657type LinkEditData struct {
658	LinkEditDataCmd
659}
660
661func (s *LinkEditData) String() string { return "LinkEditData " + s.LoadCmd.String() }
662func (s *LinkEditData) Copy() *LinkEditData {
663	return &LinkEditData{LinkEditDataCmd: s.LinkEditDataCmd}
664}
665func (s *LinkEditData) LoadSize(t *FileTOC) uint32 {
666	return uint32(unsafe.Sizeof(LinkEditDataCmd{}))
667}
668
669type Uuid struct {
670	UuidCmd
671}
672
673func (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
677func (s *Uuid) Copy() *Uuid {
678	return &Uuid{UuidCmd: s.UuidCmd}
679}
680func (s *Uuid) LoadSize(t *FileTOC) uint32 {
681	return uint32(unsafe.Sizeof(UuidCmd{}))
682}
683func (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
690type DyldInfo struct {
691	DyldInfoCmd
692}
693
694func (s *DyldInfo) String() string { return "DyldInfo " + s.LoadCmd.String() }
695func (s *DyldInfo) Copy() *DyldInfo {
696	return &DyldInfo{DyldInfoCmd: s.DyldInfoCmd}
697}
698func (s *DyldInfo) LoadSize(t *FileTOC) uint32 {
699	return uint32(unsafe.Sizeof(DyldInfoCmd{}))
700}
701
702type EncryptionInfo struct {
703	EncryptionInfoCmd
704}
705
706func (s *EncryptionInfo) String() string { return "EncryptionInfo " + s.LoadCmd.String() }
707func (s *EncryptionInfo) Copy() *EncryptionInfo {
708	return &EncryptionInfo{EncryptionInfoCmd: s.EncryptionInfoCmd}
709}
710func (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.
715type Dysymtab struct {
716	DysymtabCmd
717	IndirectSyms []uint32 // indices into Symtab.Syms
718}
719
720func (s *Dysymtab) String() string { return fmt.Sprintf("Dysymtab %#v", s.DysymtabCmd) }
721func (s *Dysymtab) Copy() *Dysymtab {
722	return &Dysymtab{DysymtabCmd: s.DysymtabCmd, IndirectSyms: append([]uint32{}, s.IndirectSyms...)}
723}
724func (s *Dysymtab) LoadSize(t *FileTOC) uint32 {
725	return uint32(unsafe.Sizeof(DysymtabCmd{}))
726}
727
728// A Rpath represents a Mach-O rpath command.
729type Rpath struct {
730	LoadCmd
731	Path string
732}
733
734func (s *Rpath) String() string   { return "Rpath " + s.Path }
735func (s *Rpath) Command() LoadCmd { return LcRpath }
736func (s *Rpath) Copy() *Rpath {
737	return &Rpath{Path: s.Path}
738}
739func (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.
744func 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.
761func (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.
772func 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
1063func (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
1099type relocInfo struct {
1100	Addr   uint32
1101	Symnum uint32
1102}
1103
1104func (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
1160func 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.
1169func (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.
1180func (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.
1190func (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.
1274func (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.
1291func (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
1301func RoundUp(x, align uint64) uint64 {
1302	return uint64((x + align - 1) & -align)
1303}
1304