...

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

Documentation: cmd/internal/objfile

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

View as plain text