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 permW = 0x80000000 73 ) 74 ch := sect.Characteristics 75 switch { 76 case ch&text != 0: 77 sym.Code = 'T' 78 case ch&data != 0: 79 if ch&permW == 0 { 80 sym.Code = 'R' 81 } else { 82 sym.Code = 'D' 83 } 84 case ch&bss != 0: 85 sym.Code = 'B' 86 } 87 sym.Addr += imageBase + uint64(sect.VirtualAddress) 88 } 89 syms = append(syms, sym) 90 addrs = append(addrs, sym.Addr) 91 } 92 93 sort.Sort(uint64s(addrs)) 94 for i := range syms { 95 j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) 96 if j < len(addrs) { 97 syms[i].Size = int64(addrs[j] - syms[i].Addr) 98 } 99 } 100 101 return syms, nil 102 } 103 104 func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { 105 var imageBase uint64 106 switch oh := f.pe.OptionalHeader.(type) { 107 case *pe.OptionalHeader32: 108 imageBase = uint64(oh.ImageBase) 109 case *pe.OptionalHeader64: 110 imageBase = oh.ImageBase 111 default: 112 return 0, nil, nil, fmt.Errorf("pe file format not recognized") 113 } 114 if sect := f.pe.Section(".text"); sect != nil { 115 textStart = imageBase + uint64(sect.VirtualAddress) 116 } 117 if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil { 118 // We didn't find the symbols, so look for the names used in 1.3 and earlier. 119 // TODO: Remove code looking for the old symbols when we no longer care about 1.3. 120 var err2 error 121 if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil { 122 return 0, nil, nil, err 123 } 124 } 125 if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil { 126 // Same as above. 127 var err2 error 128 if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil { 129 return 0, nil, nil, err 130 } 131 } 132 return textStart, symtab, pclntab, nil 133 } 134 135 func (f *peFile) text() (textStart uint64, text []byte, err error) { 136 var imageBase uint64 137 switch oh := f.pe.OptionalHeader.(type) { 138 case *pe.OptionalHeader32: 139 imageBase = uint64(oh.ImageBase) 140 case *pe.OptionalHeader64: 141 imageBase = oh.ImageBase 142 default: 143 return 0, nil, fmt.Errorf("pe file format not recognized") 144 } 145 sect := f.pe.Section(".text") 146 if sect == nil { 147 return 0, nil, fmt.Errorf("text section not found") 148 } 149 textStart = imageBase + uint64(sect.VirtualAddress) 150 text, err = sect.Data() 151 return 152 } 153 154 func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { 155 for _, s := range f.Symbols { 156 if s.Name != name { 157 continue 158 } 159 if s.SectionNumber <= 0 { 160 return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) 161 } 162 if len(f.Sections) < int(s.SectionNumber) { 163 return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) 164 } 165 return s, nil 166 } 167 return nil, fmt.Errorf("no %s symbol found", name) 168 } 169 170 func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { 171 ssym, err := findPESymbol(f, sname) 172 if err != nil { 173 return nil, err 174 } 175 esym, err := findPESymbol(f, ename) 176 if err != nil { 177 return nil, err 178 } 179 if ssym.SectionNumber != esym.SectionNumber { 180 return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) 181 } 182 sect := f.Sections[ssym.SectionNumber-1] 183 data, err := sect.Data() 184 if err != nil { 185 return nil, err 186 } 187 return data[ssym.Value:esym.Value], nil 188 } 189 190 func (f *peFile) goarch() string { 191 // Not sure how to get the info we want from PE header. 192 // Look in symbol table for telltale rt0 symbol. 193 if _, err := findPESymbol(f.pe, "_rt0_386_windows"); err == nil { 194 return "386" 195 } 196 if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil { 197 return "amd64" 198 } 199 return "" 200 } 201 202 func (f *peFile) loadAddress() (uint64, error) { 203 return 0, fmt.Errorf("unknown load address") 204 } 205 206 func (f *peFile) dwarf() (*dwarf.Data, error) { 207 return f.pe.DWARF() 208 } 209