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