github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/nm/pe.go (about)

     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 main
     8  
     9  import (
    10  	"debug/pe"
    11  	"os"
    12  	"sort"
    13  )
    14  
    15  func peSymbols(f *os.File) []Sym {
    16  	p, err := pe.NewFile(f)
    17  	if err != nil {
    18  		errorf("parsing %s: %v", f.Name(), err)
    19  		return nil
    20  	}
    21  
    22  	// Build sorted list of addresses of all symbols.
    23  	// We infer the size of a symbol by looking at where the next symbol begins.
    24  	var addrs []uint64
    25  
    26  	var imageBase uint64
    27  	switch oh := p.OptionalHeader.(type) {
    28  	case *pe.OptionalHeader32:
    29  		imageBase = uint64(oh.ImageBase)
    30  	case *pe.OptionalHeader64:
    31  		imageBase = oh.ImageBase
    32  	default:
    33  		errorf("parsing %s: file format not recognized", f.Name())
    34  		return nil
    35  	}
    36  
    37  	var syms []Sym
    38  	for _, s := range p.Symbols {
    39  		const (
    40  			N_UNDEF = 0  // An undefined (extern) symbol
    41  			N_ABS   = -1 // An absolute symbol (e_value is a constant, not an address)
    42  			N_DEBUG = -2 // A debugging symbol
    43  		)
    44  		sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
    45  		switch s.SectionNumber {
    46  		case N_UNDEF:
    47  			sym.Code = 'U'
    48  		case N_ABS:
    49  			sym.Code = 'C'
    50  		case N_DEBUG:
    51  			sym.Code = '?'
    52  		default:
    53  			if s.SectionNumber < 0 {
    54  				errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber)
    55  				return nil
    56  			}
    57  			if len(p.Sections) < int(s.SectionNumber) {
    58  				errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections))
    59  				return nil
    60  			}
    61  			sect := p.Sections[s.SectionNumber-1]
    62  			const (
    63  				text  = 0x20
    64  				data  = 0x40
    65  				bss   = 0x80
    66  				permX = 0x20000000
    67  				permR = 0x40000000
    68  				permW = 0x80000000
    69  			)
    70  			ch := sect.Characteristics
    71  			switch {
    72  			case ch&text != 0:
    73  				sym.Code = 'T'
    74  			case ch&data != 0:
    75  				if ch&permW == 0 {
    76  					sym.Code = 'R'
    77  				} else {
    78  					sym.Code = 'D'
    79  				}
    80  			case ch&bss != 0:
    81  				sym.Code = 'B'
    82  			}
    83  			sym.Addr += imageBase + uint64(sect.VirtualAddress)
    84  		}
    85  		syms = append(syms, sym)
    86  		addrs = append(addrs, sym.Addr)
    87  	}
    88  
    89  	sort.Sort(uint64s(addrs))
    90  	for i := range syms {
    91  		j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
    92  		if j < len(addrs) {
    93  			syms[i].Size = int64(addrs[j] - syms[i].Addr)
    94  		}
    95  	}
    96  
    97  	return syms
    98  }