github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/internal/objfile/macho.go (about)

     1  // Copyright 2013 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  // Parsing of Mach-O executables (OS X).
     6  
     7  package objfile
     8  
     9  import (
    10  	"debug/macho"
    11  	"fmt"
    12  	"os"
    13  	"sort"
    14  )
    15  
    16  const stabTypeMask = 0xe0
    17  
    18  type machoFile struct {
    19  	macho *macho.File
    20  }
    21  
    22  func openMacho(r *os.File) (rawFile, error) {
    23  	f, err := macho.NewFile(r)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	return &machoFile{f}, nil
    28  }
    29  
    30  func (f *machoFile) symbols() ([]Sym, error) {
    31  	if f.macho.Symtab == nil {
    32  		return nil, fmt.Errorf("missing symbol table")
    33  	}
    34  
    35  	// Build sorted list of addresses of all symbols.
    36  	// We infer the size of a symbol by looking at where the next symbol begins.
    37  	var addrs []uint64
    38  	for _, s := range f.macho.Symtab.Syms {
    39  		// Skip stab debug info.
    40  		if s.Type&stabTypeMask == 0 {
    41  			addrs = append(addrs, s.Value)
    42  		}
    43  	}
    44  	sort.Sort(uint64s(addrs))
    45  
    46  	var syms []Sym
    47  	for _, s := range f.macho.Symtab.Syms {
    48  		if s.Type&stabTypeMask != 0 {
    49  			// Skip stab debug info.
    50  			continue
    51  		}
    52  		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
    53  		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
    54  		if i < len(addrs) {
    55  			sym.Size = int64(addrs[i] - s.Value)
    56  		}
    57  		if s.Sect == 0 {
    58  			sym.Code = 'U'
    59  		} else if int(s.Sect) <= len(f.macho.Sections) {
    60  			sect := f.macho.Sections[s.Sect-1]
    61  			switch sect.Seg {
    62  			case "__TEXT":
    63  				sym.Code = 'R'
    64  			case "__DATA":
    65  				sym.Code = 'D'
    66  			}
    67  			switch sect.Seg + " " + sect.Name {
    68  			case "__TEXT __text":
    69  				sym.Code = 'T'
    70  			case "__DATA __bss", "__DATA __noptrbss":
    71  				sym.Code = 'B'
    72  			}
    73  		}
    74  		syms = append(syms, sym)
    75  	}
    76  
    77  	return syms, nil
    78  }
    79  
    80  func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
    81  	if sect := f.macho.Section("__text"); sect != nil {
    82  		textStart = sect.Addr
    83  	}
    84  	if sect := f.macho.Section("__gosymtab"); sect != nil {
    85  		if symtab, err = sect.Data(); err != nil {
    86  			return 0, nil, nil, err
    87  		}
    88  	}
    89  	if sect := f.macho.Section("__gopclntab"); sect != nil {
    90  		if pclntab, err = sect.Data(); err != nil {
    91  			return 0, nil, nil, err
    92  		}
    93  	}
    94  	return textStart, symtab, pclntab, nil
    95  }
    96  
    97  func (f *machoFile) text() (textStart uint64, text []byte, err error) {
    98  	sect := f.macho.Section("__text")
    99  	if sect == nil {
   100  		return 0, nil, fmt.Errorf("text section not found")
   101  	}
   102  	textStart = sect.Addr
   103  	text, err = sect.Data()
   104  	return
   105  }
   106  
   107  func (f *machoFile) goarch() string {
   108  	switch f.macho.Cpu {
   109  	case macho.Cpu386:
   110  		return "386"
   111  	case macho.CpuAmd64:
   112  		return "amd64"
   113  	case macho.CpuArm:
   114  		return "arm"
   115  	case macho.CpuPpc64:
   116  		return "ppc64"
   117  	}
   118  	return ""
   119  }
   120  
   121  type uint64s []uint64
   122  
   123  func (x uint64s) Len() int           { return len(x) }
   124  func (x uint64s) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   125  func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }