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