...

Source file src/cmd/internal/objfile/objfile.go

     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		openXcoff,
    65	}
    66	
    67	// Open opens the named file.
    68	// The caller must call f.Close when the file is no longer needed.
    69	func 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{&Entry{raw: raw}}}, nil
    80			}
    81		}
    82		r.Close()
    83		return nil, fmt.Errorf("open %s: unrecognized object file", name)
    84	}
    85	
    86	func (f *File) Close() error {
    87		return f.r.Close()
    88	}
    89	
    90	func (f *File) Entries() []*Entry {
    91		return f.entries
    92	}
    93	
    94	func (f *File) Symbols() ([]Sym, error) {
    95		return f.entries[0].Symbols()
    96	}
    97	
    98	func (f *File) PCLineTable() (Liner, error) {
    99		return f.entries[0].PCLineTable()
   100	}
   101	
   102	func (f *File) Text() (uint64, []byte, error) {
   103		return f.entries[0].Text()
   104	}
   105	
   106	func (f *File) GOARCH() string {
   107		return f.entries[0].GOARCH()
   108	}
   109	
   110	func (f *File) LoadAddress() (uint64, error) {
   111		return f.entries[0].LoadAddress()
   112	}
   113	
   114	func (f *File) DWARF() (*dwarf.Data, error) {
   115		return f.entries[0].DWARF()
   116	}
   117	
   118	func (f *File) Disasm() (*Disasm, error) {
   119		return f.entries[0].Disasm()
   120	}
   121	
   122	func (e *Entry) Name() string {
   123		return e.name
   124	}
   125	
   126	func (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	
   135	type byAddr []Sym
   136	
   137	func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
   138	func (x byAddr) Len() int           { return len(x) }
   139	func (x byAddr) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   140	
   141	func (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	
   155	func (e *Entry) Text() (uint64, []byte, error) {
   156		return e.raw.text()
   157	}
   158	
   159	func (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.
   166	func (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.
   172	func (e *Entry) DWARF() (*dwarf.Data, error) {
   173		return e.raw.dwarf()
   174	}
   175	

View as plain text