Source file
src/debug/pe/symbol.go
1
2
3
4
5 package pe
6
7 import (
8 "encoding/binary"
9 "errors"
10 "fmt"
11 "internal/saferio"
12 "io"
13 "unsafe"
14 )
15
16 const COFFSymbolSize = 18
17
18
19 type COFFSymbol struct {
20 Name [8]uint8
21 Value uint32
22 SectionNumber int16
23 Type uint16
24 StorageClass uint8
25 NumberOfAuxSymbols uint8
26 }
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
52 if fh.PointerToSymbolTable == 0 {
53 return nil, nil
54 }
55 if fh.NumberOfSymbols <= 0 {
56 return nil, nil
57 }
58 _, err := r.Seek(int64(fh.PointerToSymbolTable), io.SeekStart)
59 if err != nil {
60 return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
61 }
62 c := saferio.SliceCap[COFFSymbol](uint64(fh.NumberOfSymbols))
63 if c < 0 {
64 return nil, errors.New("too many symbols; file may be corrupt")
65 }
66 syms := make([]COFFSymbol, 0, c)
67 naux := 0
68 for k := uint32(0); k < fh.NumberOfSymbols; k++ {
69 var sym COFFSymbol
70 if naux == 0 {
71
72 err = binary.Read(r, binary.LittleEndian, &sym)
73 if err != nil {
74 return nil, fmt.Errorf("fail to read symbol table: %v", err)
75 }
76
77 naux = int(sym.NumberOfAuxSymbols)
78 } else {
79
80
81
82
83 naux--
84 aux := (*COFFSymbolAuxFormat5)(unsafe.Pointer(&sym))
85 err = binary.Read(r, binary.LittleEndian, aux)
86 if err != nil {
87 return nil, fmt.Errorf("fail to read symbol table: %v", err)
88 }
89 }
90 syms = append(syms, sym)
91 }
92 if naux != 0 {
93 return nil, fmt.Errorf("fail to read symbol table: %d aux symbols unread", naux)
94 }
95 return syms, nil
96 }
97
98
99 func isSymNameOffset(name [8]byte) (bool, uint32) {
100 if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
101 return true, binary.LittleEndian.Uint32(name[4:])
102 }
103 return false, 0
104 }
105
106
107
108
109 func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
110 if ok, offset := isSymNameOffset(sym.Name); ok {
111 return st.String(offset)
112 }
113 return cstring(sym.Name[:]), nil
114 }
115
116 func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
117 if len(allsyms) == 0 {
118 return nil, nil
119 }
120 syms := make([]*Symbol, 0)
121 aux := uint8(0)
122 for _, sym := range allsyms {
123 if aux > 0 {
124 aux--
125 continue
126 }
127 name, err := sym.FullName(st)
128 if err != nil {
129 return nil, err
130 }
131 aux = sym.NumberOfAuxSymbols
132 s := &Symbol{
133 Name: name,
134 Value: sym.Value,
135 SectionNumber: sym.SectionNumber,
136 Type: sym.Type,
137 StorageClass: sym.StorageClass,
138 }
139 syms = append(syms, s)
140 }
141 return syms, nil
142 }
143
144
145
146 type Symbol struct {
147 Name string
148 Value uint32
149 SectionNumber int16
150 Type uint16
151 StorageClass uint8
152 }
153
154
155
156
157
158
159
160
161
162 type COFFSymbolAuxFormat5 struct {
163 Size uint32
164 NumRelocs uint16
165 NumLineNumbers uint16
166 Checksum uint32
167 SecNum uint16
168 Selection uint8
169 _ [3]uint8
170 }
171
172
173
174 const (
175 IMAGE_COMDAT_SELECT_NODUPLICATES = 1
176 IMAGE_COMDAT_SELECT_ANY = 2
177 IMAGE_COMDAT_SELECT_SAME_SIZE = 3
178 IMAGE_COMDAT_SELECT_EXACT_MATCH = 4
179 IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5
180 IMAGE_COMDAT_SELECT_LARGEST = 6
181 )
182
183
184
185
186
187
188
189
190
191
192 func (f *File) COFFSymbolReadSectionDefAux(idx int) (*COFFSymbolAuxFormat5, error) {
193 var rv *COFFSymbolAuxFormat5
194 if idx < 0 || idx >= len(f.COFFSymbols) {
195 return rv, fmt.Errorf("invalid symbol index")
196 }
197 pesym := &f.COFFSymbols[idx]
198 const IMAGE_SYM_CLASS_STATIC = 3
199 if pesym.StorageClass != uint8(IMAGE_SYM_CLASS_STATIC) {
200 return rv, fmt.Errorf("incorrect symbol storage class")
201 }
202 if pesym.NumberOfAuxSymbols == 0 || idx+1 >= len(f.COFFSymbols) {
203 return rv, fmt.Errorf("aux symbol unavailable")
204 }
205
206 pesymn := &f.COFFSymbols[idx+1]
207 rv = (*COFFSymbolAuxFormat5)(unsafe.Pointer(pesymn))
208 return rv, nil
209 }
210
View as plain text