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