github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/objfile/objfile.go (about) 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 // Package objfile implements portable access to OS-specific executable files. 6 package objfile 7 8 import ( 9 "debug/dwarf" 10 "debug/gosym" 11 "fmt" 12 "io" 13 "os" 14 "sort" 15 ) 16 17 type rawFile interface { 18 symbols() (syms []Sym, err error) 19 pcln() (textStart uint64, symtab, pclntab []byte, err error) 20 text() (textStart uint64, text []byte, err error) 21 goarch() string 22 loadAddress() (uint64, error) 23 dwarf() (*dwarf.Data, error) 24 } 25 26 // A File is an opened executable file. 27 type File struct { 28 r *os.File 29 entries []*Entry 30 } 31 32 type Entry struct { 33 name string 34 raw rawFile 35 } 36 37 // A Sym is a symbol defined in an executable file. 38 type Sym struct { 39 Name string // symbol name 40 Addr uint64 // virtual address of symbol 41 Size int64 // size in bytes 42 Code rune // nm code (T for text, D for data, and so on) 43 Type string // XXX? 44 Relocs []Reloc // in increasing Addr order 45 } 46 47 type Reloc struct { 48 Addr uint64 // Address of first byte that reloc applies to. 49 Size uint64 // Number of bytes 50 Stringer RelocStringer 51 } 52 53 type RelocStringer interface { 54 // insnOffset is the offset of the instruction containing the relocation 55 // from the start of the symbol containing the relocation. 56 String(insnOffset uint64) string 57 } 58 59 var openers = []func(io.ReaderAt) (rawFile, error){ 60 openElf, 61 openMacho, 62 openPE, 63 openPlan9, 64 openXcoff, 65 } 66 67 // Open opens the named file. 68 // The caller must call f.Close when the file is no longer needed. 69 func Open(name string) (*File, error) { 70 r, err := os.Open(name) 71 if err != nil { 72 return nil, err 73 } 74 if f, err := openGoFile(r); err == nil { 75 return f, nil 76 } 77 for _, try := range openers { 78 if raw, err := try(r); err == nil { 79 return &File{r, []*Entry{{raw: raw}}}, nil 80 } 81 } 82 r.Close() 83 return nil, fmt.Errorf("open %s: unrecognized object file", name) 84 } 85 86 func (f *File) Close() error { 87 return f.r.Close() 88 } 89 90 func (f *File) Entries() []*Entry { 91 return f.entries 92 } 93 94 func (f *File) Symbols() ([]Sym, error) { 95 return f.entries[0].Symbols() 96 } 97 98 func (f *File) PCLineTable() (Liner, error) { 99 return f.entries[0].PCLineTable() 100 } 101 102 func (f *File) Text() (uint64, []byte, error) { 103 return f.entries[0].Text() 104 } 105 106 func (f *File) GOARCH() string { 107 return f.entries[0].GOARCH() 108 } 109 110 func (f *File) LoadAddress() (uint64, error) { 111 return f.entries[0].LoadAddress() 112 } 113 114 func (f *File) DWARF() (*dwarf.Data, error) { 115 return f.entries[0].DWARF() 116 } 117 118 func (f *File) Disasm() (*Disasm, error) { 119 return f.entries[0].Disasm() 120 } 121 122 func (e *Entry) Name() string { 123 return e.name 124 } 125 126 func (e *Entry) Symbols() ([]Sym, error) { 127 syms, err := e.raw.symbols() 128 if err != nil { 129 return nil, err 130 } 131 sort.Sort(byAddr(syms)) 132 return syms, nil 133 } 134 135 type byAddr []Sym 136 137 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } 138 func (x byAddr) Len() int { return len(x) } 139 func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 140 141 func (e *Entry) PCLineTable() (Liner, error) { 142 // If the raw file implements Liner directly, use that. 143 // Currently, only Go intermediate objects and archives (goobj) use this path. 144 if pcln, ok := e.raw.(Liner); ok { 145 return pcln, nil 146 } 147 // Otherwise, read the pcln tables and build a Liner out of that. 148 textStart, symtab, pclntab, err := e.raw.pcln() 149 if err != nil { 150 return nil, err 151 } 152 return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) 153 } 154 155 func (e *Entry) Text() (uint64, []byte, error) { 156 return e.raw.text() 157 } 158 159 func (e *Entry) GOARCH() string { 160 return e.raw.goarch() 161 } 162 163 // LoadAddress returns the expected load address of the file. 164 // This differs from the actual load address for a position-independent 165 // executable. 166 func (e *Entry) LoadAddress() (uint64, error) { 167 return e.raw.loadAddress() 168 } 169 170 // DWARF returns DWARF debug data for the file, if any. 171 // This is for cmd/pprof to locate cgo functions. 172 func (e *Entry) DWARF() (*dwarf.Data, error) { 173 return e.raw.dwarf() 174 }