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. 6package objfile 7 8import ( 9 "debug/dwarf" 10 "debug/gosym" 11 "fmt" 12 "io" 13 "os" 14 "sort" 15) 16 17type 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. 27type File struct { 28 r *os.File 29 entries []*Entry 30} 31 32type Entry struct { 33 name string 34 raw rawFile 35} 36 37// A Sym is a symbol defined in an executable file. 38type 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 47type Reloc struct { 48 Addr uint64 // Address of first byte that reloc applies to. 49 Size uint64 // Number of bytes 50 Stringer RelocStringer 51} 52 53type 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 59var 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. 69func 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 86func (f *File) Close() error { 87 return f.r.Close() 88} 89 90func (f *File) Entries() []*Entry { 91 return f.entries 92} 93 94func (f *File) Symbols() ([]Sym, error) { 95 return f.entries[0].Symbols() 96} 97 98func (f *File) PCLineTable() (Liner, error) { 99 return f.entries[0].PCLineTable() 100} 101 102func (f *File) Text() (uint64, []byte, error) { 103 return f.entries[0].Text() 104} 105 106func (f *File) GOARCH() string { 107 return f.entries[0].GOARCH() 108} 109 110func (f *File) LoadAddress() (uint64, error) { 111 return f.entries[0].LoadAddress() 112} 113 114func (f *File) DWARF() (*dwarf.Data, error) { 115 return f.entries[0].DWARF() 116} 117 118func (f *File) Disasm() (*Disasm, error) { 119 return f.entries[0].Disasm() 120} 121 122func (e *Entry) Name() string { 123 return e.name 124} 125 126func (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 135type byAddr []Sym 136 137func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } 138func (x byAddr) Len() int { return len(x) } 139func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 140 141func (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 155func (e *Entry) Text() (uint64, []byte, error) { 156 return e.raw.text() 157} 158 159func (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. 166func (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. 172func (e *Entry) DWARF() (*dwarf.Data, error) { 173 return e.raw.dwarf() 174} 175