...

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

     1	// Copyright 2013 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	// Parsing of PE executables (Microsoft Windows).
     6	
     7	package objfile
     8	
     9	import (
    10		"debug/dwarf"
    11		"debug/pe"
    12		"fmt"
    13		"io"
    14		"sort"
    15	)
    16	
    17	type peFile struct {
    18		pe *pe.File
    19	}
    20	
    21	func openPE(r io.ReaderAt) (rawFile, error) {
    22		f, err := pe.NewFile(r)
    23		if err != nil {
    24			return nil, err
    25		}
    26		return &peFile{f}, nil
    27	}
    28	
    29	func (f *peFile) symbols() ([]Sym, error) {
    30		// Build sorted list of addresses of all symbols.
    31		// We infer the size of a symbol by looking at where the next symbol begins.
    32		var addrs []uint64
    33	
    34		var imageBase uint64
    35		switch oh := f.pe.OptionalHeader.(type) {
    36		case *pe.OptionalHeader32:
    37			imageBase = uint64(oh.ImageBase)
    38		case *pe.OptionalHeader64:
    39			imageBase = oh.ImageBase
    40		}
    41	
    42		var syms []Sym
    43		for _, s := range f.pe.Symbols {
    44			const (
    45				N_UNDEF = 0  // An undefined (extern) symbol
    46				N_ABS   = -1 // An absolute symbol (e_value is a constant, not an address)
    47				N_DEBUG = -2 // A debugging symbol
    48			)
    49			sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
    50			switch s.SectionNumber {
    51			case N_UNDEF:
    52				sym.Code = 'U'
    53			case N_ABS:
    54				sym.Code = 'C'
    55			case N_DEBUG:
    56				sym.Code = '?'
    57			default:
    58				if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) {
    59					return nil, fmt.Errorf("invalid section number in symbol table")
    60				}
    61				sect := f.pe.Sections[s.SectionNumber-1]
    62				const (
    63					text  = 0x20
    64					data  = 0x40
    65					bss   = 0x80
    66					permW = 0x80000000
    67				)
    68				ch := sect.Characteristics
    69				switch {
    70				case ch&text != 0:
    71					sym.Code = 'T'
    72				case ch&data != 0:
    73					if ch&permW == 0 {
    74						sym.Code = 'R'
    75					} else {
    76						sym.Code = 'D'
    77					}
    78				case ch&bss != 0:
    79					sym.Code = 'B'
    80				}
    81				sym.Addr += imageBase + uint64(sect.VirtualAddress)
    82			}
    83			syms = append(syms, sym)
    84			addrs = append(addrs, sym.Addr)
    85		}
    86	
    87		sort.Sort(uint64s(addrs))
    88		for i := range syms {
    89			j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
    90			if j < len(addrs) {
    91				syms[i].Size = int64(addrs[j] - syms[i].Addr)
    92			}
    93		}
    94	
    95		return syms, nil
    96	}
    97	
    98	func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
    99		var imageBase uint64
   100		switch oh := f.pe.OptionalHeader.(type) {
   101		case *pe.OptionalHeader32:
   102			imageBase = uint64(oh.ImageBase)
   103		case *pe.OptionalHeader64:
   104			imageBase = oh.ImageBase
   105		default:
   106			return 0, nil, nil, fmt.Errorf("pe file format not recognized")
   107		}
   108		if sect := f.pe.Section(".text"); sect != nil {
   109			textStart = imageBase + uint64(sect.VirtualAddress)
   110		}
   111		if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil {
   112			// We didn't find the symbols, so look for the names used in 1.3 and earlier.
   113			// TODO: Remove code looking for the old symbols when we no longer care about 1.3.
   114			var err2 error
   115			if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil {
   116				return 0, nil, nil, err
   117			}
   118		}
   119		if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil {
   120			// Same as above.
   121			var err2 error
   122			if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil {
   123				return 0, nil, nil, err
   124			}
   125		}
   126		return textStart, symtab, pclntab, nil
   127	}
   128	
   129	func (f *peFile) text() (textStart uint64, text []byte, err error) {
   130		var imageBase uint64
   131		switch oh := f.pe.OptionalHeader.(type) {
   132		case *pe.OptionalHeader32:
   133			imageBase = uint64(oh.ImageBase)
   134		case *pe.OptionalHeader64:
   135			imageBase = oh.ImageBase
   136		default:
   137			return 0, nil, fmt.Errorf("pe file format not recognized")
   138		}
   139		sect := f.pe.Section(".text")
   140		if sect == nil {
   141			return 0, nil, fmt.Errorf("text section not found")
   142		}
   143		textStart = imageBase + uint64(sect.VirtualAddress)
   144		text, err = sect.Data()
   145		return
   146	}
   147	
   148	func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
   149		for _, s := range f.Symbols {
   150			if s.Name != name {
   151				continue
   152			}
   153			if s.SectionNumber <= 0 {
   154				return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
   155			}
   156			if len(f.Sections) < int(s.SectionNumber) {
   157				return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
   158			}
   159			return s, nil
   160		}
   161		return nil, fmt.Errorf("no %s symbol found", name)
   162	}
   163	
   164	func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
   165		ssym, err := findPESymbol(f, sname)
   166		if err != nil {
   167			return nil, err
   168		}
   169		esym, err := findPESymbol(f, ename)
   170		if err != nil {
   171			return nil, err
   172		}
   173		if ssym.SectionNumber != esym.SectionNumber {
   174			return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
   175		}
   176		sect := f.Sections[ssym.SectionNumber-1]
   177		data, err := sect.Data()
   178		if err != nil {
   179			return nil, err
   180		}
   181		return data[ssym.Value:esym.Value], nil
   182	}
   183	
   184	func (f *peFile) goarch() string {
   185		// Not sure how to get the info we want from PE header.
   186		// Look in symbol table for telltale rt0 symbol.
   187		if _, err := findPESymbol(f.pe, "_rt0_386_windows"); err == nil {
   188			return "386"
   189		}
   190		if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil {
   191			return "amd64"
   192		}
   193		if _, err := findPESymbol(f.pe, "_rt0_arm_windows"); err == nil {
   194			return "arm"
   195		}
   196		return ""
   197	}
   198	
   199	func (f *peFile) loadAddress() (uint64, error) {
   200		return 0, fmt.Errorf("unknown load address")
   201	}
   202	
   203	func (f *peFile) dwarf() (*dwarf.Data, error) {
   204		return f.pe.DWARF()
   205	}
   206	

View as plain text