Source file src/cmd/internal/objfile/macho.go

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

View as plain text