| // Copyright 2014 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Package objfile implements portable access to OS-specific executable files. | |
| package objfile | |
| import ( | |
| "debug/gosym" | |
| "fmt" | |
| "os" | |
| "sort" | |
| ) | |
| type rawFile interface { | |
| symbols() (syms []Sym, err error) | |
| pcln() (textStart uint64, symtab, pclntab []byte, err error) | |
| text() (textStart uint64, text []byte, err error) | |
| goarch() string | |
| } | |
| // A File is an opened executable file. | |
| type File struct { | |
| r *os.File | |
| raw rawFile | |
| } | |
| // A Sym is a symbol defined in an executable file. | |
| type Sym struct { | |
| Name string // symbol name | |
| Addr uint64 // virtual address of symbol | |
| Size int64 // size in bytes | |
| Code rune // nm code (T for text, D for data, and so on) | |
| Type string // XXX? | |
| } | |
| var openers = []func(*os.File) (rawFile, error){ | |
| openElf, | |
| openGoobj, | |
| openMacho, | |
| openPE, | |
| openPlan9, | |
| } | |
| // Open opens the named file. | |
| // The caller must call f.Close when the file is no longer needed. | |
| func Open(name string) (*File, error) { | |
| r, err := os.Open(name) | |
| if err != nil { | |
| return nil, err | |
| } | |
| for _, try := range openers { | |
| if raw, err := try(r); err == nil { | |
| return &File{r, raw}, nil | |
| } | |
| } | |
| r.Close() | |
| return nil, fmt.Errorf("open %s: unrecognized object file", name) | |
| } | |
| func (f *File) Close() error { | |
| return f.r.Close() | |
| } | |
| func (f *File) Symbols() ([]Sym, error) { | |
| syms, err := f.raw.symbols() | |
| if err != nil { | |
| return nil, err | |
| } | |
| sort.Sort(byAddr(syms)) | |
| return syms, nil | |
| } | |
| type byAddr []Sym | |
| func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } | |
| func (x byAddr) Len() int { return len(x) } | |
| func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | |
| func (f *File) PCLineTable() (*gosym.Table, error) { | |
| textStart, symtab, pclntab, err := f.raw.pcln() | |
| if err != nil { | |
| return nil, err | |
| } | |
| return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) | |
| } | |
| func (f *File) Text() (uint64, []byte, error) { | |
| return f.raw.text() | |
| } | |
| func (f *File) GOARCH() string { | |
| return f.raw.goarch() | |
| } |