| // Copyright 2009 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // Package macho implements access to Mach-O object files. | 
 | package macho | 
 |  | 
 | // High level access to low level data structures. | 
 |  | 
 | import ( | 
 | 	"bytes" | 
 | 	"compress/zlib" | 
 | 	"debug/dwarf" | 
 | 	"encoding/binary" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"os" | 
 | 	"strings" | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | // A File represents an open Mach-O file. | 
 | type File struct { | 
 | 	FileTOC | 
 |  | 
 | 	Symtab   *Symtab | 
 | 	Dysymtab *Dysymtab | 
 |  | 
 | 	closer io.Closer | 
 | } | 
 |  | 
 | type FileTOC struct { | 
 | 	FileHeader | 
 | 	ByteOrder binary.ByteOrder | 
 | 	Loads     []Load | 
 | 	Sections  []*Section | 
 | } | 
 |  | 
 | func (t *FileTOC) AddLoad(l Load) { | 
 | 	t.Loads = append(t.Loads, l) | 
 | 	t.NCommands++ | 
 | 	t.SizeCommands += l.LoadSize(t) | 
 | } | 
 |  | 
 | // AddSegment adds segment s to the file table of contents, | 
 | // and also zeroes out the segment information with the expectation | 
 | // that this will be added next. | 
 | func (t *FileTOC) AddSegment(s *Segment) { | 
 | 	t.AddLoad(s) | 
 | 	s.Nsect = 0 | 
 | 	s.Firstsect = 0 | 
 | } | 
 |  | 
 | // Adds section to the most recently added Segment | 
 | func (t *FileTOC) AddSection(s *Section) { | 
 | 	g := t.Loads[len(t.Loads)-1].(*Segment) | 
 | 	if g.Nsect == 0 { | 
 | 		g.Firstsect = uint32(len(t.Sections)) | 
 | 	} | 
 | 	g.Nsect++ | 
 | 	t.Sections = append(t.Sections, s) | 
 | 	sectionsize := uint32(unsafe.Sizeof(Section32{})) | 
 | 	if g.Command() == LcSegment64 { | 
 | 		sectionsize = uint32(unsafe.Sizeof(Section64{})) | 
 | 	} | 
 | 	t.SizeCommands += sectionsize | 
 | 	g.Len += sectionsize | 
 | } | 
 |  | 
 | // A Load represents any Mach-O load command. | 
 | type Load interface { | 
 | 	String() string | 
 | 	Command() LoadCmd | 
 | 	LoadSize(*FileTOC) uint32 // Need the TOC for alignment, sigh. | 
 | 	Put([]byte, binary.ByteOrder) int | 
 |  | 
 | 	// command LC_DYLD_INFO_ONLY contains offsets into __LINKEDIT | 
 | 	// e.g., from "otool -l a.out" | 
 | 	// | 
 | 	// 	Load command 3 | 
 | 	//       cmd LC_SEGMENT_64 | 
 | 	//   cmdsize 72 | 
 | 	//   segname __LINKEDIT | 
 | 	//    vmaddr 0x0000000100002000 | 
 | 	//    vmsize 0x0000000000001000 | 
 | 	//   fileoff 8192 | 
 | 	//  filesize 520 | 
 | 	//   maxprot 0x00000007 | 
 | 	//  initprot 0x00000001 | 
 | 	//    nsects 0 | 
 | 	//     flags 0x0 | 
 | 	// Load command 4 | 
 | 	//             cmd LC_DYLD_INFO_ONLY | 
 | 	//         cmdsize 48 | 
 | 	//      rebase_off 8192 | 
 | 	//     rebase_size 8 | 
 | 	//        bind_off 8200 | 
 | 	//       bind_size 24 | 
 | 	//   weak_bind_off 0 | 
 | 	//  weak_bind_size 0 | 
 | 	//   lazy_bind_off 8224 | 
 | 	//  lazy_bind_size 16 | 
 | 	//      export_off 8240 | 
 | 	//     export_size 48 | 
 | } | 
 |  | 
 | // LoadBytes is the uninterpreted bytes of a Mach-O load command. | 
 | type LoadBytes []byte | 
 |  | 
 | // A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command. | 
 | type SegmentHeader struct { | 
 | 	LoadCmd | 
 | 	Len       uint32 | 
 | 	Name      string // 16 characters or fewer | 
 | 	Addr      uint64 // memory address | 
 | 	Memsz     uint64 // memory size | 
 | 	Offset    uint64 // file offset | 
 | 	Filesz    uint64 // number of bytes starting at that file offset | 
 | 	Maxprot   uint32 | 
 | 	Prot      uint32 | 
 | 	Nsect     uint32 | 
 | 	Flag      SegFlags | 
 | 	Firstsect uint32 | 
 | } | 
 |  | 
 | // A Segment represents a Mach-O 32-bit or 64-bit load segment command. | 
 | type Segment struct { | 
 | 	SegmentHeader | 
 |  | 
 | 	// Embed ReaderAt for ReadAt method. | 
 | 	// Do not embed SectionReader directly | 
 | 	// to avoid having Read and Seek. | 
 | 	// If a client wants Read and Seek it must use | 
 | 	// Open() to avoid fighting over the seek offset | 
 | 	// with other clients. | 
 | 	io.ReaderAt | 
 | 	sr *io.SectionReader | 
 | } | 
 |  | 
 | func (s *Segment) Put32(b []byte, o binary.ByteOrder) int { | 
 | 	o.PutUint32(b[0*4:], uint32(s.LoadCmd)) | 
 | 	o.PutUint32(b[1*4:], s.Len) | 
 | 	putAtMost16Bytes(b[2*4:], s.Name) | 
 | 	o.PutUint32(b[6*4:], uint32(s.Addr)) | 
 | 	o.PutUint32(b[7*4:], uint32(s.Memsz)) | 
 | 	o.PutUint32(b[8*4:], uint32(s.Offset)) | 
 | 	o.PutUint32(b[9*4:], uint32(s.Filesz)) | 
 | 	o.PutUint32(b[10*4:], s.Maxprot) | 
 | 	o.PutUint32(b[11*4:], s.Prot) | 
 | 	o.PutUint32(b[12*4:], s.Nsect) | 
 | 	o.PutUint32(b[13*4:], uint32(s.Flag)) | 
 | 	return 14 * 4 | 
 | } | 
 |  | 
 | func (s *Segment) Put64(b []byte, o binary.ByteOrder) int { | 
 | 	o.PutUint32(b[0*4:], uint32(s.LoadCmd)) | 
 | 	o.PutUint32(b[1*4:], s.Len) | 
 | 	putAtMost16Bytes(b[2*4:], s.Name) | 
 | 	o.PutUint64(b[6*4+0*8:], s.Addr) | 
 | 	o.PutUint64(b[6*4+1*8:], s.Memsz) | 
 | 	o.PutUint64(b[6*4+2*8:], s.Offset) | 
 | 	o.PutUint64(b[6*4+3*8:], s.Filesz) | 
 | 	o.PutUint32(b[6*4+4*8:], s.Maxprot) | 
 | 	o.PutUint32(b[7*4+4*8:], s.Prot) | 
 | 	o.PutUint32(b[8*4+4*8:], s.Nsect) | 
 | 	o.PutUint32(b[9*4+4*8:], uint32(s.Flag)) | 
 | 	return 10*4 + 4*8 | 
 | } | 
 |  | 
 | // LoadCmdBytes is a command-tagged sequence of bytes. | 
 | // This is used for Load Commands that are not (yet) | 
 | // interesting to us, and to common up this behavior for | 
 | // all those that are. | 
 | type LoadCmdBytes struct { | 
 | 	LoadCmd | 
 | 	LoadBytes | 
 | } | 
 |  | 
 | type SectionHeader struct { | 
 | 	Name      string | 
 | 	Seg       string | 
 | 	Addr      uint64 | 
 | 	Size      uint64 | 
 | 	Offset    uint32 | 
 | 	Align     uint32 | 
 | 	Reloff    uint32 | 
 | 	Nreloc    uint32 | 
 | 	Flags     SecFlags | 
 | 	Reserved1 uint32 | 
 | 	Reserved2 uint32 | 
 | 	Reserved3 uint32 // only present if original was 64-bit | 
 | } | 
 |  | 
 | // A Reloc represents a Mach-O relocation. | 
 | type Reloc struct { | 
 | 	Addr  uint32 | 
 | 	Value uint32 | 
 | 	// when Scattered == false && Extern == true, Value is the symbol number. | 
 | 	// when Scattered == false && Extern == false, Value is the section number. | 
 | 	// when Scattered == true, Value is the value that this reloc refers to. | 
 | 	Type      uint8 | 
 | 	Len       uint8 // 0=byte, 1=word, 2=long, 3=quad | 
 | 	Pcrel     bool | 
 | 	Extern    bool // valid if Scattered == false | 
 | 	Scattered bool | 
 | } | 
 |  | 
 | type Section struct { | 
 | 	SectionHeader | 
 | 	Relocs []Reloc | 
 |  | 
 | 	// Embed ReaderAt for ReadAt method. | 
 | 	// Do not embed SectionReader directly | 
 | 	// to avoid having Read and Seek. | 
 | 	// If a client wants Read and Seek it must use | 
 | 	// Open() to avoid fighting over the seek offset | 
 | 	// with other clients. | 
 | 	io.ReaderAt | 
 | 	sr *io.SectionReader | 
 | } | 
 |  | 
 | func (s *Section) Put32(b []byte, o binary.ByteOrder) int { | 
 | 	putAtMost16Bytes(b[0:], s.Name) | 
 | 	putAtMost16Bytes(b[16:], s.Seg) | 
 | 	o.PutUint32(b[8*4:], uint32(s.Addr)) | 
 | 	o.PutUint32(b[9*4:], uint32(s.Size)) | 
 | 	o.PutUint32(b[10*4:], s.Offset) | 
 | 	o.PutUint32(b[11*4:], s.Align) | 
 | 	o.PutUint32(b[12*4:], s.Reloff) | 
 | 	o.PutUint32(b[13*4:], s.Nreloc) | 
 | 	o.PutUint32(b[14*4:], uint32(s.Flags)) | 
 | 	o.PutUint32(b[15*4:], s.Reserved1) | 
 | 	o.PutUint32(b[16*4:], s.Reserved2) | 
 | 	a := 17 * 4 | 
 | 	return a + s.PutRelocs(b[a:], o) | 
 | } | 
 |  | 
 | func (s *Section) Put64(b []byte, o binary.ByteOrder) int { | 
 | 	putAtMost16Bytes(b[0:], s.Name) | 
 | 	putAtMost16Bytes(b[16:], s.Seg) | 
 | 	o.PutUint64(b[8*4+0*8:], s.Addr) | 
 | 	o.PutUint64(b[8*4+1*8:], s.Size) | 
 | 	o.PutUint32(b[8*4+2*8:], s.Offset) | 
 | 	o.PutUint32(b[9*4+2*8:], s.Align) | 
 | 	o.PutUint32(b[10*4+2*8:], s.Reloff) | 
 | 	o.PutUint32(b[11*4+2*8:], s.Nreloc) | 
 | 	o.PutUint32(b[12*4+2*8:], uint32(s.Flags)) | 
 | 	o.PutUint32(b[13*4+2*8:], s.Reserved1) | 
 | 	o.PutUint32(b[14*4+2*8:], s.Reserved2) | 
 | 	o.PutUint32(b[15*4+2*8:], s.Reserved3) | 
 | 	a := 16*4 + 2*8 | 
 | 	return a + s.PutRelocs(b[a:], o) | 
 | } | 
 |  | 
 | func (s *Section) PutRelocs(b []byte, o binary.ByteOrder) int { | 
 | 	a := 0 | 
 | 	for _, r := range s.Relocs { | 
 | 		var ri relocInfo | 
 | 		typ := uint32(r.Type) & (1<<4 - 1) | 
 | 		len := uint32(r.Len) & (1<<2 - 1) | 
 | 		pcrel := uint32(0) | 
 | 		if r.Pcrel { | 
 | 			pcrel = 1 | 
 | 		} | 
 | 		ext := uint32(0) | 
 | 		if r.Extern { | 
 | 			ext = 1 | 
 | 		} | 
 | 		switch { | 
 | 		case r.Scattered: | 
 | 			ri.Addr = r.Addr&(1<<24-1) | typ<<24 | len<<28 | 1<<31 | pcrel<<30 | 
 | 			ri.Symnum = r.Value | 
 | 		case o == binary.LittleEndian: | 
 | 			ri.Addr = r.Addr | 
 | 			ri.Symnum = r.Value&(1<<24-1) | pcrel<<24 | len<<25 | ext<<27 | typ<<28 | 
 | 		case o == binary.BigEndian: | 
 | 			ri.Addr = r.Addr | 
 | 			ri.Symnum = r.Value<<8 | pcrel<<7 | len<<5 | ext<<4 | typ | 
 | 		} | 
 | 		o.PutUint32(b, ri.Addr) | 
 | 		o.PutUint32(b[4:], ri.Symnum) | 
 | 		a += 8 | 
 | 		b = b[8:] | 
 | 	} | 
 | 	return a | 
 | } | 
 |  | 
 | func putAtMost16Bytes(b []byte, n string) { | 
 | 	for i := range n { // at most 16 bytes | 
 | 		if i == 16 { | 
 | 			break | 
 | 		} | 
 | 		b[i] = n[i] | 
 | 	} | 
 | } | 
 |  | 
 | // A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. | 
 | type Symbol struct { | 
 | 	Name  string | 
 | 	Type  uint8 | 
 | 	Sect  uint8 | 
 | 	Desc  uint16 | 
 | 	Value uint64 | 
 | } | 
 |  | 
 | /* | 
 |  * Mach-O reader | 
 |  */ | 
 |  | 
 | // FormatError is returned by some operations if the data does | 
 | // not have the correct format for an object file. | 
 | type FormatError struct { | 
 | 	off int64 | 
 | 	msg string | 
 | } | 
 |  | 
 | func formatError(off int64, format string, data ...interface{}) *FormatError { | 
 | 	return &FormatError{off, fmt.Sprintf(format, data...)} | 
 | } | 
 |  | 
 | func (e *FormatError) Error() string { | 
 | 	return e.msg + fmt.Sprintf(" in record at byte %#x", e.off) | 
 | } | 
 |  | 
 | func (e *FormatError) String() string { | 
 | 	return e.Error() | 
 | } | 
 |  | 
 | // DerivedCopy returns a modified copy of the TOC, with empty loads and sections, | 
 | // and with the specified header type and flags. | 
 | func (t *FileTOC) DerivedCopy(Type HdrType, Flags HdrFlags) *FileTOC { | 
 | 	h := t.FileHeader | 
 | 	h.NCommands, h.SizeCommands, h.Type, h.Flags = 0, 0, Type, Flags | 
 |  | 
 | 	return &FileTOC{FileHeader: h, ByteOrder: t.ByteOrder} | 
 | } | 
 |  | 
 | // TOCSize returns the size in bytes of the object file representation | 
 | // of the header and Load Commands (including Segments and Sections, but | 
 | // not their contents) at the beginning of a Mach-O file.  This typically | 
 | // overlaps the text segment in the object file. | 
 | func (t *FileTOC) TOCSize() uint32 { | 
 | 	return t.HdrSize() + t.LoadSize() | 
 | } | 
 |  | 
 | // LoadAlign returns the required alignment of Load commands in a binary. | 
 | // This is used to add padding for necessary alignment. | 
 | func (t *FileTOC) LoadAlign() uint64 { | 
 | 	if t.Magic == Magic64 { | 
 | 		return 8 | 
 | 	} | 
 | 	return 4 | 
 | } | 
 |  | 
 | // SymbolSize returns the size in bytes of a Symbol (Nlist32 or Nlist64) | 
 | func (t *FileTOC) SymbolSize() uint32 { | 
 | 	if t.Magic == Magic64 { | 
 | 		return uint32(unsafe.Sizeof(Nlist64{})) | 
 | 	} | 
 | 	return uint32(unsafe.Sizeof(Nlist32{})) | 
 | } | 
 |  | 
 | // HdrSize returns the size in bytes of the Macho header for a given | 
 | // magic number (where the magic number has been appropriately byte-swapped). | 
 | func (t *FileTOC) HdrSize() uint32 { | 
 | 	switch t.Magic { | 
 | 	case Magic32: | 
 | 		return fileHeaderSize32 | 
 | 	case Magic64: | 
 | 		return fileHeaderSize64 | 
 | 	case MagicFat: | 
 | 		panic("MagicFat not handled yet") | 
 | 	default: | 
 | 		panic(fmt.Sprintf("Unexpected magic number 0x%x, expected Mach-O object file", t.Magic)) | 
 | 	} | 
 | } | 
 |  | 
 | // LoadSize returns the size of all the load commands in a file's table-of contents | 
 | // (but not their associated data, e.g., sections and symbol tables) | 
 | func (t *FileTOC) LoadSize() uint32 { | 
 | 	cmdsz := uint32(0) | 
 | 	for _, l := range t.Loads { | 
 | 		s := l.LoadSize(t) | 
 | 		cmdsz += s | 
 | 	} | 
 | 	return cmdsz | 
 | } | 
 |  | 
 | // FileSize returns the size in bytes of the header, load commands, and the | 
 | // in-file contents of all the segments and sections included in those | 
 | // load commands, accounting for their offsets within the file. | 
 | func (t *FileTOC) FileSize() uint64 { | 
 | 	sz := uint64(t.LoadSize()) // ought to be contained in text segment, but just in case. | 
 | 	for _, l := range t.Loads { | 
 | 		if s, ok := l.(*Segment); ok { | 
 | 			if m := s.Offset + s.Filesz; m > sz { | 
 | 				sz = m | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return sz | 
 | } | 
 |  | 
 | // Put writes the header and all load commands to buffer, using | 
 | // the byte ordering specified in FileTOC t.  For sections, this | 
 | // writes the headers that come in-line with the segment Load commands, | 
 | // but does not write the reference data for those sections. | 
 | func (t *FileTOC) Put(buffer []byte) int { | 
 | 	next := t.FileHeader.Put(buffer, t.ByteOrder) | 
 | 	for _, l := range t.Loads { | 
 | 		if s, ok := l.(*Segment); ok { | 
 | 			switch t.Magic { | 
 | 			case Magic64: | 
 | 				next += s.Put64(buffer[next:], t.ByteOrder) | 
 | 				for i := uint32(0); i < s.Nsect; i++ { | 
 | 					c := t.Sections[i+s.Firstsect] | 
 | 					next += c.Put64(buffer[next:], t.ByteOrder) | 
 | 				} | 
 | 			case Magic32: | 
 | 				next += s.Put32(buffer[next:], t.ByteOrder) | 
 | 				for i := uint32(0); i < s.Nsect; i++ { | 
 | 					c := t.Sections[i+s.Firstsect] | 
 | 					next += c.Put32(buffer[next:], t.ByteOrder) | 
 | 				} | 
 | 			default: | 
 | 				panic(fmt.Sprintf("Unexpected magic number 0x%x", t.Magic)) | 
 | 			} | 
 |  | 
 | 		} else { | 
 | 			next += l.Put(buffer[next:], t.ByteOrder) | 
 | 		} | 
 | 	} | 
 | 	return next | 
 | } | 
 |  | 
 | // UncompressedSize returns the size of the segment with its sections uncompressed, ignoring | 
 | // its offset within the file.  The returned size is rounded up to the power of two in align. | 
 | func (s *Segment) UncompressedSize(t *FileTOC, align uint64) uint64 { | 
 | 	sz := uint64(0) | 
 | 	for j := uint32(0); j < s.Nsect; j++ { | 
 | 		c := t.Sections[j+s.Firstsect] | 
 | 		sz += c.UncompressedSize() | 
 | 	} | 
 | 	return (sz + align - 1) & uint64(-int64(align)) | 
 | } | 
 |  | 
 | func (s *Section) UncompressedSize() uint64 { | 
 | 	if !strings.HasPrefix(s.Name, "__z") { | 
 | 		return s.Size | 
 | 	} | 
 | 	b := make([]byte, 12) | 
 | 	n, err := s.sr.ReadAt(b, 0) | 
 | 	if err != nil { | 
 | 		panic("Malformed object file") | 
 | 	} | 
 | 	if n != len(b) { | 
 | 		return s.Size | 
 | 	} | 
 | 	if string(b[:4]) == "ZLIB" { | 
 | 		return binary.BigEndian.Uint64(b[4:12]) | 
 | 	} | 
 | 	return s.Size | 
 | } | 
 |  | 
 | func (s *Section) PutData(b []byte) { | 
 | 	bb := b[0:s.Size] | 
 | 	n, err := s.sr.ReadAt(bb, 0) | 
 | 	if err != nil || uint64(n) != s.Size { | 
 | 		panic("Malformed object file (ReadAt error)") | 
 | 	} | 
 | } | 
 |  | 
 | func (s *Section) PutUncompressedData(b []byte) { | 
 | 	if strings.HasPrefix(s.Name, "__z") { | 
 | 		bb := make([]byte, 12) | 
 | 		n, err := s.sr.ReadAt(bb, 0) | 
 | 		if err != nil { | 
 | 			panic("Malformed object file") | 
 | 		} | 
 | 		if n == len(bb) && string(bb[:4]) == "ZLIB" { | 
 | 			size := binary.BigEndian.Uint64(bb[4:12]) | 
 | 			// Decompress starting at b[12:] | 
 | 			r, err := zlib.NewReader(io.NewSectionReader(s, 12, int64(size)-12)) | 
 | 			if err != nil { | 
 | 				panic("Malformed object file (zlib.NewReader error)") | 
 | 			} | 
 | 			n, err := io.ReadFull(r, b[0:size]) | 
 | 			if err != nil { | 
 | 				panic("Malformed object file (ReadFull error)") | 
 | 			} | 
 | 			if uint64(n) != size { | 
 | 				panic(fmt.Sprintf("PutUncompressedData, expected to read %d bytes, instead read %d", size, n)) | 
 | 			} | 
 | 			if err := r.Close(); err != nil { | 
 | 				panic("Malformed object file (Close error)") | 
 | 			} | 
 | 			return | 
 | 		} | 
 | 	} | 
 | 	// Not compressed | 
 | 	s.PutData(b) | 
 | } | 
 |  | 
 | func (b LoadBytes) String() string { | 
 | 	s := "[" | 
 | 	for i, a := range b { | 
 | 		if i > 0 { | 
 | 			s += " " | 
 | 			if len(b) > 48 && i >= 16 { | 
 | 				s += fmt.Sprintf("... (%d bytes)", len(b)) | 
 | 				break | 
 | 			} | 
 | 		} | 
 | 		s += fmt.Sprintf("%x", a) | 
 | 	} | 
 | 	s += "]" | 
 | 	return s | 
 | } | 
 |  | 
 | func (b LoadBytes) Raw() []byte                { return b } | 
 | func (b LoadBytes) Copy() LoadBytes            { return LoadBytes(append([]byte{}, b...)) } | 
 | func (b LoadBytes) LoadSize(t *FileTOC) uint32 { return uint32(len(b)) } | 
 |  | 
 | func (lc LoadCmd) Put(b []byte, o binary.ByteOrder) int { | 
 | 	panic(fmt.Sprintf("Put not implemented for %s", lc.String())) | 
 | } | 
 |  | 
 | func (s LoadCmdBytes) String() string { | 
 | 	return s.LoadCmd.String() + ": " + s.LoadBytes.String() | 
 | } | 
 | func (s LoadCmdBytes) Copy() LoadCmdBytes { | 
 | 	return LoadCmdBytes{LoadCmd: s.LoadCmd, LoadBytes: s.LoadBytes.Copy()} | 
 | } | 
 |  | 
 | func (s *SegmentHeader) String() string { | 
 | 	return fmt.Sprintf( | 
 | 		"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", | 
 | 		s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect) | 
 | } | 
 |  | 
 | func (s *Segment) String() string { | 
 | 	return fmt.Sprintf( | 
 | 		"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", | 
 | 		s.Name, s.Len, s.Addr, s.Memsz, s.Offset, s.Filesz, s.Maxprot, s.Prot, s.Nsect, s.Flag, s.Firstsect) | 
 | } | 
 |  | 
 | // Data reads and returns the contents of the segment. | 
 | func (s *Segment) Data() ([]byte, error) { | 
 | 	dat := make([]byte, s.sr.Size()) | 
 | 	n, err := s.sr.ReadAt(dat, 0) | 
 | 	if n == len(dat) { | 
 | 		err = nil | 
 | 	} | 
 | 	return dat[0:n], err | 
 | } | 
 |  | 
 | func (s *Segment) Copy() *Segment { | 
 | 	r := &Segment{SegmentHeader: s.SegmentHeader} | 
 | 	return r | 
 | } | 
 | func (s *Segment) CopyZeroed() *Segment { | 
 | 	r := s.Copy() | 
 | 	r.Filesz = 0 | 
 | 	r.Offset = 0 | 
 | 	r.Nsect = 0 | 
 | 	r.Firstsect = 0 | 
 | 	if s.Command() == LcSegment64 { | 
 | 		r.Len = uint32(unsafe.Sizeof(Segment64{})) | 
 | 	} else { | 
 | 		r.Len = uint32(unsafe.Sizeof(Segment32{})) | 
 | 	} | 
 | 	return r | 
 | } | 
 |  | 
 | func (s *Segment) LoadSize(t *FileTOC) uint32 { | 
 | 	if s.Command() == LcSegment64 { | 
 | 		return uint32(unsafe.Sizeof(Segment64{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section64{})) | 
 | 	} | 
 | 	return uint32(unsafe.Sizeof(Segment32{})) + uint32(s.Nsect)*uint32(unsafe.Sizeof(Section32{})) | 
 | } | 
 |  | 
 | // Open returns a new ReadSeeker reading the segment. | 
 | func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } | 
 |  | 
 | // Data reads and returns the contents of the Mach-O section. | 
 | func (s *Section) Data() ([]byte, error) { | 
 | 	dat := make([]byte, s.sr.Size()) | 
 | 	n, err := s.sr.ReadAt(dat, 0) | 
 | 	if n == len(dat) { | 
 | 		err = nil | 
 | 	} | 
 | 	return dat[0:n], err | 
 | } | 
 |  | 
 | func (s *Section) Copy() *Section { | 
 | 	return &Section{SectionHeader: s.SectionHeader} | 
 | } | 
 |  | 
 | // Open returns a new ReadSeeker reading the Mach-O section. | 
 | func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } | 
 |  | 
 | // A Dylib represents a Mach-O load dynamic library command. | 
 | type Dylib struct { | 
 | 	DylibCmd | 
 | 	Name           string | 
 | 	Time           uint32 | 
 | 	CurrentVersion uint32 | 
 | 	CompatVersion  uint32 | 
 | } | 
 |  | 
 | func (s *Dylib) String() string { return "Dylib " + s.Name } | 
 | func (s *Dylib) Copy() *Dylib { | 
 | 	r := *s | 
 | 	return &r | 
 | } | 
 | func (s *Dylib) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(RoundUp(uint64(unsafe.Sizeof(DylibCmd{}))+uint64(len(s.Name)), t.LoadAlign())) | 
 | } | 
 |  | 
 | type Dylinker struct { | 
 | 	DylinkerCmd // shared by 3 commands, need the LoadCmd | 
 | 	Name        string | 
 | } | 
 |  | 
 | func (s *Dylinker) String() string { return s.DylinkerCmd.LoadCmd.String() + " " + s.Name } | 
 | func (s *Dylinker) Copy() *Dylinker { | 
 | 	return &Dylinker{DylinkerCmd: s.DylinkerCmd, Name: s.Name} | 
 | } | 
 | func (s *Dylinker) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(RoundUp(uint64(unsafe.Sizeof(DylinkerCmd{}))+uint64(len(s.Name)), t.LoadAlign())) | 
 | } | 
 |  | 
 | // A Symtab represents a Mach-O symbol table command. | 
 | type Symtab struct { | 
 | 	SymtabCmd | 
 | 	Syms []Symbol | 
 | } | 
 |  | 
 | func (s *Symtab) Put(b []byte, o binary.ByteOrder) int { | 
 | 	o.PutUint32(b[0*4:], uint32(s.LoadCmd)) | 
 | 	o.PutUint32(b[1*4:], s.Len) | 
 | 	o.PutUint32(b[2*4:], s.Symoff) | 
 | 	o.PutUint32(b[3*4:], s.Nsyms) | 
 | 	o.PutUint32(b[4*4:], s.Stroff) | 
 | 	o.PutUint32(b[5*4:], s.Strsize) | 
 | 	return 6 * 4 | 
 | } | 
 |  | 
 | func (s *Symtab) String() string { return fmt.Sprintf("Symtab %#v", s.SymtabCmd) } | 
 | func (s *Symtab) Copy() *Symtab { | 
 | 	return &Symtab{SymtabCmd: s.SymtabCmd, Syms: append([]Symbol{}, s.Syms...)} | 
 | } | 
 | func (s *Symtab) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(SymtabCmd{})) | 
 | } | 
 |  | 
 | type LinkEditData struct { | 
 | 	LinkEditDataCmd | 
 | } | 
 |  | 
 | func (s *LinkEditData) String() string { return "LinkEditData " + s.LoadCmd.String() } | 
 | func (s *LinkEditData) Copy() *LinkEditData { | 
 | 	return &LinkEditData{LinkEditDataCmd: s.LinkEditDataCmd} | 
 | } | 
 | func (s *LinkEditData) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(LinkEditDataCmd{})) | 
 | } | 
 |  | 
 | type Uuid struct { | 
 | 	UuidCmd | 
 | } | 
 |  | 
 | func (s *Uuid) String() string { | 
 | 	return fmt.Sprintf("Uuid %X-%X-%X-%X-%X", | 
 | 		s.Id[0:4], s.Id[4:6], s.Id[6:8], s.Id[8:10], s.Id[10:16]) | 
 | } // 8-4-4-4-12 | 
 | func (s *Uuid) Copy() *Uuid { | 
 | 	return &Uuid{UuidCmd: s.UuidCmd} | 
 | } | 
 | func (s *Uuid) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(UuidCmd{})) | 
 | } | 
 | func (s *Uuid) Put(b []byte, o binary.ByteOrder) int { | 
 | 	o.PutUint32(b[0*4:], uint32(s.LoadCmd)) | 
 | 	o.PutUint32(b[1*4:], s.Len) | 
 | 	copy(b[2*4:], s.Id[0:]) | 
 | 	return int(s.Len) | 
 | } | 
 |  | 
 | type DyldInfo struct { | 
 | 	DyldInfoCmd | 
 | } | 
 |  | 
 | func (s *DyldInfo) String() string { return "DyldInfo " + s.LoadCmd.String() } | 
 | func (s *DyldInfo) Copy() *DyldInfo { | 
 | 	return &DyldInfo{DyldInfoCmd: s.DyldInfoCmd} | 
 | } | 
 | func (s *DyldInfo) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(DyldInfoCmd{})) | 
 | } | 
 |  | 
 | type EncryptionInfo struct { | 
 | 	EncryptionInfoCmd | 
 | } | 
 |  | 
 | func (s *EncryptionInfo) String() string { return "EncryptionInfo " + s.LoadCmd.String() } | 
 | func (s *EncryptionInfo) Copy() *EncryptionInfo { | 
 | 	return &EncryptionInfo{EncryptionInfoCmd: s.EncryptionInfoCmd} | 
 | } | 
 | func (s *EncryptionInfo) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(EncryptionInfoCmd{})) | 
 | } | 
 |  | 
 | // A Dysymtab represents a Mach-O dynamic symbol table command. | 
 | type Dysymtab struct { | 
 | 	DysymtabCmd | 
 | 	IndirectSyms []uint32 // indices into Symtab.Syms | 
 | } | 
 |  | 
 | func (s *Dysymtab) String() string { return fmt.Sprintf("Dysymtab %#v", s.DysymtabCmd) } | 
 | func (s *Dysymtab) Copy() *Dysymtab { | 
 | 	return &Dysymtab{DysymtabCmd: s.DysymtabCmd, IndirectSyms: append([]uint32{}, s.IndirectSyms...)} | 
 | } | 
 | func (s *Dysymtab) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(unsafe.Sizeof(DysymtabCmd{})) | 
 | } | 
 |  | 
 | // A Rpath represents a Mach-O rpath command. | 
 | type Rpath struct { | 
 | 	LoadCmd | 
 | 	Path string | 
 | } | 
 |  | 
 | func (s *Rpath) String() string   { return "Rpath " + s.Path } | 
 | func (s *Rpath) Command() LoadCmd { return LcRpath } | 
 | func (s *Rpath) Copy() *Rpath { | 
 | 	return &Rpath{Path: s.Path} | 
 | } | 
 | func (s *Rpath) LoadSize(t *FileTOC) uint32 { | 
 | 	return uint32(RoundUp(uint64(unsafe.Sizeof(RpathCmd{}))+uint64(len(s.Path)), t.LoadAlign())) | 
 | } | 
 |  | 
 | // Open opens the named file using os.Open and prepares it for use as a Mach-O binary. | 
 | func Open(name string) (*File, error) { | 
 | 	f, err := os.Open(name) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	ff, err := NewFile(f) | 
 | 	if err != nil { | 
 | 		f.Close() | 
 | 		return nil, err | 
 | 	} | 
 | 	ff.closer = f | 
 | 	return ff, nil | 
 | } | 
 |  | 
 | // Close closes the File. | 
 | // If the File was created using NewFile directly instead of Open, | 
 | // Close has no effect. | 
 | func (f *File) Close() error { | 
 | 	var err error | 
 | 	if f.closer != nil { | 
 | 		err = f.closer.Close() | 
 | 		f.closer = nil | 
 | 	} | 
 | 	return err | 
 | } | 
 |  | 
 | // NewFile creates a new File for accessing a Mach-O binary in an underlying reader. | 
 | // The Mach-O binary is expected to start at position 0 in the ReaderAt. | 
 | func NewFile(r io.ReaderAt) (*File, error) { | 
 | 	f := new(File) | 
 | 	sr := io.NewSectionReader(r, 0, 1<<63-1) | 
 |  | 
 | 	// Read and decode Mach magic to determine byte order, size. | 
 | 	// Magic32 and Magic64 differ only in the bottom bit. | 
 | 	var ident [4]byte | 
 | 	if _, err := r.ReadAt(ident[0:], 0); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	be := binary.BigEndian.Uint32(ident[0:]) | 
 | 	le := binary.LittleEndian.Uint32(ident[0:]) | 
 | 	switch Magic32 &^ 1 { | 
 | 	case be &^ 1: | 
 | 		f.ByteOrder = binary.BigEndian | 
 | 		f.Magic = be | 
 | 	case le &^ 1: | 
 | 		f.ByteOrder = binary.LittleEndian | 
 | 		f.Magic = le | 
 | 	default: | 
 | 		return nil, formatError(0, "invalid magic number be=0x%x, le=0x%x", be, le) | 
 | 	} | 
 |  | 
 | 	// Read entire file header. | 
 | 	if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 |  | 
 | 	// Then load commands. | 
 | 	offset := int64(fileHeaderSize32) | 
 | 	if f.Magic == Magic64 { | 
 | 		offset = fileHeaderSize64 | 
 | 	} | 
 | 	dat := make([]byte, f.SizeCommands) | 
 | 	if _, err := r.ReadAt(dat, offset); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	f.Loads = make([]Load, f.NCommands) | 
 | 	bo := f.ByteOrder | 
 | 	for i := range f.Loads { | 
 | 		// Each load command begins with uint32 command and length. | 
 | 		if len(dat) < 8 { | 
 | 			return nil, formatError(offset, "command block too small, len(dat) = %d", len(dat)) | 
 | 		} | 
 | 		cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8]) | 
 | 		if siz < 8 || siz > uint32(len(dat)) { | 
 | 			return nil, formatError(offset, "invalid command block size, len(dat)=%d, size=%d", len(dat), siz) | 
 | 		} | 
 | 		var cmddat []byte | 
 | 		cmddat, dat = dat[0:siz], dat[siz:] | 
 | 		offset += int64(siz) | 
 | 		var s *Segment | 
 | 		switch cmd { | 
 | 		default: | 
 | 			f.Loads[i] = LoadCmdBytes{LoadCmd(cmd), LoadBytes(cmddat)} | 
 |  | 
 | 		case LcUuid: | 
 | 			var hdr UuidCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := &Uuid{UuidCmd: hdr} | 
 |  | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcRpath: | 
 | 			var hdr RpathCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := &Rpath{LoadCmd: hdr.LoadCmd} | 
 | 			if hdr.Path >= uint32(len(cmddat)) { | 
 | 				return nil, formatError(offset, "invalid path in rpath command, len(cmddat)=%d, hdr.Path=%d", len(cmddat), hdr.Path) | 
 | 			} | 
 | 			l.Path = cstring(cmddat[hdr.Path:]) | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcLoadDylinker, LcIdDylinker, LcDyldEnvironment: | 
 | 			var hdr DylinkerCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := new(Dylinker) | 
 | 			if hdr.Name >= uint32(len(cmddat)) { | 
 | 				return nil, formatError(offset, "invalid name in dynamic linker command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat)) | 
 | 			} | 
 | 			l.Name = cstring(cmddat[hdr.Name:]) | 
 | 			l.DylinkerCmd = hdr | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcDylib: | 
 | 			var hdr DylibCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := new(Dylib) | 
 | 			if hdr.Name >= uint32(len(cmddat)) { | 
 | 				return nil, formatError(offset, "invalid name in dynamic library command, hdr.Name=%d, len(cmddat)=%d", hdr.Name, len(cmddat)) | 
 | 			} | 
 | 			l.Name = cstring(cmddat[hdr.Name:]) | 
 | 			l.Time = hdr.Time | 
 | 			l.CurrentVersion = hdr.CurrentVersion | 
 | 			l.CompatVersion = hdr.CompatVersion | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcSymtab: | 
 | 			var hdr SymtabCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			strtab := make([]byte, hdr.Strsize) | 
 | 			if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			var symsz int | 
 | 			if f.Magic == Magic64 { | 
 | 				symsz = 16 | 
 | 			} else { | 
 | 				symsz = 12 | 
 | 			} | 
 | 			symdat := make([]byte, int(hdr.Nsyms)*symsz) | 
 | 			if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset) | 
 | 			st.SymtabCmd = hdr | 
 | 			if err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			f.Loads[i] = st | 
 | 			f.Symtab = st | 
 |  | 
 | 		case LcDysymtab: | 
 | 			var hdr DysymtabCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			dat := make([]byte, hdr.Nindirectsyms*4) | 
 | 			if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			x := make([]uint32, hdr.Nindirectsyms) | 
 | 			if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			st := new(Dysymtab) | 
 | 			st.DysymtabCmd = hdr | 
 | 			st.IndirectSyms = x | 
 | 			f.Loads[i] = st | 
 | 			f.Dysymtab = st | 
 |  | 
 | 		case LcSegment: | 
 | 			var seg32 Segment32 | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &seg32); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			s = new(Segment) | 
 | 			s.LoadCmd = cmd | 
 | 			s.Len = siz | 
 | 			s.Name = cstring(seg32.Name[0:]) | 
 | 			s.Addr = uint64(seg32.Addr) | 
 | 			s.Memsz = uint64(seg32.Memsz) | 
 | 			s.Offset = uint64(seg32.Offset) | 
 | 			s.Filesz = uint64(seg32.Filesz) | 
 | 			s.Maxprot = seg32.Maxprot | 
 | 			s.Prot = seg32.Prot | 
 | 			s.Nsect = seg32.Nsect | 
 | 			s.Flag = seg32.Flag | 
 | 			s.Firstsect = uint32(len(f.Sections)) | 
 | 			f.Loads[i] = s | 
 | 			for i := 0; i < int(s.Nsect); i++ { | 
 | 				var sh32 Section32 | 
 | 				if err := binary.Read(b, bo, &sh32); err != nil { | 
 | 					return nil, err | 
 | 				} | 
 | 				sh := new(Section) | 
 | 				sh.Name = cstring(sh32.Name[0:]) | 
 | 				sh.Seg = cstring(sh32.Seg[0:]) | 
 | 				sh.Addr = uint64(sh32.Addr) | 
 | 				sh.Size = uint64(sh32.Size) | 
 | 				sh.Offset = sh32.Offset | 
 | 				sh.Align = sh32.Align | 
 | 				sh.Reloff = sh32.Reloff | 
 | 				sh.Nreloc = sh32.Nreloc | 
 | 				sh.Flags = sh32.Flags | 
 | 				sh.Reserved1 = sh32.Reserve1 | 
 | 				sh.Reserved2 = sh32.Reserve2 | 
 | 				if err := f.pushSection(sh, r); err != nil { | 
 | 					return nil, err | 
 | 				} | 
 | 			} | 
 |  | 
 | 		case LcSegment64: | 
 | 			var seg64 Segment64 | 
 | 			b := bytes.NewReader(cmddat) | 
 | 			if err := binary.Read(b, bo, &seg64); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			s = new(Segment) | 
 | 			s.LoadCmd = cmd | 
 | 			s.Len = siz | 
 | 			s.Name = cstring(seg64.Name[0:]) | 
 | 			s.Addr = seg64.Addr | 
 | 			s.Memsz = seg64.Memsz | 
 | 			s.Offset = seg64.Offset | 
 | 			s.Filesz = seg64.Filesz | 
 | 			s.Maxprot = seg64.Maxprot | 
 | 			s.Prot = seg64.Prot | 
 | 			s.Nsect = seg64.Nsect | 
 | 			s.Flag = seg64.Flag | 
 | 			s.Firstsect = uint32(len(f.Sections)) | 
 | 			f.Loads[i] = s | 
 | 			for i := 0; i < int(s.Nsect); i++ { | 
 | 				var sh64 Section64 | 
 | 				if err := binary.Read(b, bo, &sh64); err != nil { | 
 | 					return nil, err | 
 | 				} | 
 | 				sh := new(Section) | 
 | 				sh.Name = cstring(sh64.Name[0:]) | 
 | 				sh.Seg = cstring(sh64.Seg[0:]) | 
 | 				sh.Addr = sh64.Addr | 
 | 				sh.Size = sh64.Size | 
 | 				sh.Offset = sh64.Offset | 
 | 				sh.Align = sh64.Align | 
 | 				sh.Reloff = sh64.Reloff | 
 | 				sh.Nreloc = sh64.Nreloc | 
 | 				sh.Flags = sh64.Flags | 
 | 				sh.Reserved1 = sh64.Reserve1 | 
 | 				sh.Reserved2 = sh64.Reserve2 | 
 | 				sh.Reserved3 = sh64.Reserve3 | 
 | 				if err := f.pushSection(sh, r); err != nil { | 
 | 					return nil, err | 
 | 				} | 
 | 			} | 
 |  | 
 | 		case LcCodeSignature, LcSegmentSplitInfo, LcFunctionStarts, | 
 | 			LcDataInCode, LcDylibCodeSignDrs: | 
 | 			var hdr LinkEditDataCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 |  | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := new(LinkEditData) | 
 |  | 
 | 			l.LinkEditDataCmd = hdr | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcEncryptionInfo, LcEncryptionInfo64: | 
 | 			var hdr EncryptionInfoCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 |  | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := new(EncryptionInfo) | 
 |  | 
 | 			l.EncryptionInfoCmd = hdr | 
 | 			f.Loads[i] = l | 
 |  | 
 | 		case LcDyldInfo, LcDyldInfoOnly: | 
 | 			var hdr DyldInfoCmd | 
 | 			b := bytes.NewReader(cmddat) | 
 |  | 
 | 			if err := binary.Read(b, bo, &hdr); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			l := new(DyldInfo) | 
 |  | 
 | 			l.DyldInfoCmd = hdr | 
 | 			f.Loads[i] = l | 
 | 		} | 
 | 		if s != nil { | 
 | 			s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz)) | 
 | 			s.ReaderAt = s.sr | 
 | 		} | 
 | 		if f.Loads[i].LoadSize(&f.FileTOC) != siz { | 
 | 			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()) | 
 | 			panic("oops") | 
 | 		} | 
 | 	} | 
 | 	return f, nil | 
 | } | 
 |  | 
 | func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) { | 
 | 	bo := f.ByteOrder | 
 | 	symtab := make([]Symbol, hdr.Nsyms) | 
 | 	b := bytes.NewReader(symdat) | 
 | 	for i := range symtab { | 
 | 		var n Nlist64 | 
 | 		if f.Magic == Magic64 { | 
 | 			if err := binary.Read(b, bo, &n); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 		} else { | 
 | 			var n32 Nlist32 | 
 | 			if err := binary.Read(b, bo, &n32); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			n.Name = n32.Name | 
 | 			n.Type = n32.Type | 
 | 			n.Sect = n32.Sect | 
 | 			n.Desc = n32.Desc | 
 | 			n.Value = uint64(n32.Value) | 
 | 		} | 
 | 		sym := &symtab[i] | 
 | 		if n.Name >= uint32(len(strtab)) { | 
 | 			return nil, formatError(offset, "invalid name in symbol table, n.Name=%d, len(strtab)=%d", n.Name, len(strtab)) | 
 | 		} | 
 | 		sym.Name = cstring(strtab[n.Name:]) | 
 | 		sym.Type = n.Type | 
 | 		sym.Sect = n.Sect | 
 | 		sym.Desc = n.Desc | 
 | 		sym.Value = n.Value | 
 | 	} | 
 | 	st := new(Symtab) | 
 | 	st.Syms = symtab | 
 | 	return st, nil | 
 | } | 
 |  | 
 | type relocInfo struct { | 
 | 	Addr   uint32 | 
 | 	Symnum uint32 | 
 | } | 
 |  | 
 | func (f *File) pushSection(sh *Section, r io.ReaderAt) error { | 
 | 	f.Sections = append(f.Sections, sh) | 
 | 	sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) | 
 | 	sh.ReaderAt = sh.sr | 
 |  | 
 | 	if sh.Nreloc > 0 { | 
 | 		reldat := make([]byte, int(sh.Nreloc)*8) | 
 | 		if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil { | 
 | 			return err | 
 | 		} | 
 | 		b := bytes.NewReader(reldat) | 
 |  | 
 | 		bo := f.ByteOrder | 
 |  | 
 | 		sh.Relocs = make([]Reloc, sh.Nreloc) | 
 | 		for i := range sh.Relocs { | 
 | 			rel := &sh.Relocs[i] | 
 |  | 
 | 			var ri relocInfo | 
 | 			if err := binary.Read(b, bo, &ri); err != nil { | 
 | 				return err | 
 | 			} | 
 |  | 
 | 			if ri.Addr&(1<<31) != 0 { // scattered | 
 | 				rel.Addr = ri.Addr & (1<<24 - 1) | 
 | 				rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1)) | 
 | 				rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1)) | 
 | 				rel.Pcrel = ri.Addr&(1<<30) != 0 | 
 | 				rel.Value = ri.Symnum | 
 | 				rel.Scattered = true | 
 | 			} else { | 
 | 				switch bo { | 
 | 				case binary.LittleEndian: | 
 | 					rel.Addr = ri.Addr | 
 | 					rel.Value = ri.Symnum & (1<<24 - 1) | 
 | 					rel.Pcrel = ri.Symnum&(1<<24) != 0 | 
 | 					rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1)) | 
 | 					rel.Extern = ri.Symnum&(1<<27) != 0 | 
 | 					rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1)) | 
 | 				case binary.BigEndian: | 
 | 					rel.Addr = ri.Addr | 
 | 					rel.Value = ri.Symnum >> 8 | 
 | 					rel.Pcrel = ri.Symnum&(1<<7) != 0 | 
 | 					rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1)) | 
 | 					rel.Extern = ri.Symnum&(1<<4) != 0 | 
 | 					rel.Type = uint8(ri.Symnum & (1<<4 - 1)) | 
 | 				default: | 
 | 					panic("unreachable") | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | func cstring(b []byte) string { | 
 | 	i := bytes.IndexByte(b, 0) | 
 | 	if i == -1 { | 
 | 		i = len(b) | 
 | 	} | 
 | 	return string(b[0:i]) | 
 | } | 
 |  | 
 | // Segment returns the first Segment with the given name, or nil if no such segment exists. | 
 | func (f *File) Segment(name string) *Segment { | 
 | 	for _, l := range f.Loads { | 
 | 		if s, ok := l.(*Segment); ok && s.Name == name { | 
 | 			return s | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // Section returns the first section with the given name, or nil if no such | 
 | // section exists. | 
 | func (f *File) Section(name string) *Section { | 
 | 	for _, s := range f.Sections { | 
 | 		if s.Name == name { | 
 | 			return s | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // DWARF returns the DWARF debug information for the Mach-O file. | 
 | func (f *File) DWARF() (*dwarf.Data, error) { | 
 | 	dwarfSuffix := func(s *Section) string { | 
 | 		switch { | 
 | 		case strings.HasPrefix(s.Name, "__debug_"): | 
 | 			return s.Name[8:] | 
 | 		case strings.HasPrefix(s.Name, "__zdebug_"): | 
 | 			return s.Name[9:] | 
 | 		default: | 
 | 			return "" | 
 | 		} | 
 |  | 
 | 	} | 
 | 	sectionData := func(s *Section) ([]byte, error) { | 
 | 		b, err := s.Data() | 
 | 		if err != nil && uint64(len(b)) < s.Size { | 
 | 			return nil, err | 
 | 		} | 
 |  | 
 | 		if len(b) >= 12 && string(b[:4]) == "ZLIB" { | 
 | 			dlen := binary.BigEndian.Uint64(b[4:12]) | 
 | 			dbuf := make([]byte, dlen) | 
 | 			r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) | 
 | 			if err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			if _, err := io.ReadFull(r, dbuf); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			if err := r.Close(); err != nil { | 
 | 				return nil, err | 
 | 			} | 
 | 			b = dbuf | 
 | 		} | 
 | 		return b, nil | 
 | 	} | 
 |  | 
 | 	// There are many other DWARF sections, but these | 
 | 	// are the ones the debug/dwarf package uses. | 
 | 	// Don't bother loading others. | 
 | 	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} | 
 | 	for _, s := range f.Sections { | 
 | 		suffix := dwarfSuffix(s) | 
 | 		if suffix == "" { | 
 | 			continue | 
 | 		} | 
 | 		if _, ok := dat[suffix]; !ok { | 
 | 			continue | 
 | 		} | 
 | 		b, err := sectionData(s) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		dat[suffix] = b | 
 | 	} | 
 |  | 
 | 	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 |  | 
 | 	// Look for DWARF4 .debug_types sections. | 
 | 	for i, s := range f.Sections { | 
 | 		suffix := dwarfSuffix(s) | 
 | 		if suffix != "types" { | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		b, err := sectionData(s) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 |  | 
 | 		err = d.AddTypes(fmt.Sprintf("types-%d", i), b) | 
 | 		if err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return d, nil | 
 | } | 
 |  | 
 | // ImportedSymbols returns the names of all symbols | 
 | // referred to by the binary f that are expected to be | 
 | // satisfied by other libraries at dynamic load time. | 
 | func (f *File) ImportedSymbols() ([]string, error) { | 
 | 	if f.Dysymtab == nil || f.Symtab == nil { | 
 | 		return nil, formatError(0, "missing symbol table, f.Dsymtab=%v, f.Symtab=%v", f.Dysymtab, f.Symtab) | 
 | 	} | 
 |  | 
 | 	st := f.Symtab | 
 | 	dt := f.Dysymtab | 
 | 	var all []string | 
 | 	for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { | 
 | 		all = append(all, s.Name) | 
 | 	} | 
 | 	return all, nil | 
 | } | 
 |  | 
 | // ImportedLibraries returns the paths of all libraries | 
 | // referred to by the binary f that are expected to be | 
 | // linked with the binary at dynamic link time. | 
 | func (f *File) ImportedLibraries() ([]string, error) { | 
 | 	var all []string | 
 | 	for _, l := range f.Loads { | 
 | 		if lib, ok := l.(*Dylib); ok { | 
 | 			all = append(all, lib.Name) | 
 | 		} | 
 | 	} | 
 | 	return all, nil | 
 | } | 
 |  | 
 | func RoundUp(x, align uint64) uint64 { | 
 | 	return uint64((x + align - 1) & -align) | 
 | } |