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