Source file src/pkg/cmd/go/internal/version/exe.go
1
2
3
4
5 package version
6
7 import (
8 "bytes"
9 "debug/elf"
10 "debug/macho"
11 "debug/pe"
12 "fmt"
13 "internal/xcoff"
14 "io"
15 "os"
16 )
17
18
19 type exe interface {
20
21 Close() error
22
23
24 ReadData(addr, size uint64) ([]byte, error)
25
26
27 DataStart() uint64
28 }
29
30
31 func openExe(file string) (exe, error) {
32 f, err := os.Open(file)
33 if err != nil {
34 return nil, err
35 }
36 data := make([]byte, 16)
37 if _, err := io.ReadFull(f, data); err != nil {
38 return nil, err
39 }
40 f.Seek(0, 0)
41 if bytes.HasPrefix(data, []byte("\x7FELF")) {
42 e, err := elf.NewFile(f)
43 if err != nil {
44 f.Close()
45 return nil, err
46 }
47 return &elfExe{f, e}, nil
48 }
49 if bytes.HasPrefix(data, []byte("MZ")) {
50 e, err := pe.NewFile(f)
51 if err != nil {
52 f.Close()
53 return nil, err
54 }
55 return &peExe{f, e}, nil
56 }
57 if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) {
58 e, err := macho.NewFile(f)
59 if err != nil {
60 f.Close()
61 return nil, err
62 }
63 return &machoExe{f, e}, nil
64 }
65 if bytes.HasPrefix(data, []byte{0x01, 0xDF}) || bytes.HasPrefix(data, []byte{0x01, 0xF7}) {
66 e, err := xcoff.NewFile(f)
67 if err != nil {
68 f.Close()
69 return nil, err
70 }
71 return &xcoffExe{f, e}, nil
72
73 }
74 return nil, fmt.Errorf("unrecognized executable format")
75 }
76
77
78 type elfExe struct {
79 os *os.File
80 f *elf.File
81 }
82
83 func (x *elfExe) Close() error {
84 return x.os.Close()
85 }
86
87 func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
88 for _, prog := range x.f.Progs {
89 if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
90 n := prog.Vaddr + prog.Filesz - addr
91 if n > size {
92 n = size
93 }
94 data := make([]byte, n)
95 _, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
96 if err != nil {
97 return nil, err
98 }
99 return data, nil
100 }
101 }
102 return nil, fmt.Errorf("address not mapped")
103 }
104
105 func (x *elfExe) DataStart() uint64 {
106 for _, s := range x.f.Sections {
107 if s.Name == ".go.buildinfo" {
108 return s.Addr
109 }
110 }
111 for _, p := range x.f.Progs {
112 if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {
113 return p.Vaddr
114 }
115 }
116 return 0
117 }
118
119
120 type peExe struct {
121 os *os.File
122 f *pe.File
123 }
124
125 func (x *peExe) Close() error {
126 return x.os.Close()
127 }
128
129 func (x *peExe) imageBase() uint64 {
130 switch oh := x.f.OptionalHeader.(type) {
131 case *pe.OptionalHeader32:
132 return uint64(oh.ImageBase)
133 case *pe.OptionalHeader64:
134 return oh.ImageBase
135 }
136 return 0
137 }
138
139 func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
140 addr -= x.imageBase()
141 for _, sect := range x.f.Sections {
142 if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
143 n := uint64(sect.VirtualAddress+sect.Size) - addr
144 if n > size {
145 n = size
146 }
147 data := make([]byte, n)
148 _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
149 if err != nil {
150 return nil, err
151 }
152 return data, nil
153 }
154 }
155 return nil, fmt.Errorf("address not mapped")
156 }
157
158 func (x *peExe) DataStart() uint64 {
159
160 const (
161 IMAGE_SCN_CNT_CODE = 0x00000020
162 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
163 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
164 IMAGE_SCN_MEM_EXECUTE = 0x20000000
165 IMAGE_SCN_MEM_READ = 0x40000000
166 IMAGE_SCN_MEM_WRITE = 0x80000000
167 IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
168 IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
169 IMAGE_SCN_ALIGN_32BYTES = 0x600000
170 )
171 for _, sect := range x.f.Sections {
172 if sect.VirtualAddress != 0 && sect.Size != 0 &&
173 sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE {
174 return uint64(sect.VirtualAddress) + x.imageBase()
175 }
176 }
177 return 0
178 }
179
180
181 type machoExe struct {
182 os *os.File
183 f *macho.File
184 }
185
186 func (x *machoExe) Close() error {
187 return x.os.Close()
188 }
189
190 func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
191 for _, load := range x.f.Loads {
192 seg, ok := load.(*macho.Segment)
193 if !ok {
194 continue
195 }
196 if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 {
197 if seg.Name == "__PAGEZERO" {
198 continue
199 }
200 n := seg.Addr + seg.Filesz - addr
201 if n > size {
202 n = size
203 }
204 data := make([]byte, n)
205 _, err := seg.ReadAt(data, int64(addr-seg.Addr))
206 if err != nil {
207 return nil, err
208 }
209 return data, nil
210 }
211 }
212 return nil, fmt.Errorf("address not mapped")
213 }
214
215 func (x *machoExe) DataStart() uint64 {
216
217 for _, sec := range x.f.Sections {
218 if sec.Name == "__go_buildinfo" {
219 return sec.Addr
220 }
221 }
222
223 const RW = 3
224 for _, load := range x.f.Loads {
225 seg, ok := load.(*macho.Segment)
226 if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW {
227 return seg.Addr
228 }
229 }
230 return 0
231 }
232
233
234 type xcoffExe struct {
235 os *os.File
236 f *xcoff.File
237 }
238
239 func (x *xcoffExe) Close() error {
240 return x.os.Close()
241 }
242
243 func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) {
244 for _, sect := range x.f.Sections {
245 if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) {
246 n := uint64(sect.VirtualAddress+sect.Size) - addr
247 if n > size {
248 n = size
249 }
250 data := make([]byte, n)
251 _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
252 if err != nil {
253 return nil, err
254 }
255 return data, nil
256 }
257 }
258 return nil, fmt.Errorf("address not mapped")
259 }
260
261 func (x *xcoffExe) DataStart() uint64 {
262 return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress
263 }
264
View as plain text