Home | History | Annotate | Download | only in objfile
      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 	"os"
     14 	"sort"
     15 )
     16 
     17 const stabTypeMask = 0xe0
     18 
     19 type machoFile struct {
     20 	macho *macho.File
     21 }
     22 
     23 func openMacho(r *os.File) (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, fmt.Errorf("missing symbol table")
     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":
     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.CpuPpc64:
    117 		return "ppc64"
    118 	}
    119 	return ""
    120 }
    121 
    122 type uint64s []uint64
    123 
    124 func (x uint64s) Len() int           { return len(x) }
    125 func (x uint64s) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
    126 func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
    127 
    128 func (f *machoFile) loadAddress() (uint64, error) {
    129 	return 0, fmt.Errorf("unknown load address")
    130 }
    131 
    132 func (f *machoFile) dwarf() (*dwarf.Data, error) {
    133 	return f.macho.DWARF()
    134 }
    135