github.com/april1989/origin-go-tools@v0.0.32/cmd/splitdwarf/internal/macho/file.go (about)

     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  }