OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [debug/] [macho/] [file.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors.  All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
// Package macho implements access to Mach-O object files, as defined by
6
// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.
7
package macho
8
 
9
// High level access to low level data structures.
10
 
11
import (
12
        "bytes"
13
        "debug/dwarf"
14
        "encoding/binary"
15
        "errors"
16
        "fmt"
17
        "io"
18
        "os"
19
)
20
 
21
// A File represents an open Mach-O file.
22
type File struct {
23
        FileHeader
24
        ByteOrder binary.ByteOrder
25
        Loads     []Load
26
        Sections  []*Section
27
 
28
        Symtab   *Symtab
29
        Dysymtab *Dysymtab
30
 
31
        closer io.Closer
32
}
33
 
34
// A Load represents any Mach-O load command.
35
type Load interface {
36
        Raw() []byte
37
}
38
 
39
// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
40
type LoadBytes []byte
41
 
42
func (b LoadBytes) Raw() []byte { return b }
43
 
44
// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
45
type SegmentHeader struct {
46
        Cmd     LoadCmd
47
        Len     uint32
48
        Name    string
49
        Addr    uint64
50
        Memsz   uint64
51
        Offset  uint64
52
        Filesz  uint64
53
        Maxprot uint32
54
        Prot    uint32
55
        Nsect   uint32
56
        Flag    uint32
57
}
58
 
59
// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
60
type Segment struct {
61
        LoadBytes
62
        SegmentHeader
63
 
64
        // Embed ReaderAt for ReadAt method.
65
        // Do not embed SectionReader directly
66
        // to avoid having Read and Seek.
67
        // If a client wants Read and Seek it must use
68
        // Open() to avoid fighting over the seek offset
69
        // with other clients.
70
        io.ReaderAt
71
        sr *io.SectionReader
72
}
73
 
74
// Data reads and returns the contents of the segment.
75
func (s *Segment) Data() ([]byte, error) {
76
        dat := make([]byte, s.sr.Size())
77
        n, err := s.sr.ReadAt(dat, 0)
78
        return dat[0:n], err
79
}
80
 
81
// Open returns a new ReadSeeker reading the segment.
82
func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
83
 
84
type SectionHeader struct {
85
        Name   string
86
        Seg    string
87
        Addr   uint64
88
        Size   uint64
89
        Offset uint32
90
        Align  uint32
91
        Reloff uint32
92
        Nreloc uint32
93
        Flags  uint32
94
}
95
 
96
type Section struct {
97
        SectionHeader
98
 
99
        // Embed ReaderAt for ReadAt method.
100
        // Do not embed SectionReader directly
101
        // to avoid having Read and Seek.
102
        // If a client wants Read and Seek it must use
103
        // Open() to avoid fighting over the seek offset
104
        // with other clients.
105
        io.ReaderAt
106
        sr *io.SectionReader
107
}
108
 
109
// Data reads and returns the contents of the Mach-O section.
110
func (s *Section) Data() ([]byte, error) {
111
        dat := make([]byte, s.sr.Size())
112
        n, err := s.sr.ReadAt(dat, 0)
113
        return dat[0:n], err
114
}
115
 
116
// Open returns a new ReadSeeker reading the Mach-O section.
117
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
118
 
119
// A Dylib represents a Mach-O load dynamic library command.
120
type Dylib struct {
121
        LoadBytes
122
        Name           string
123
        Time           uint32
124
        CurrentVersion uint32
125
        CompatVersion  uint32
126
}
127
 
128
// A Symtab represents a Mach-O symbol table command.
129
type Symtab struct {
130
        LoadBytes
131
        SymtabCmd
132
        Syms []Symbol
133
}
134
 
135
// A Dysymtab represents a Mach-O dynamic symbol table command.
136
type Dysymtab struct {
137
        LoadBytes
138
        DysymtabCmd
139
        IndirectSyms []uint32 // indices into Symtab.Syms
140
}
141
 
142
/*
143
 * Mach-O reader
144
 */
145
 
146
type FormatError struct {
147
        off int64
148
        msg string
149
        val interface{}
150
}
151
 
152
func (e *FormatError) Error() string {
153
        msg := e.msg
154
        if e.val != nil {
155
                msg += fmt.Sprintf(" '%v'", e.val)
156
        }
157
        msg += fmt.Sprintf(" in record at byte %#x", e.off)
158
        return msg
159
}
160
 
161
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
162
func Open(name string) (*File, error) {
163
        f, err := os.Open(name)
164
        if err != nil {
165
                return nil, err
166
        }
167
        ff, err := NewFile(f)
168
        if err != nil {
169
                f.Close()
170
                return nil, err
171
        }
172
        ff.closer = f
173
        return ff, nil
174
}
175
 
176
// Close closes the File.
177
// If the File was created using NewFile directly instead of Open,
178
// Close has no effect.
179
func (f *File) Close() error {
180
        var err error
181
        if f.closer != nil {
182
                err = f.closer.Close()
183
                f.closer = nil
184
        }
185
        return err
186
}
187
 
188
// NewFile creates a new File for accessing a Mach-O binary in an underlying reader.
189
// The Mach-O binary is expected to start at position 0 in the ReaderAt.
190
func NewFile(r io.ReaderAt) (*File, error) {
191
        f := new(File)
192
        sr := io.NewSectionReader(r, 0, 1<<63-1)
193
 
194
        // Read and decode Mach magic to determine byte order, size.
195
        // Magic32 and Magic64 differ only in the bottom bit.
196
        var ident [4]byte
197
        if _, err := r.ReadAt(ident[0:], 0); err != nil {
198
                return nil, err
199
        }
200
        be := binary.BigEndian.Uint32(ident[0:])
201
        le := binary.LittleEndian.Uint32(ident[0:])
202
        switch Magic32 &^ 1 {
203
        case be &^ 1:
204
                f.ByteOrder = binary.BigEndian
205
                f.Magic = be
206
        case le &^ 1:
207
                f.ByteOrder = binary.LittleEndian
208
                f.Magic = le
209
        default:
210
                return nil, &FormatError{0, "invalid magic number", nil}
211
        }
212
 
213
        // Read entire file header.
214
        if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
215
                return nil, err
216
        }
217
 
218
        // Then load commands.
219
        offset := int64(fileHeaderSize32)
220
        if f.Magic == Magic64 {
221
                offset = fileHeaderSize64
222
        }
223
        dat := make([]byte, f.Cmdsz)
224
        if _, err := r.ReadAt(dat, offset); err != nil {
225
                return nil, err
226
        }
227
        f.Loads = make([]Load, f.Ncmd)
228
        bo := f.ByteOrder
229
        for i := range f.Loads {
230
                // Each load command begins with uint32 command and length.
231
                if len(dat) < 8 {
232
                        return nil, &FormatError{offset, "command block too small", nil}
233
                }
234
                cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
235
                if siz < 8 || siz > uint32(len(dat)) {
236
                        return nil, &FormatError{offset, "invalid command block size", nil}
237
                }
238
                var cmddat []byte
239
                cmddat, dat = dat[0:siz], dat[siz:]
240
                offset += int64(siz)
241
                var s *Segment
242
                switch cmd {
243
                default:
244
                        f.Loads[i] = LoadBytes(cmddat)
245
 
246
                case LoadCmdDylib:
247
                        var hdr DylibCmd
248
                        b := bytes.NewBuffer(cmddat)
249
                        if err := binary.Read(b, bo, &hdr); err != nil {
250
                                return nil, err
251
                        }
252
                        l := new(Dylib)
253
                        if hdr.Name >= uint32(len(cmddat)) {
254
                                return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
255
                        }
256
                        l.Name = cstring(cmddat[hdr.Name:])
257
                        l.Time = hdr.Time
258
                        l.CurrentVersion = hdr.CurrentVersion
259
                        l.CompatVersion = hdr.CompatVersion
260
                        l.LoadBytes = LoadBytes(cmddat)
261
                        f.Loads[i] = l
262
 
263
                case LoadCmdSymtab:
264
                        var hdr SymtabCmd
265
                        b := bytes.NewBuffer(cmddat)
266
                        if err := binary.Read(b, bo, &hdr); err != nil {
267
                                return nil, err
268
                        }
269
                        strtab := make([]byte, hdr.Strsize)
270
                        if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
271
                                return nil, err
272
                        }
273
                        var symsz int
274
                        if f.Magic == Magic64 {
275
                                symsz = 16
276
                        } else {
277
                                symsz = 12
278
                        }
279
                        symdat := make([]byte, int(hdr.Nsyms)*symsz)
280
                        if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
281
                                return nil, err
282
                        }
283
                        st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
284
                        if err != nil {
285
                                return nil, err
286
                        }
287
                        f.Loads[i] = st
288
                        f.Symtab = st
289
 
290
                case LoadCmdDysymtab:
291
                        var hdr DysymtabCmd
292
                        b := bytes.NewBuffer(cmddat)
293
                        if err := binary.Read(b, bo, &hdr); err != nil {
294
                                return nil, err
295
                        }
296
                        dat := make([]byte, hdr.Nindirectsyms*4)
297
                        if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
298
                                return nil, err
299
                        }
