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