...

Source file src/pkg/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":
    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		return 0, fmt.Errorf("unknown load address")
   132	}
   133	
   134	func (f *machoFile) dwarf() (*dwarf.Data, error) {
   135		return f.macho.DWARF()
   136	}
   137	

View as plain text