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