300
                        x := make([]uint32, hdr.Nindirectsyms)
301
                        if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
302
                                return nil, err
303
                        }
304
                        st := new(Dysymtab)
305
                        st.LoadBytes = LoadBytes(cmddat)
306
                        st.DysymtabCmd = hdr
307
                        st.IndirectSyms = x
308
                        f.Loads[i] = st
309
                        f.Dysymtab = st
310
 
311
                case LoadCmdSegment:
312
                        var seg32 Segment32
313
                        b := bytes.NewBuffer(cmddat)
314
                        if err := binary.Read(b, bo, &seg32); err != nil {
315
                                return nil, err
316
                        }
317
                        s = new(Segment)
318
                        s.LoadBytes = cmddat
319
                        s.Cmd = cmd
320
                        s.Len = siz
321
                        s.Name = cstring(seg32.Name[0:])
322
                        s.Addr = uint64(seg32.Addr)
323
                        s.Memsz = uint64(seg32.Memsz)
324
                        s.Offset = uint64(seg32.Offset)
325
                        s.Filesz = uint64(seg32.Filesz)
326
                        s.Maxprot = seg32.Maxprot
327
                        s.Prot = seg32.Prot
328
                        s.Nsect = seg32.Nsect
329
                        s.Flag = seg32.Flag
