Home | History | Annotate | Download | only in objfile
      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/gosym"
     10 	"fmt"
     11 	"os"
     12 	"sort"
     13 )
     14 
     15 type rawFile interface {
     16 	symbols() (syms []Sym, err error)
     17 	pcln() (textStart uint64, symtab, pclntab []byte, err error)
     18 	text() (textStart uint64, text []byte, err error)
     19 	goarch() string
     20 }
     21 
     22 // A File is an opened executable file.
     23 type File struct {
     24 	r   *os.File
     25 	raw rawFile
     26 }
     27 
     28 // A Sym is a symbol defined in an executable file.
     29 type Sym struct {
     30 	Name string // symbol name
     31 	Addr uint64 // virtual address of symbol
     32 	Size int64  // size in bytes
     33 	Code rune   // nm code (T for text, D for data, and so on)
     34 	Type string // XXX?
     35 }
     36 
     37 var openers = []func(*os.File) (rawFile, error){
     38 	openElf,
     39 	openGoobj,
     40 	openMacho,
     41 	openPE,
     42 	openPlan9,
     43 }
     44 
     45 // Open opens the named file.
     46 // The caller must call f.Close when the file is no longer needed.
     47 func Open(name string) (*File, error) {
     48 	r, err := os.Open(name)
     49 	if err != nil {
     50 		return nil, err
     51 	}
     52 	for _, try := range openers {
     53 		if raw, err := try(r); err == nil {
     54 			return &File{r, raw}, nil
     55 		}
     56 	}
     57 	r.Close()
     58 	return nil, fmt.Errorf("open %s: unrecognized object file", name)
     59 }
     60 
     61 func (f *File) Close() error {
     62 	return f.r.Close()
     63 }
     64 
     65 func (f *File) Symbols() ([]Sym, error) {
     66 	syms, err := f.raw.symbols()
     67 	if err != nil {
     68 		return nil, err
     69 	}
     70 	sort.Sort(byAddr(syms))
     71 	return syms, nil
     72 }
     73 
     74 type byAddr []Sym
     75 
     76 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
     77 func (x byAddr) Len() int           { return len(x) }
     78 func (x byAddr) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
     79 
     80 func (f *File) PCLineTable() (*gosym.Table, error) {
     81 	textStart, symtab, pclntab, err := f.raw.pcln()
     82 	if err != nil {
     83 		return nil, err
     84 	}
     85 	return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart))
     86 }
     87 
     88 func (f *File) Text() (uint64, []byte, error) {
     89 	return f.raw.text()
     90 }
     91 
     92 func (f *File) GOARCH() string {
     93 	return f.raw.goarch()
     94 }
     95