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

Subversion Repositories openrisc

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

Go to most recent revision | 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 pe implements access to PE (Microsoft Windows Portable Executable) files.
6
package pe
7
 
8
import (
9
        "debug/dwarf"
10
        "encoding/binary"
11
        "errors"
12
        "fmt"
13
        "io"
14
        "os"
15
        "strconv"
16
)
17
 
18
// A File represents an open PE file.
19
type File struct {
20
        FileHeader
21
        Sections []*Section
22
 
23
        closer io.Closer
24
}
25
 
26
type SectionHeader struct {
27
        Name                 string
28
        VirtualSize          uint32
29
        VirtualAddress       uint32
30
        Size                 uint32
31
        Offset               uint32
32
        PointerToRelocations uint32
33
        PointerToLineNumbers uint32
34
        NumberOfRelocations  uint16
35
        NumberOfLineNumbers  uint16
36
        Characteristics      uint32
37
}
38
 
39
type Section struct {
40
        SectionHeader
41
 
42
        // Embed ReaderAt for ReadAt method.
43
        // Do not embed SectionReader directly
44
        // to avoid having Read and Seek.
45
        // If a client wants Read and Seek it must use
46
        // Open() to avoid fighting over the seek offset
47
        // with other clients.
48
        io.ReaderAt
49
        sr *io.SectionReader
50
}
51
 
52
type ImportDirectory struct {
53
        OriginalFirstThunk uint32
54
        TimeDateStamp      uint32
55
        ForwarderChain     uint32
56
        Name               uint32
57
        FirstThunk         uint32
58
 
59
        dll string
60
}
61
 
62
// Data reads and returns the contents of the PE section.
63
func (s *Section) Data() ([]byte, error) {
64
        dat := make([]byte, s.sr.Size())
65
        n, err := s.sr.ReadAt(dat, 0)
66
        return dat[0:n], err
67
}
68
 
69
// Open returns a new ReadSeeker reading the PE section.
70
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
71
 
72
type FormatError struct {
73
        off int64
74
        msg string
75
        val interface{}
76
}
77
 
78
func (e *FormatError) Error() string {
79
        msg := e.msg
80
        if e.val != nil {
81
                msg += fmt.Sprintf(" '%v'", e.val)
82
        }
83
        msg += fmt.Sprintf(" in record at byte %#x", e.off)
84
        return msg
85
}
86
 
87
// Open opens the named file using os.Open and prepares it for use as a PE binary.
88
func Open(name string) (*File, error) {
89
        f, err := os.Open(name)
90
        if err != nil {
91
                return nil, err
92
        }
93
        ff, err := NewFile(f)
94
        if err != nil {
95
                f.Close()
96
                return nil, err
97
        }
98
        ff.closer = f
99
        return ff, nil
100
}
101
 
102
// Close closes the File.
103
// If the File was created using NewFile directly instead of Open,
104
// Close has no effect.
105
func (f *File) Close() error {
106
        var err error
107
        if f.closer != nil {
108
                err = f.closer.Close()
109
                f.closer = nil
110
        }
111
        return err
112
}
113
 
114
// NewFile creates a new File for accessing a PE binary in an underlying reader.
115
func NewFile(r io.ReaderAt) (*File, error) {
116
        f := new(File)
117
        sr := io.NewSectionReader(r, 0, 1<<63-1)
118
 
119
        var dosheader [96]byte
120
        if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
121
                return nil, err
122
        }
123
        var base int64
124
        if dosheader[0] == 'M' && dosheader[1] == 'Z' {
125
                var sign [4]byte
126
                r.ReadAt(sign[0:], int64(dosheader[0x3c]))
127
                if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
128
                        return nil, errors.New("Invalid PE File Format.")
129
                }
130
                base = int64(dosheader[0x3c]) + 4
131
        } else {
132
                base = int64(0)
133
        }
134
        sr.Seek(base, os.SEEK_SET)
135
        if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
136
                return nil, err
137
        }
138
        if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
139
                return nil, errors.New("Invalid PE File Format.")
140
        }
141
        // get symbol string table
142
        sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
143
        var l uint32
144
        if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
145
                return nil, err
146
        }
147
        ss := make([]byte, l)
148
        if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
149
                return nil, err
150
        }
151
        sr.Seek(base, os.SEEK_SET)
152
        binary.Read(sr, binary.LittleEndian, &f.FileHeader)
153
        sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
154
        f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
155
        for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
156
                sh := new(SectionHeader32)
157
                if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
158
                        return nil, err
159
                }
160
                var name string
161
                if sh.Name[0] == '\x2F' {
162
                        si, _ := strconv.Atoi(cstring(sh.Name[1:]))
163
                        name, _ = getString(ss, si)
164
                } else {
165
                        name = cstring(sh.Name[0:])
166
                }
167
                s := new(Section)
