|
@@ -18,7 +18,9 @@ package binutils
|
18
|
18
|
import (
|
19
|
19
|
"debug/elf"
|
20
|
20
|
"debug/macho"
|
|
21
|
+ "encoding/binary"
|
21
|
22
|
"fmt"
|
|
23
|
+ "io"
|
22
|
24
|
"os"
|
23
|
25
|
"os/exec"
|
24
|
26
|
"path/filepath"
|
|
@@ -173,12 +175,8 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi
|
173
|
175
|
b := bu.get()
|
174
|
176
|
|
175
|
177
|
// Make sure file is a supported executable.
|
176
|
|
- // The pprof driver uses Open to sniff the difference
|
177
|
|
- // between an executable and a profile.
|
178
|
|
- // For now, only ELF is supported.
|
179
|
|
- // Could read the first few bytes of the file and
|
180
|
|
- // use a table of prefixes if we need to support other
|
181
|
|
- // systems at some point.
|
|
178
|
+ // This uses magic numbers, mainly to provide better error messages but
|
|
179
|
+ // it should also help speed.
|
182
|
180
|
|
183
|
181
|
if _, err := os.Stat(name); err != nil {
|
184
|
182
|
// For testing, do not require file name to exist.
|
|
@@ -188,13 +186,48 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi
|
188
|
186
|
return nil, err
|
189
|
187
|
}
|
190
|
188
|
|
191
|
|
- if f, err := b.openELF(name, start, limit, offset); err == nil {
|
|
189
|
+ // Read the first 4 bytes of the file.
|
|
190
|
+
|
|
191
|
+ f, err := os.Open(name)
|
|
192
|
+ if err != nil {
|
|
193
|
+ return nil, fmt.Errorf("error opening %s: %s", name, err)
|
|
194
|
+ }
|
|
195
|
+ defer f.Close()
|
|
196
|
+
|
|
197
|
+ var header [4]byte
|
|
198
|
+ if _, err = io.ReadFull(f, header[:]); err != nil {
|
|
199
|
+ return nil, fmt.Errorf("error reading magic number from %s: %s", name, err)
|
|
200
|
+ }
|
|
201
|
+
|
|
202
|
+ elfMagic := string(header[:])
|
|
203
|
+
|
|
204
|
+ // Match against supported file types.
|
|
205
|
+ if elfMagic == elf.ELFMAG {
|
|
206
|
+ f, err := b.openELF(name, start, limit, offset)
|
|
207
|
+ if err != nil {
|
|
208
|
+ return nil, fmt.Errorf("error reading ELF file %s: %s", name, err)
|
|
209
|
+ }
|
192
|
210
|
return f, nil
|
193
|
211
|
}
|
194
|
|
- if f, err := b.openMachO(name, start, limit, offset); err == nil {
|
|
212
|
+
|
|
213
|
+ // Mach-O magic numbers can be big or little endian.
|
|
214
|
+ machoMagicLittle := binary.LittleEndian.Uint32(header[:])
|
|
215
|
+ machoMagicBig := binary.BigEndian.Uint32(header[:])
|
|
216
|
+
|
|
217
|
+ if machoMagicLittle == macho.Magic32 || machoMagicLittle == macho.Magic64 ||
|
|
218
|
+ machoMagicBig == macho.Magic32 || machoMagicBig == macho.Magic64 {
|
|
219
|
+ f, err := b.openMachO(name, start, limit, offset)
|
|
220
|
+ if err != nil {
|
|
221
|
+ return nil, fmt.Errorf("error reading Mach-O file %s: %s", name, err)
|
|
222
|
+ }
|
195
|
223
|
return f, nil
|
196
|
224
|
}
|
197
|
|
- return nil, fmt.Errorf("unrecognized binary: %s", name)
|
|
225
|
+ if machoMagicLittle == macho.MagicFat || machoMagicBig == macho.MagicFat {
|
|
226
|
+ // TODO: #1033
|
|
227
|
+ return nil, fmt.Errorf("fat Mach-O archives are currently unsupported")
|
|
228
|
+ }
|
|
229
|
+
|
|
230
|
+ return nil, fmt.Errorf("unrecognized binary format: %s", name)
|
198
|
231
|
}
|
199
|
232
|
|
200
|
233
|
func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
|