330
                        f.Loads[i] = s
331
                        for i := 0; i < int(s.Nsect); i++ {
332
                                var sh32 Section32
333
                                if err := binary.Read(b, bo, &sh32); err != nil {
334
                                        return nil, err
335
                                }
336
                                sh := new(Section)
337
                                sh.Name = cstring(sh32.Name[0:])
338
                                sh.Seg = cstring(sh32.Seg[0:])
339
                                sh.Addr = uint64(sh32.Addr)
340
                                sh.Size = uint64(sh32.Size)
341
                                sh.Offset = sh32.Offset
342
                                sh.Align = sh32.Align
343
                                sh.Reloff = sh32.Reloff
344
                                sh.Nreloc = sh32.Nreloc
345
                                sh.Flags = sh32.Flags
346
                                f.pushSection(sh, r)
347
                        }
348
 
349
                case LoadCmdSegment64:
350
                        var seg64 Segment64
351
                        b := bytes.NewBuffer(cmddat)
352
                        if err := binary.Read(b, bo, &seg64); err != nil {
353
                                return nil, err
354
                        }
355
                        s = new(Segment)
356
                        s.LoadBytes = cmddat
357
                        s.Cmd = cmd
358
                        s.Len = siz
359
                        s.Name = cstring(seg64.Name[0:])
360
                        s.Addr = seg64.Addr
361
                        s.Memsz = seg64.Memsz
362
                        s.Offset = seg64.Offset
363
                        s.Filesz = seg64.Filesz
364
                        s.Maxprot = seg64.Maxprot
365
                        s.Prot = seg64.Prot
366
                        s.Nsect = seg64.Nsect
367
                        s.Flag = seg64.Flag
368
                        f.Loads[i] = s
369
                        for i := 0; i < int(s.Nsect); i++ {
370
                                var sh64 Section64
371
                                if err := binary.Read(b, bo, &sh64); err != nil {
372
                                        return nil, err
373
                                }
374
                                sh := new(Section)
375
                                sh.Name = cstring(sh64.Name[0:])
376
                                sh.Seg = cstring(sh64.Seg[0:])
377
                                sh.Addr = sh64.Addr
378
                                sh.Size = sh64.Size
379
                                sh.Offset = sh64.Offset
380
                                sh.Align = sh64.Align
381
                                sh.Reloff = sh64.Reloff
382
                                sh.Nreloc = sh64.Nreloc
383
                                sh.Flags = sh64.Flags
384
                                f.pushSection(sh, r)
385
                        }