168
                s.SectionHeader = SectionHeader{
169
                        Name:                 name,
170
                        VirtualSize:          uint32(sh.VirtualSize),
171
                        VirtualAddress:       uint32(sh.VirtualAddress),
172
                        Size:                 uint32(sh.SizeOfRawData),
173
                        Offset:               uint32(sh.PointerToRawData),
174
                        PointerToRelocations: uint32(sh.PointerToRelocations),
175
                        PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
176
                        NumberOfRelocations:  uint16(sh.NumberOfRelocations),
177
                        NumberOfLineNumbers:  uint16(sh.NumberOfLineNumbers),
178
                        Characteristics:      uint32(sh.Characteristics),
179
                }
180
                s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
181
                s.ReaderAt = s.sr
182
                f.Sections[i] = s
183
        }
184
        return f, nil
185
}
186
 
187
func cstring(b []byte) string {
188
        var i int
189
        for i = 0; i < len(b) && b[i] != 0; i++ {
190
        }
191
        return string(b[0:i])
192
}
193
 
194
// getString extracts a string from symbol string table.
195
func getString(section []byte, start int) (string, bool) {
196
        if start < 0 || start >= len(section) {
197
                return "", false
198
        }
199
 
200
        for end := start; end < len(section); end++ {
201
                if section[end] == 0 {
202
                        return string(section[start:end]), true
203
                }
204
        }
205
        return "", false
206
}
207
 
208
// Section returns the first section with the given name, or nil if no such
209
// section exists.
210
func (f *File) Section(name string) *Section {
211
        for _, s := range f.Sections {
212
                if s.Name == name {
213
                        return s
214
                }
215
        }
216
        return nil
217
}
218
 
219
func (f *File) DWARF() (*dwarf.Data, error) {
220
        // There are many other DWARF sections, but these
221
        // are the required ones, and the debug/dwarf package
222
        // does not use the others, so don't bother loading them.
223
        var names = [...]string{"abbrev", "info", "str"}
224
        var dat [len(names)][]byte
225
        for i, name := range names {
226
                name = ".debug_" + name
227
                s := f.Section(name)
228
                if s == nil {
229
                        continue
230
                }
231
                b, err := s.Data()
232
                if err != nil && uint32(len(b)) < s.Size {
233
                        return nil, err
234
                }
235
                dat[i] = b
236
        }
237
 
238
        abbrev, info, str := dat[0], dat[1], dat[2]
239
        return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
240
}
241
 
242
// ImportedSymbols returns the names of all symbols
243
// referred to by the binary f that are expected to be
244
// satisfied by other libraries at dynamic load time.
245
// It does not return weak symbols.
246
func (f *File) ImportedSymbols() ([]string, error) {
247
        pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
248
        ds := f.Section(".idata")
249
        if ds == nil {
250
                // not dynamic, so no libraries
251
                return nil, nil
252
        }
253
        d, err := ds.Data()
254
        if err != nil {
255
                return nil, err
256
        }
257
        var ida []ImportDirectory
258
        for len(d) > 0 {
259
                var dt ImportDirectory
260
                dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
261
                dt.Name = binary.LittleEndian.Uint32(d[12:16])
262
                dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
263
                d = d[20:]
264
                if dt.OriginalFirstThunk == 0 {
265
                        break
266
                }
267
                ida = append(ida, dt)
268
        }
269
        names, _ := ds.Data()
270
        var all []string
271
        for _, dt := range ida {
272
                dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
273
                d, _ = ds.Data()
274
                // seek to OriginalFirstThunk
275
                d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
276
                for len(d) > 0 {
277
                        if pe64 { // 64bit
278
                                va := binary.LittleEndian.Uint64(d[0:8])
279
                                d = d[8:]
280
                                if va == 0 {
281
                                        break
282
                                }
283
                                if va&0x8000000000000000 > 0 { // is Ordinal
284
                                        // TODO add dynimport ordinal support.
285
                                } else {
286
                                        fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
287
                                        all = append(all, fn+":"+dt.dll)
288
                                }
289
                        } else { // 32bit
290
                                va := binary.LittleEndian.Uint32(d[0:4])
291
                                d = d[4:]
292
                                if va == 0 {
293
                                        break
294
                                }
295
                                if va&0x80000000 > 0 { // is Ordinal
296
                                        // TODO add dynimport ordinal support.
297
                                        //ord := va&0x0000FFFF
298
                                } else {
299
                                        fn, _ := getString(names, int(va-ds.VirtualAddress+2))
300
                                        all = append(all, fn+":"+dt.dll)
301
                                }
302
                        }
303
                }
304
        }
305
 
306
        return all, nil
307
}
308
 
309
// ImportedLibraries returns the names of all libraries
310
// referred to by the binary f that are expected to be
311
// linked with the binary at dynamic link time.
312
func (f *File) ImportedLibraries() ([]string, error) {
313
        // TODO
314
        // cgo -dynimport don't use this for windows PE, so just return.
315
        return nil, nil
316
}

powered by: WebSVN 2.1.0

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