1
2
3
4
5
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
31
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
46 N_ABS = -1
47 N_DEBUG = -2
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
113
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
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 switch f.pe.Machine {
186 case pe.IMAGE_FILE_MACHINE_I386:
187 return "386"
188 case pe.IMAGE_FILE_MACHINE_AMD64:
189 return "amd64"
190 case pe.IMAGE_FILE_MACHINE_ARMNT:
191 return "arm"
192 case pe.IMAGE_FILE_MACHINE_ARM64:
193 return "arm64"
194 default:
195 return ""
196 }
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 }
206
View as plain text