386
                }
387
                if s != nil {
388
                        s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
389
                        s.ReaderAt = s.sr
390
                }
391
        }
392
        return f, nil
393
}
394
 
395
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
396
        bo := f.ByteOrder
397
        symtab := make([]Symbol, hdr.Nsyms)
398
        b := bytes.NewBuffer(symdat)
399
        for i := range symtab {
400
                var n Nlist64
401
                if f.Magic == Magic64 {
402
                        if err := binary.Read(b, bo, &n); err != nil {
403
                                return nil, err
404
                        }
405
                } else {
406
                        var n32 Nlist32
407
                        if err := binary.Read(b, bo, &n32); err != nil {
408
                                return nil, err
409
                        }
410
                        n.Name = n32.Name
411
                        n.Type = n32.Type
412
                        n.Sect = n32.Sect
413
                        n.Desc = n32.Desc
414
                        n.Value = uint64(n32.Value)
415
                }
416
                sym := &symtab[i]
417
                if n.Name >= uint32(len(strtab)) {
418
                        return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
419
                }
420
                sym.Name = cstring(strtab[n.Name:])
421
                sym.Type = n.Type
422
                sym.Sect = n.Sect
423
                sym.Desc = n.Desc
424
                sym.Value = n.Value
425
        }
426
        st := new(Symtab)
427
        st.LoadBytes = LoadBytes(cmddat)
428
        st.Syms = symtab
429
        return st, nil
430
}
431
 
432
func (f *File) pushSection(sh *Section, r io.ReaderAt) {
433
        f.Sections = append(f.Sections, sh)
434
        sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
435
        sh.ReaderAt = sh.sr
436
}
437
 
438
func cstring(b []byte) string {
439
        var i int
440
        for i = 0; i < len(b) && b[i] != 0; i++ {
441
        }
442
        return string(b[0:i])
443
}
444
 
445
// Segment returns the first Segment with the given name, or nil if no such segment exists.
446
func (f *File) Segment(name string) *Segment {
447
        for _, l := range f.Loads {
448
                if s, ok := l.(*Segment); ok && s.Name == name {
449
                        return s
450
                }
451
        }
452
        return nil
453
}
454
 
455
// Section returns the first section with the given name, or nil if no such
456
// section exists.
457
func (f *File) Section(name string) *Section {
458
        for _, s := range f.Sections {
459
                if s.Name == name {
460
                        return s
461
                }
462
        }
463
        return nil
464
}
465
 
466
// DWARF returns the DWARF debug information for the Mach-O file.
467
func (f *File) DWARF() (*dwarf.Data, error) {
468
        // There are many other DWARF sections, but these
469
        // are the required ones, and the debug/dwarf package
470
        // does not use the others, so don't bother loading them.
471
        var names = [...]string{"abbrev", "info", "str"}
472
        var dat [len(names)][]byte
473
        for i, name := range names {
474
                name = "__debug_" + name
475
                s := f.Section(name)
476
                if s == nil {
477
                        return nil, errors.New("missing Mach-O section " + name)
478
                }
479
                b, err := s.Data()
480
                if err != nil && uint64(len(b)) < s.Size {
481
                        return nil, err
482
                }
483
                dat[i] = b
484
        }
485
 
486
        abbrev, info, str := dat[0], dat[1], dat[2]
487
        return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
488
}
489
 
490
// ImportedSymbols returns the names of all symbols
491
// referred to by the binary f that are expected to be
492
// satisfied by other libraries at dynamic load time.
493
func (f *File) ImportedSymbols() ([]string, error) {
494
        if f.Dysymtab == nil || f.Symtab == nil {
495
                return nil, &FormatError{0, "missing symbol table", nil}
496
        }
497
 
498
        st := f.Symtab
499
        dt := f.Dysymtab
500
        var all []string
501
        for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
502
                all = append(all, s.Name)
503
        }
504
        return all, nil
505
}
506
 
507
// ImportedLibraries returns the paths of all libraries
508
// referred to by the binary f that are expected to be
509
// linked with the binary at dynamic link time.
510
func (f *File) ImportedLibraries() ([]string, error) {
511
        var all []string
512
        for _, l := range f.Loads {
513
                if lib, ok := l.(*Dylib); ok {
514
                        all = append(all, lib.Name)
515
                }
516
        }
517
        return all, nil
518
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.