1 // Copyright 2014 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 Plan 9 a.out executables. 6 7 package objfile 8 9 import ( 10 "debug/dwarf" 11 "debug/plan9obj" 12 "errors" 13 "fmt" 14 "os" 15 "sort" 16 ) 17 18 var validSymType = map[rune]bool{ 19 'T': true, 20 't': true, 21 'D': true, 22 'd': true, 23 'B': true, 24 'b': true, 25 } 26 27 type plan9File struct { 28 plan9 *plan9obj.File 29 } 30 31 func openPlan9(r *os.File) (rawFile, error) { 32 f, err := plan9obj.NewFile(r) 33 if err != nil { 34 return nil, err 35 } 36 return &plan9File{f}, nil 37 } 38 39 func (f *plan9File) symbols() ([]Sym, error) { 40 plan9Syms, err := f.plan9.Symbols() 41 if err != nil { 42 return nil, err 43 } 44 45 // Build sorted list of addresses of all symbols. 46 // We infer the size of a symbol by looking at where the next symbol begins. 47 var addrs []uint64 48 for _, s := range plan9Syms { 49 if !validSymType[s.Type] { 50 continue 51 } 52 addrs = append(addrs, s.Value) 53 } 54 sort.Sort(uint64s(addrs)) 55 56 var syms []Sym 57 58 for _, s := range plan9Syms { 59 if !validSymType[s.Type] { 60 continue 61 } 62 sym := Sym{Addr: s.Value, Name: s.Name, Code: s.Type} 63 i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) 64 if i < len(addrs) { 65 sym.Size = int64(addrs[i] - s.Value) 66 } 67 syms = append(syms, sym) 68 } 69 70 return syms, nil 71 } 72 73 func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) { 74 textStart = f.plan9.LoadAddress + f.plan9.HdrSize 75 if pclntab, err = loadPlan9Table(f.plan9, "runtime.pclntab", "runtime.epclntab"); err != nil { 76 // We didn't find the symbols, so look for the names used in 1.3 and earlier. 77 // TODO: Remove code looking for the old symbols when we no longer care about 1.3. 78 var err2 error 79 if pclntab, err2 = loadPlan9Table(f.plan9, "pclntab", "epclntab"); err2 != nil { 80 return 0, nil, nil, err 81 } 82 } 83 if symtab, err = loadPlan9Table(f.plan9, "runtime.symtab", "runtime.esymtab"); err != nil { 84 // Same as above. 85 var err2 error 86 if symtab, err2 = loadPlan9Table(f.plan9, "symtab", "esymtab"); err2 != nil { 87 return 0, nil, nil, err 88 } 89 } 90 return textStart, symtab, pclntab, nil 91 } 92 93 func (f *plan9File) text() (textStart uint64, text []byte, err error) { 94 sect := f.plan9.Section("text") 95 if sect == nil { 96 return 0, nil, fmt.Errorf("text section not found") 97 } 98 textStart = f.plan9.LoadAddress + f.plan9.HdrSize 99 text, err = sect.Data() 100 return 101 } 102 103 func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { 104 syms, err := f.Symbols() 105 if err != nil { 106 return nil, err 107 } 108 for _, s := range syms { 109 if s.Name != name { 110 continue 111 } 112 return &s, nil 113 } 114 return nil, fmt.Errorf("no %s symbol found", name) 115 } 116 117 func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { 118 ssym, err := findPlan9Symbol(f, sname) 119 if err != nil { 120 return nil, err 121 } 122 esym, err := findPlan9Symbol(f, ename) 123 if err != nil { 124 return nil, err 125 } 126 sect := f.Section("text") 127 if sect == nil { 128 return nil, err 129 } 130 data, err := sect.Data() 131 if err != nil { 132 return nil, err 133 } 134 textStart := f.LoadAddress + f.HdrSize 135 return data[ssym.Value-textStart : esym.Value-textStart], nil 136 } 137 138 func (f *plan9File) goarch() string { 139 switch f.plan9.Magic { 140 case plan9obj.Magic386: 141 return "386" 142 case plan9obj.MagicAMD64: 143 return "amd64" 144 case plan9obj.MagicARM: 145 return "arm" 146 } 147 return "" 148 } 149 150 func (f *plan9File) loadAddress() (uint64, error) { 151 return 0, fmt.Errorf("unknown load address") 152 } 153 154 func (f *plan9File) dwarf() (*dwarf.Data, error) { 155 return nil, errors.New("no DWARF data in Plan 9 file") 156 } 157