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