@@ -103,16 +103,16 @@ func (s *Signature) Validate() error {
103
103
}
104
104
105
105
// Matches checks if the signature applies to the stream
106
- func (s * Signature ) Matches (in io. ReaderAt ) (bool , error ) {
106
+ func (s * Signature ) Matches (in * SignatureReadCache ) (bool , error ) {
107
107
if s .Slice .Start > 0 {
108
- _ , err := in .ReadAt ([]byte {}, s .Slice .Start )
108
+ _ , err := in .Reader . ReadAt ([]byte {}, s .Slice .Start )
109
109
// slice start exceeds what we can read - this signature cannot match
110
110
if err != nil {
111
111
return false , nil
112
112
}
113
113
}
114
114
if s .Slice .End > 0 {
115
- _ , err := in .ReadAt ([]byte {}, s .Slice .End )
115
+ _ , err := in .Reader . ReadAt ([]byte {}, s .Slice .End )
116
116
// slice start exceeds what we can read - this signature cannot match
117
117
if err != nil {
118
118
return false , nil
@@ -121,21 +121,27 @@ func (s *Signature) Matches(in io.ReaderAt) (bool, error) {
121
121
122
122
// check the object kind
123
123
if s .Kind != ObjectAny {
124
- head := make ([]byte , 261 )
125
- _ , err := in .ReadAt (head , 0 )
126
- if err == io .EOF {
127
- // cannot read header which means that only Any rules would apply
128
- return false , nil
129
- }
130
- if err != nil {
131
- return false , xerrors .Errorf ("cannot read stream head: %w" , err )
124
+ var head []byte
125
+ if len (in .header ) > 0 {
126
+ head = in .header
127
+ } else {
128
+ head = make ([]byte , 261 )
129
+ _ , err := in .Reader .ReadAt (head , 0 )
130
+ if err == io .EOF {
131
+ // cannot read header which means that only Any rules would apply
132
+ return false , nil
133
+ }
134
+ if err != nil {
135
+ return false , xerrors .Errorf ("cannot read stream head: %w" , err )
136
+ }
137
+ in .header = head
132
138
}
133
139
134
140
matches := false
135
141
switch s .Kind {
136
142
case ObjectELFSymbols , ObjectELFRodata :
137
143
matches = isELF (head )
138
- case ObjectAny :
144
+ default :
139
145
matches = true
140
146
}
141
147
if ! matches {
@@ -172,16 +178,23 @@ func isELF(head []byte) bool {
172
178
}
173
179
174
180
// matchELF matches a signature against an ELF file
175
- func (s * Signature ) matchELFRodata (in io.ReaderAt ) (bool , error ) {
176
- executable , err := elf .NewFile (in )
177
- if err != nil {
178
- return false , xerrors .Errorf ("cannot anaylse ELF file: %w" , err )
179
- }
181
+ func (s * Signature ) matchELFRodata (in * SignatureReadCache ) (bool , error ) {
182
+ var rodata []byte
183
+ if len (in .rodata ) > 0 {
184
+ rodata = in .rodata
185
+ } else {
186
+ executable , err := elf .NewFile (in .Reader )
187
+ if err != nil {
188
+ return false , xerrors .Errorf ("cannot anaylse ELF file: %w" , err )
189
+ }
180
190
181
- rodata , err := ExtractELFRodata (executable )
182
- if err != nil {
183
- return false , err
191
+ rodata , err = ExtractELFRodata (executable )
192
+ if err != nil {
193
+ return false , err
194
+ }
195
+ in .rodata = rodata
184
196
}
197
+
185
198
matches , err := s .matches (rodata )
186
199
if matches || err != nil {
187
200
return matches , err
@@ -191,16 +204,23 @@ func (s *Signature) matchELFRodata(in io.ReaderAt) (bool, error) {
191
204
}
192
205
193
206
// matchELF matches a signature against an ELF file
194
- func (s * Signature ) matchELF (in io.ReaderAt ) (bool , error ) {
195
- executable , err := elf .NewFile (in )
196
- if err != nil {
197
- return false , xerrors .Errorf ("cannot anaylse ELF file: %w" , err )
198
- }
207
+ func (s * Signature ) matchELF (in * SignatureReadCache ) (bool , error ) {
208
+ var symbols []string
209
+ if len (in .symbols ) > 0 {
210
+ symbols = in .symbols
211
+ } else {
212
+ executable , err := elf .NewFile (in .Reader )
213
+ if err != nil {
214
+ return false , xerrors .Errorf ("cannot anaylse ELF file: %w" , err )
215
+ }
199
216
200
- symbols , err := ExtractELFSymbols (executable )
201
- if err != nil {
202
- return false , err
217
+ symbols , err = ExtractELFSymbols (executable )
218
+ if err != nil {
219
+ return false , err
220
+ }
221
+ in .symbols = symbols
203
222
}
223
+
204
224
for _ , sym := range symbols {
205
225
matches , err := s .matches ([]byte (sym ))
206
226
if matches || err != nil {
@@ -213,22 +233,28 @@ func (s *Signature) matchELF(in io.ReaderAt) (bool, error) {
213
233
214
234
// ExtractELFSymbols extracts all ELF symbol names from an ELF binary
215
235
func ExtractELFSymbols (executable * elf.File ) ([]string , error ) {
216
- var symbols []string
217
236
syms , err := executable .Symbols ()
218
237
if err != nil && err != elf .ErrNoSymbols {
219
238
return nil , xerrors .Errorf ("cannot get dynsym section: %w" , err )
220
239
}
221
- for _ , s := range syms {
222
- symbols = append (symbols , s .Name )
223
- }
224
240
225
241
dynsyms , err := executable .DynamicSymbols ()
226
242
if err != nil && err != elf .ErrNoSymbols {
227
243
return nil , xerrors .Errorf ("cannot get dynsym section: %w" , err )
228
244
}
245
+
246
+ symbols := make ([]string , len (syms )+ len (dynsyms ))
247
+ i := 0
248
+ for _ , s := range syms {
249
+ symbols [i ] = s .Name
250
+ i += 1
251
+ }
252
+
229
253
for _ , s := range dynsyms {
230
- symbols = append (symbols , s .Name )
254
+ symbols [i ] = s .Name
255
+ i += 1
231
256
}
257
+
232
258
return symbols , nil
233
259
}
234
260
@@ -247,11 +273,11 @@ func ExtractELFRodata(executable *elf.File) ([]byte, error) {
247
273
}
248
274
249
275
// matchAny matches a signature against a binary file
250
- func (s * Signature ) matchAny (in io. ReaderAt ) (bool , error ) {
276
+ func (s * Signature ) matchAny (in * SignatureReadCache ) (bool , error ) {
251
277
buffer := make ([]byte , 8096 )
252
278
pos := s .Slice .Start
253
279
for {
254
- n , err := in .ReadAt (buffer , pos )
280
+ n , err := in .Reader . ReadAt (buffer , pos )
255
281
sub := buffer [0 :n ]
256
282
pos += int64 (n )
257
283
0 commit comments