github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/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 } 65 66 // Open opens the named file. 67 // The caller must call f.Close when the file is no longer needed. 68 func Open(name string) (*File, error) { 69 r, err := os.Open(name) 70 if err != nil { 71 return nil, err 72 } 73 if f, err := openGoFile(r); err == nil { 74 return f, nil 75 } 76 for _, try := range openers { 77 if raw, err := try(r); err == nil { 78 return &File{r, []*Entry{&Entry{raw: raw}}}, nil 79 } 80 } 81 r.Close() 82 return nil, fmt.Errorf("open %s: unrecognized object file", name) 83 } 84 85 func (f *File) Close() error { 86 return f.r.Close() 87 } 88 89 func (f *File) Entries() []*Entry { 90 return f.entries 91 } 92 93 func (f *File) Symbols() ([]Sym, error) { 94 return f.entries[0].Symbols() 95 } 96 97 func (f *File) PCLineTable() (Liner, error) { 98 return f.entries[0].PCLineTable() 99 } 100 101 func (f *File) Text() (uint64, []byte, error) { 102 return f.entries[0].Text() 103 } 104 105 func (f *File) GOARCH() string { 106 return f.entries[0].GOARCH() 107 } 108 109 func (f *File) LoadAddress() (uint64, error) { 110 return f.entries[0].LoadAddress() 111 } 112 113 func (f *File) DWARF() (*dwarf.Data, error) { 114 return f.entries[0].DWARF() 115 } 116 117 func (f *File) Disasm() (*Disasm, error) { 118 return f.entries[0].Disasm() 119 } 120 121 func (e *Entry) Name() string { 122 return e.name 123 } 124 125 func (e *Entry) Symbols() ([]Sym, error) { 126 syms, err := e.raw.symbols() 127 if err != nil { 128 return nil, err 129 } 130 sort.Sort(byAddr(syms)) 131 return syms, nil 132 } 133 134 type byAddr []Sym 135 136 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } 137 func (x byAddr) Len() int { return len(x) } 138 func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 139 140 func (e *Entry) PCLineTable() (Liner, error) { 141 // If the raw file implements Liner directly, use that. 142 // Currently, only Go intermediate objects and archives (goobj) use this path. 143 if pcln, ok := e.raw.(Liner); ok { 144 return pcln, nil 145 } 146 // Otherwise, read the pcln tables and build a Liner out of that. 147 textStart, symtab, pclntab, err := e.raw.pcln() 148 if err != nil { 149 return nil, err 150 } 151 return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) 152 } 153 154 func (e *Entry) Text() (uint64, []byte, error) { 155 return e.raw.text() 156 } 157 158 func (e *Entry) GOARCH() string { 159 return e.raw.goarch() 160 } 161 162 // LoadAddress returns the expected load address of the file. 163 // This differs from the actual load address for a position-independent 164 // executable. 165 func (e *Entry) LoadAddress() (uint64, error) { 166 return e.raw.loadAddress() 167 } 168 169 // DWARF returns DWARF debug data for the file, if any. 170 // This is for cmd/pprof to locate cgo functions. 171 func (e *Entry) DWARF() (*dwarf.Data, error) { 172 return e.raw.dwarf() 173 }