blob: 95c0606f8022ee33b39a59a78e185d025a613abb [file] [log] [blame]
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001// Copyright 2009 The Go Authors. All rights reserved.
Brent Austinba3052e2015-04-21 16:08:23 -07002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package elf implements access to ELF object files.
6package elf
7
8import (
9 "bytes"
Dan Willemsen38f2dba2016-07-08 14:54:35 -070010 "compress/zlib"
Brent Austinba3052e2015-04-21 16:08:23 -070011 "debug/dwarf"
12 "encoding/binary"
13 "errors"
14 "fmt"
15 "io"
16 "os"
Dan Willemsen09eb3b12015-09-16 14:34:17 -070017 "strings"
Brent Austinba3052e2015-04-21 16:08:23 -070018)
19
Dan Willemsena3223282018-02-27 19:41:43 -080020// seekStart, seekCurrent, seekEnd are copies of
21// io.SeekStart, io.SeekCurrent, and io.SeekEnd.
22// We can't use the ones from package io because
23// we want this code to build with Go 1.4 during
24// cmd/dist bootstrap.
25const (
26 seekStart int = 0
27 seekCurrent int = 1
28 seekEnd int = 2
29)
30
Brent Austinba3052e2015-04-21 16:08:23 -070031// TODO: error reporting detail
32
33/*
34 * Internal ELF representation
35 */
36
37// A FileHeader represents an ELF file header.
38type FileHeader struct {
39 Class Class
40 Data Data
41 Version Version
42 OSABI OSABI
43 ABIVersion uint8
44 ByteOrder binary.ByteOrder
45 Type Type
46 Machine Machine
47 Entry uint64
48}
49
50// A File represents an open ELF file.
51type File struct {
52 FileHeader
53 Sections []*Section
54 Progs []*Prog
55 closer io.Closer
56 gnuNeed []verneed
57 gnuVersym []byte
58}
59
60// A SectionHeader represents a single ELF section header.
61type SectionHeader struct {
62 Name string
63 Type SectionType
64 Flags SectionFlag
65 Addr uint64
66 Offset uint64
67 Size uint64
68 Link uint32
69 Info uint32
70 Addralign uint64
71 Entsize uint64
Dan Willemsen38f2dba2016-07-08 14:54:35 -070072
73 // FileSize is the size of this section in the file in bytes.
74 // If a section is compressed, FileSize is the size of the
75 // compressed data, while Size (above) is the size of the
76 // uncompressed data.
77 FileSize uint64
Brent Austinba3052e2015-04-21 16:08:23 -070078}
79
80// A Section represents a single section in an ELF file.
81type Section struct {
82 SectionHeader
83
84 // Embed ReaderAt for ReadAt method.
85 // Do not embed SectionReader directly
86 // to avoid having Read and Seek.
87 // If a client wants Read and Seek it must use
88 // Open() to avoid fighting over the seek offset
89 // with other clients.
Dan Willemsen38f2dba2016-07-08 14:54:35 -070090 //
91 // ReaderAt may be nil if the section is not easily available
92 // in a random-access form. For example, a compressed section
93 // may have a nil ReaderAt.
Brent Austinba3052e2015-04-21 16:08:23 -070094 io.ReaderAt
95 sr *io.SectionReader
Dan Willemsen38f2dba2016-07-08 14:54:35 -070096
97 compressionType CompressionType
98 compressionOffset int64
Brent Austinba3052e2015-04-21 16:08:23 -070099}
100
101// Data reads and returns the contents of the ELF section.
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700102// Even if the section is stored compressed in the ELF file,
103// Data returns uncompressed data.
Brent Austinba3052e2015-04-21 16:08:23 -0700104func (s *Section) Data() ([]byte, error) {
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700105 dat := make([]byte, s.Size)
106 n, err := io.ReadFull(s.Open(), dat)
Brent Austinba3052e2015-04-21 16:08:23 -0700107 return dat[0:n], err
108}
109
110// stringTable reads and returns the string table given by the
111// specified link value.
112func (f *File) stringTable(link uint32) ([]byte, error) {
113 if link <= 0 || link >= uint32(len(f.Sections)) {
114 return nil, errors.New("section has invalid string table link")
115 }
116 return f.Sections[link].Data()
117}
118
119// Open returns a new ReadSeeker reading the ELF section.
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700120// Even if the section is stored compressed in the ELF file,
121// the ReadSeeker reads uncompressed data.
122func (s *Section) Open() io.ReadSeeker {
123 if s.Flags&SHF_COMPRESSED == 0 {
124 return io.NewSectionReader(s.sr, 0, 1<<63-1)
125 }
126 if s.compressionType == COMPRESS_ZLIB {
127 return &readSeekerFromReader{
128 reset: func() (io.Reader, error) {
129 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
130 return zlib.NewReader(fr)
131 },
132 size: int64(s.Size),
133 }
134 }
135 err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
136 return errorReader{err}
137}
Brent Austinba3052e2015-04-21 16:08:23 -0700138
139// A ProgHeader represents a single ELF program header.
140type ProgHeader struct {
141 Type ProgType
142 Flags ProgFlag
143 Off uint64
144 Vaddr uint64
145 Paddr uint64
146 Filesz uint64
147 Memsz uint64
148 Align uint64
149}
150
151// A Prog represents a single ELF program header in an ELF binary.
152type Prog struct {
153 ProgHeader
154
155 // Embed ReaderAt for ReadAt method.
156 // Do not embed SectionReader directly
157 // to avoid having Read and Seek.
158 // If a client wants Read and Seek it must use
159 // Open() to avoid fighting over the seek offset
160 // with other clients.
161 io.ReaderAt
162 sr *io.SectionReader
163}
164
165// Open returns a new ReadSeeker reading the ELF program body.
166func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
167
168// A Symbol represents an entry in an ELF symbol table section.
169type Symbol struct {
170 Name string
171 Info, Other byte
172 Section SectionIndex
173 Value, Size uint64
174}
175
176/*
177 * ELF reader
178 */
179
180type FormatError struct {
181 off int64
182 msg string
183 val interface{}
184}
185
186func (e *FormatError) Error() string {
187 msg := e.msg
188 if e.val != nil {
189 msg += fmt.Sprintf(" '%v' ", e.val)
190 }
191 msg += fmt.Sprintf("in record at byte %#x", e.off)
192 return msg
193}
194
195// Open opens the named file using os.Open and prepares it for use as an ELF binary.
196func Open(name string) (*File, error) {
197 f, err := os.Open(name)
198 if err != nil {
199 return nil, err
200 }
201 ff, err := NewFile(f)
202 if err != nil {
203 f.Close()
204 return nil, err
205 }
206 ff.closer = f
207 return ff, nil
208}
209
210// Close closes the File.
211// If the File was created using NewFile directly instead of Open,
212// Close has no effect.
213func (f *File) Close() error {
214 var err error
215 if f.closer != nil {
216 err = f.closer.Close()
217 f.closer = nil
218 }
219 return err
220}
221
222// SectionByType returns the first section in f with the
223// given type, or nil if there is no such section.
224func (f *File) SectionByType(typ SectionType) *Section {
225 for _, s := range f.Sections {
226 if s.Type == typ {
227 return s
228 }
229 }
230 return nil
231}
232
233// NewFile creates a new File for accessing an ELF binary in an underlying reader.
234// The ELF binary is expected to start at position 0 in the ReaderAt.
235func NewFile(r io.ReaderAt) (*File, error) {
236 sr := io.NewSectionReader(r, 0, 1<<63-1)
237 // Read and decode ELF identifier
238 var ident [16]uint8
239 if _, err := r.ReadAt(ident[0:], 0); err != nil {
240 return nil, err
241 }
242 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
243 return nil, &FormatError{0, "bad magic number", ident[0:4]}
244 }
245
246 f := new(File)
247 f.Class = Class(ident[EI_CLASS])
248 switch f.Class {
249 case ELFCLASS32:
250 case ELFCLASS64:
251 // ok
252 default:
253 return nil, &FormatError{0, "unknown ELF class", f.Class}
254 }
255
256 f.Data = Data(ident[EI_DATA])
257 switch f.Data {
258 case ELFDATA2LSB:
259 f.ByteOrder = binary.LittleEndian
260 case ELFDATA2MSB:
261 f.ByteOrder = binary.BigEndian
262 default:
263 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
264 }
265
266 f.Version = Version(ident[EI_VERSION])
267 if f.Version != EV_CURRENT {
268 return nil, &FormatError{0, "unknown ELF version", f.Version}
269 }
270
271 f.OSABI = OSABI(ident[EI_OSABI])
272 f.ABIVersion = ident[EI_ABIVERSION]
273
274 // Read ELF file header
275 var phoff int64
276 var phentsize, phnum int
277 var shoff int64
278 var shentsize, shnum, shstrndx int
279 shstrndx = -1
280 switch f.Class {
281 case ELFCLASS32:
282 hdr := new(Header32)
Dan Willemsena3223282018-02-27 19:41:43 -0800283 sr.Seek(0, seekStart)
Brent Austinba3052e2015-04-21 16:08:23 -0700284 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
285 return nil, err
286 }
287 f.Type = Type(hdr.Type)
288 f.Machine = Machine(hdr.Machine)
289 f.Entry = uint64(hdr.Entry)
290 if v := Version(hdr.Version); v != f.Version {
291 return nil, &FormatError{0, "mismatched ELF version", v}
292 }
293 phoff = int64(hdr.Phoff)
294 phentsize = int(hdr.Phentsize)
295 phnum = int(hdr.Phnum)
296 shoff = int64(hdr.Shoff)
297 shentsize = int(hdr.Shentsize)
298 shnum = int(hdr.Shnum)
299 shstrndx = int(hdr.Shstrndx)
300 case ELFCLASS64:
301 hdr := new(Header64)
Dan Willemsena3223282018-02-27 19:41:43 -0800302 sr.Seek(0, seekStart)
Brent Austinba3052e2015-04-21 16:08:23 -0700303 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
304 return nil, err
305 }
306 f.Type = Type(hdr.Type)
307 f.Machine = Machine(hdr.Machine)
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700308 f.Entry = hdr.Entry
Brent Austinba3052e2015-04-21 16:08:23 -0700309 if v := Version(hdr.Version); v != f.Version {
310 return nil, &FormatError{0, "mismatched ELF version", v}
311 }
312 phoff = int64(hdr.Phoff)
313 phentsize = int(hdr.Phentsize)
314 phnum = int(hdr.Phnum)
315 shoff = int64(hdr.Shoff)
316 shentsize = int(hdr.Shentsize)
317 shnum = int(hdr.Shnum)
318 shstrndx = int(hdr.Shstrndx)
319 }
320
321 if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) {
322 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
323 }
324
325 // Read program headers
326 f.Progs = make([]*Prog, phnum)
327 for i := 0; i < phnum; i++ {
328 off := phoff + int64(i)*int64(phentsize)
Dan Willemsena3223282018-02-27 19:41:43 -0800329 sr.Seek(off, seekStart)
Brent Austinba3052e2015-04-21 16:08:23 -0700330 p := new(Prog)
331 switch f.Class {
332 case ELFCLASS32:
333 ph := new(Prog32)
334 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
335 return nil, err
336 }
337 p.ProgHeader = ProgHeader{
338 Type: ProgType(ph.Type),
339 Flags: ProgFlag(ph.Flags),
340 Off: uint64(ph.Off),
341 Vaddr: uint64(ph.Vaddr),
342 Paddr: uint64(ph.Paddr),
343 Filesz: uint64(ph.Filesz),
344 Memsz: uint64(ph.Memsz),
345 Align: uint64(ph.Align),
346 }
347 case ELFCLASS64:
348 ph := new(Prog64)
349 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
350 return nil, err
351 }
352 p.ProgHeader = ProgHeader{
353 Type: ProgType(ph.Type),
354 Flags: ProgFlag(ph.Flags),
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700355 Off: ph.Off,
356 Vaddr: ph.Vaddr,
357 Paddr: ph.Paddr,
358 Filesz: ph.Filesz,
359 Memsz: ph.Memsz,
360 Align: ph.Align,
Brent Austinba3052e2015-04-21 16:08:23 -0700361 }
362 }
363 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
364 p.ReaderAt = p.sr
365 f.Progs[i] = p
366 }
367
368 // Read section headers
369 f.Sections = make([]*Section, shnum)
370 names := make([]uint32, shnum)
371 for i := 0; i < shnum; i++ {
372 off := shoff + int64(i)*int64(shentsize)
Dan Willemsena3223282018-02-27 19:41:43 -0800373 sr.Seek(off, seekStart)
Brent Austinba3052e2015-04-21 16:08:23 -0700374 s := new(Section)
375 switch f.Class {
376 case ELFCLASS32:
377 sh := new(Section32)
378 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
379 return nil, err
380 }
381 names[i] = sh.Name
382 s.SectionHeader = SectionHeader{
383 Type: SectionType(sh.Type),
384 Flags: SectionFlag(sh.Flags),
385 Addr: uint64(sh.Addr),
386 Offset: uint64(sh.Off),
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700387 FileSize: uint64(sh.Size),
388 Link: sh.Link,
389 Info: sh.Info,
Brent Austinba3052e2015-04-21 16:08:23 -0700390 Addralign: uint64(sh.Addralign),
391 Entsize: uint64(sh.Entsize),
392 }
393 case ELFCLASS64:
394 sh := new(Section64)
395 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
396 return nil, err
397 }
398 names[i] = sh.Name
399 s.SectionHeader = SectionHeader{
400 Type: SectionType(sh.Type),
401 Flags: SectionFlag(sh.Flags),
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700402 Offset: sh.Off,
403 FileSize: sh.Size,
404 Addr: sh.Addr,
405 Link: sh.Link,
406 Info: sh.Info,
407 Addralign: sh.Addralign,
408 Entsize: sh.Entsize,
Brent Austinba3052e2015-04-21 16:08:23 -0700409 }
410 }
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700411 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
412
413 if s.Flags&SHF_COMPRESSED == 0 {
414 s.ReaderAt = s.sr
415 s.Size = s.FileSize
416 } else {
417 // Read the compression header.
418 switch f.Class {
419 case ELFCLASS32:
420 ch := new(Chdr32)
421 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
422 return nil, err
423 }
424 s.compressionType = CompressionType(ch.Type)
425 s.Size = uint64(ch.Size)
426 s.Addralign = uint64(ch.Addralign)
427 s.compressionOffset = int64(binary.Size(ch))
428 case ELFCLASS64:
429 ch := new(Chdr64)
430 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
431 return nil, err
432 }
433 s.compressionType = CompressionType(ch.Type)
434 s.Size = ch.Size
435 s.Addralign = ch.Addralign
436 s.compressionOffset = int64(binary.Size(ch))
437 }
438 }
439
Brent Austinba3052e2015-04-21 16:08:23 -0700440 f.Sections[i] = s
441 }
442
443 if len(f.Sections) == 0 {
444 return f, nil
445 }
446
447 // Load section header string table.
448 shstrtab, err := f.Sections[shstrndx].Data()
449 if err != nil {
450 return nil, err
451 }
452 for i, s := range f.Sections {
453 var ok bool
454 s.Name, ok = getString(shstrtab, int(names[i]))
455 if !ok {
456 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
457 }
458 }
459
460 return f, nil
461}
462
463// getSymbols returns a slice of Symbols from parsing the symbol table
464// with the given type, along with the associated string table.
465func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
466 switch f.Class {
467 case ELFCLASS64:
468 return f.getSymbols64(typ)
469
470 case ELFCLASS32:
471 return f.getSymbols32(typ)
472 }
473
474 return nil, nil, errors.New("not implemented")
475}
476
477// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
478// if there is no such section in the File.
479var ErrNoSymbols = errors.New("no symbol section")
480
481func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
482 symtabSection := f.SectionByType(typ)
483 if symtabSection == nil {
484 return nil, nil, ErrNoSymbols
485 }
486
487 data, err := symtabSection.Data()
488 if err != nil {
489 return nil, nil, errors.New("cannot load symbol section")
490 }
491 symtab := bytes.NewReader(data)
492 if symtab.Len()%Sym32Size != 0 {
493 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
494 }
495
496 strdata, err := f.stringTable(symtabSection.Link)
497 if err != nil {
498 return nil, nil, errors.New("cannot load string table section")
499 }
500
501 // The first entry is all zeros.
502 var skip [Sym32Size]byte
503 symtab.Read(skip[:])
504
505 symbols := make([]Symbol, symtab.Len()/Sym32Size)
506
507 i := 0
508 var sym Sym32
509 for symtab.Len() > 0 {
510 binary.Read(symtab, f.ByteOrder, &sym)
511 str, _ := getString(strdata, int(sym.Name))
512 symbols[i].Name = str
513 symbols[i].Info = sym.Info
514 symbols[i].Other = sym.Other
515 symbols[i].Section = SectionIndex(sym.Shndx)
516 symbols[i].Value = uint64(sym.Value)
517 symbols[i].Size = uint64(sym.Size)
518 i++
519 }
520
521 return symbols, strdata, nil
522}
523
524func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
525 symtabSection := f.SectionByType(typ)
526 if symtabSection == nil {
527 return nil, nil, ErrNoSymbols
528 }
529
530 data, err := symtabSection.Data()
531 if err != nil {
532 return nil, nil, errors.New("cannot load symbol section")
533 }
534 symtab := bytes.NewReader(data)
535 if symtab.Len()%Sym64Size != 0 {
536 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
537 }
538
539 strdata, err := f.stringTable(symtabSection.Link)
540 if err != nil {
541 return nil, nil, errors.New("cannot load string table section")
542 }
543
544 // The first entry is all zeros.
545 var skip [Sym64Size]byte
546 symtab.Read(skip[:])
547
548 symbols := make([]Symbol, symtab.Len()/Sym64Size)
549
550 i := 0
551 var sym Sym64
552 for symtab.Len() > 0 {
553 binary.Read(symtab, f.ByteOrder, &sym)
554 str, _ := getString(strdata, int(sym.Name))
555 symbols[i].Name = str
556 symbols[i].Info = sym.Info
557 symbols[i].Other = sym.Other
558 symbols[i].Section = SectionIndex(sym.Shndx)
559 symbols[i].Value = sym.Value
560 symbols[i].Size = sym.Size
561 i++
562 }
563
564 return symbols, strdata, nil
565}
566
567// getString extracts a string from an ELF string table.
568func getString(section []byte, start int) (string, bool) {
569 if start < 0 || start >= len(section) {
570 return "", false
571 }
572
573 for end := start; end < len(section); end++ {
574 if section[end] == 0 {
575 return string(section[start:end]), true
576 }
577 }
578 return "", false
579}
580
581// Section returns a section with the given name, or nil if no such
582// section exists.
583func (f *File) Section(name string) *Section {
584 for _, s := range f.Sections {
585 if s.Name == name {
586 return s
587 }
588 }
589 return nil
590}
591
592// applyRelocations applies relocations to dst. rels is a relocations section
Dan Willemsenebae3022017-01-13 23:01:08 -0800593// in REL or RELA format.
Brent Austinba3052e2015-04-21 16:08:23 -0700594func (f *File) applyRelocations(dst []byte, rels []byte) error {
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700595 switch {
596 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
Brent Austinba3052e2015-04-21 16:08:23 -0700597 return f.applyRelocationsAMD64(dst, rels)
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700598 case f.Class == ELFCLASS32 && f.Machine == EM_386:
Brent Austinba3052e2015-04-21 16:08:23 -0700599 return f.applyRelocations386(dst, rels)
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700600 case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
601 return f.applyRelocationsARM(dst, rels)
602 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
Brent Austinba3052e2015-04-21 16:08:23 -0700603 return f.applyRelocationsARM64(dst, rels)
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700604 case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
605 return f.applyRelocationsPPC(dst, rels)
606 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
607 return f.applyRelocationsPPC64(dst, rels)
Dan Willemsenebae3022017-01-13 23:01:08 -0800608 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
609 return f.applyRelocationsMIPS(dst, rels)
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700610 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
611 return f.applyRelocationsMIPS64(dst, rels)
612 case f.Class == ELFCLASS64 && f.Machine == EM_S390:
613 return f.applyRelocationss390x(dst, rels)
Dan Willemsenebae3022017-01-13 23:01:08 -0800614 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
615 return f.applyRelocationsSPARC64(dst, rels)
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700616 default:
617 return errors.New("applyRelocations: not implemented")
Brent Austinba3052e2015-04-21 16:08:23 -0700618 }
Brent Austinba3052e2015-04-21 16:08:23 -0700619}
620
621func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
622 // 24 is the size of Rela64.
623 if len(rels)%24 != 0 {
624 return errors.New("length of relocation section is not a multiple of 24")
625 }
626
627 symbols, _, err := f.getSymbols(SHT_SYMTAB)
628 if err != nil {
629 return err
630 }
631
632 b := bytes.NewReader(rels)
633 var rela Rela64
634
635 for b.Len() > 0 {
636 binary.Read(b, f.ByteOrder, &rela)
637 symNo := rela.Info >> 32
638 t := R_X86_64(rela.Info & 0xffff)
639
640 if symNo == 0 || symNo > uint64(len(symbols)) {
641 continue
642 }
643 sym := &symbols[symNo-1]
644 if SymType(sym.Info&0xf) != STT_SECTION {
645 // We don't handle non-section relocations for now.
646 continue
647 }
648
649 // There are relocations, so this must be a normal
650 // object file, and we only look at section symbols,
651 // so we assume that the symbol value is 0.
652
653 switch t {
654 case R_X86_64_64:
655 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
656 continue
657 }
658 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
659 case R_X86_64_32:
660 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
661 continue
662 }
663 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
664 }
665 }
666
667 return nil
668}
669
670func (f *File) applyRelocations386(dst []byte, rels []byte) error {
671 // 8 is the size of Rel32.
672 if len(rels)%8 != 0 {
673 return errors.New("length of relocation section is not a multiple of 8")
674 }
675
676 symbols, _, err := f.getSymbols(SHT_SYMTAB)
677 if err != nil {
678 return err
679 }
680
681 b := bytes.NewReader(rels)
682 var rel Rel32
683
684 for b.Len() > 0 {
685 binary.Read(b, f.ByteOrder, &rel)
686 symNo := rel.Info >> 8
687 t := R_386(rel.Info & 0xff)
688
689 if symNo == 0 || symNo > uint32(len(symbols)) {
690 continue
691 }
692 sym := &symbols[symNo-1]
693
694 if t == R_386_32 {
695 if rel.Off+4 >= uint32(len(dst)) {
696 continue
697 }
698 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
699 val += uint32(sym.Value)
700 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
701 }
702 }
703
704 return nil
705}
706
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700707func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
708 // 8 is the size of Rel32.
709 if len(rels)%8 != 0 {
710 return errors.New("length of relocation section is not a multiple of 8")
711 }
712
713 symbols, _, err := f.getSymbols(SHT_SYMTAB)
714 if err != nil {
715 return err
716 }
717
718 b := bytes.NewReader(rels)
719 var rel Rel32
720
721 for b.Len() > 0 {
722 binary.Read(b, f.ByteOrder, &rel)
723 symNo := rel.Info >> 8
724 t := R_ARM(rel.Info & 0xff)
725
726 if symNo == 0 || symNo > uint32(len(symbols)) {
727 continue
728 }
729 sym := &symbols[symNo-1]
730
731 switch t {
732 case R_ARM_ABS32:
733 if rel.Off+4 >= uint32(len(dst)) {
734 continue
735 }
736 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
737 val += uint32(sym.Value)
738 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
739 }
740 }
741
742 return nil
743}
744
Brent Austinba3052e2015-04-21 16:08:23 -0700745func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
746 // 24 is the size of Rela64.
747 if len(rels)%24 != 0 {
748 return errors.New("length of relocation section is not a multiple of 24")
749 }
750
751 symbols, _, err := f.getSymbols(SHT_SYMTAB)
752 if err != nil {
753 return err
754 }
755
756 b := bytes.NewReader(rels)
757 var rela Rela64
758
759 for b.Len() > 0 {
760 binary.Read(b, f.ByteOrder, &rela)
761 symNo := rela.Info >> 32
762 t := R_AARCH64(rela.Info & 0xffff)
763
764 if symNo == 0 || symNo > uint64(len(symbols)) {
765 continue
766 }
767 sym := &symbols[symNo-1]
768 if SymType(sym.Info&0xf) != STT_SECTION {
769 // We don't handle non-section relocations for now.
770 continue
771 }
772
773 // There are relocations, so this must be a normal
774 // object file, and we only look at section symbols,
775 // so we assume that the symbol value is 0.
776
777 switch t {
778 case R_AARCH64_ABS64:
779 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
780 continue
781 }
782 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
783 case R_AARCH64_ABS32:
784 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
785 continue
786 }
787 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
788 }
789 }
790
791 return nil
792}
793
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700794func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
795 // 12 is the size of Rela32.
796 if len(rels)%12 != 0 {
797 return errors.New("length of relocation section is not a multiple of 12")
798 }
799
800 symbols, _, err := f.getSymbols(SHT_SYMTAB)
801 if err != nil {
802 return err
803 }
804
805 b := bytes.NewReader(rels)
806 var rela Rela32
807
808 for b.Len() > 0 {
809 binary.Read(b, f.ByteOrder, &rela)
810 symNo := rela.Info >> 8
811 t := R_PPC(rela.Info & 0xff)
812
813 if symNo == 0 || symNo > uint32(len(symbols)) {
Brent Austinba3052e2015-04-21 16:08:23 -0700814 continue
815 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700816 sym := &symbols[symNo-1]
817 if SymType(sym.Info&0xf) != STT_SECTION {
818 // We don't handle non-section relocations for now.
819 continue
820 }
821
822 switch t {
823 case R_PPC_ADDR32:
824 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
825 continue
826 }
827 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
828 }
829 }
830
831 return nil
832}
833
834func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
835 // 24 is the size of Rela64.
836 if len(rels)%24 != 0 {
837 return errors.New("length of relocation section is not a multiple of 24")
838 }
839
840 symbols, _, err := f.getSymbols(SHT_SYMTAB)
841 if err != nil {
842 return err
843 }
844
845 b := bytes.NewReader(rels)
846 var rela Rela64
847
848 for b.Len() > 0 {
849 binary.Read(b, f.ByteOrder, &rela)
850 symNo := rela.Info >> 32
851 t := R_PPC64(rela.Info & 0xffff)
852
853 if symNo == 0 || symNo > uint64(len(symbols)) {
854 continue
855 }
856 sym := &symbols[symNo-1]
857 if SymType(sym.Info&0xf) != STT_SECTION {
858 // We don't handle non-section relocations for now.
859 continue
860 }
861
862 switch t {
863 case R_PPC64_ADDR64:
864 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
865 continue
866 }
867 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
868 case R_PPC64_ADDR32:
869 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
870 continue
871 }
872 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
873 }
874 }
875
876 return nil
877}
878
Dan Willemsenebae3022017-01-13 23:01:08 -0800879func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
880 // 8 is the size of Rel32.
881 if len(rels)%8 != 0 {
882 return errors.New("length of relocation section is not a multiple of 8")
883 }
884
885 symbols, _, err := f.getSymbols(SHT_SYMTAB)
886 if err != nil {
887 return err
888 }
889
890 b := bytes.NewReader(rels)
891 var rel Rel32
892
893 for b.Len() > 0 {
894 binary.Read(b, f.ByteOrder, &rel)
895 symNo := rel.Info >> 8
896 t := R_MIPS(rel.Info & 0xff)
897
898 if symNo == 0 || symNo > uint32(len(symbols)) {
899 continue
900 }
901 sym := &symbols[symNo-1]
902
903 switch t {
904 case R_MIPS_32:
905 if rel.Off+4 >= uint32(len(dst)) {
906 continue
907 }
908 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
909 val += uint32(sym.Value)
910 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
911 }
912 }
913
914 return nil
915}
916
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700917func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
918 // 24 is the size of Rela64.
919 if len(rels)%24 != 0 {
920 return errors.New("length of relocation section is not a multiple of 24")
921 }
922
923 symbols, _, err := f.getSymbols(SHT_SYMTAB)
924 if err != nil {
925 return err
926 }
927
928 b := bytes.NewReader(rels)
929 var rela Rela64
930
931 for b.Len() > 0 {
932 binary.Read(b, f.ByteOrder, &rela)
933 var symNo uint64
934 var t R_MIPS
935 if f.ByteOrder == binary.BigEndian {
936 symNo = rela.Info >> 32
937 t = R_MIPS(rela.Info & 0xff)
938 } else {
939 symNo = rela.Info & 0xffffffff
940 t = R_MIPS(rela.Info >> 56)
941 }
942
943 if symNo == 0 || symNo > uint64(len(symbols)) {
944 continue
945 }
946 sym := &symbols[symNo-1]
947 if SymType(sym.Info&0xf) != STT_SECTION {
948 // We don't handle non-section relocations for now.
949 continue
950 }
951
952 switch t {
953 case R_MIPS_64:
954 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
955 continue
956 }
957 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
958 case R_MIPS_32:
959 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
960 continue
961 }
962 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
963 }
964 }
965
966 return nil
967}
968
969func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
970 // 24 is the size of Rela64.
971 if len(rels)%24 != 0 {
972 return errors.New("length of relocation section is not a multiple of 24")
973 }
974
975 symbols, _, err := f.getSymbols(SHT_SYMTAB)
976 if err != nil {
977 return err
978 }
979
980 b := bytes.NewReader(rels)
981 var rela Rela64
982
983 for b.Len() > 0 {
984 binary.Read(b, f.ByteOrder, &rela)
985 symNo := rela.Info >> 32
986 t := R_390(rela.Info & 0xffff)
987
988 if symNo == 0 || symNo > uint64(len(symbols)) {
989 continue
990 }
991 sym := &symbols[symNo-1]
992 switch SymType(sym.Info & 0xf) {
993 case STT_SECTION, STT_NOTYPE:
994 break
995 default:
996 continue
997 }
998
999 switch t {
1000 case R_390_64:
1001 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1002 continue
1003 }
1004 val := sym.Value + uint64(rela.Addend)
1005 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
1006 case R_390_32:
1007 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1008 continue
1009 }
1010 val := uint32(sym.Value) + uint32(rela.Addend)
1011 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
1012 }
1013 }
1014
1015 return nil
1016}
1017
Dan Willemsenebae3022017-01-13 23:01:08 -08001018func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1019 // 24 is the size of Rela64.
1020 if len(rels)%24 != 0 {
1021 return errors.New("length of relocation section is not a multiple of 24")
1022 }
1023
1024 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1025 if err != nil {
1026 return err
1027 }
1028
1029 b := bytes.NewReader(rels)
1030 var rela Rela64
1031
1032 for b.Len() > 0 {
1033 binary.Read(b, f.ByteOrder, &rela)
1034 symNo := rela.Info >> 32
1035 t := R_SPARC(rela.Info & 0xff)
1036
1037 if symNo == 0 || symNo > uint64(len(symbols)) {
1038 continue
1039 }
1040 sym := &symbols[symNo-1]
1041 if SymType(sym.Info&0xf) != STT_SECTION {
1042 // We don't handle non-section relocations for now.
1043 continue
1044 }
1045
1046 switch t {
1047 case R_SPARC_64, R_SPARC_UA64:
1048 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1049 continue
1050 }
1051 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
1052 case R_SPARC_32, R_SPARC_UA32:
1053 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1054 continue
1055 }
1056 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
1057 }
1058 }
1059
1060 return nil
1061}
1062
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001063func (f *File) DWARF() (*dwarf.Data, error) {
1064 // sectionData gets the data for s, checks its size, and
1065 // applies any applicable relations.
1066 sectionData := func(i int, s *Section) ([]byte, error) {
Brent Austinba3052e2015-04-21 16:08:23 -07001067 b, err := s.Data()
1068 if err != nil && uint64(len(b)) < s.Size {
1069 return nil, err
1070 }
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001071
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001072 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1073 dlen := binary.BigEndian.Uint64(b[4:12])
1074 dbuf := make([]byte, dlen)
1075 r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1076 if err != nil {
1077 return nil, err
1078 }
1079 if _, err := io.ReadFull(r, dbuf); err != nil {
1080 return nil, err
1081 }
1082 if err := r.Close(); err != nil {
1083 return nil, err
1084 }
1085 b = dbuf
1086 }
1087
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001088 for _, r := range f.Sections {
1089 if r.Type != SHT_RELA && r.Type != SHT_REL {
1090 continue
1091 }
1092 if int(r.Info) != i {
1093 continue
1094 }
1095 rd, err := r.Data()
1096 if err != nil {
1097 return nil, err
1098 }
1099 err = f.applyRelocations(b, rd)
1100 if err != nil {
1101 return nil, err
1102 }
1103 }
1104 return b, nil
Brent Austinba3052e2015-04-21 16:08:23 -07001105 }
1106
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001107 // There are many other DWARF sections, but these
1108 // are the ones the debug/dwarf package uses.
1109 // Don't bother loading others.
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001110 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001111 for i, s := range f.Sections {
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001112 suffix := ""
1113 switch {
1114 case strings.HasPrefix(s.Name, ".debug_"):
1115 suffix = s.Name[7:]
1116 case strings.HasPrefix(s.Name, ".zdebug_"):
1117 suffix = s.Name[8:]
1118 default:
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001119 continue
1120 }
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001121 if _, ok := dat[suffix]; !ok {
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001122 continue
1123 }
1124 b, err := sectionData(i, s)
Brent Austinba3052e2015-04-21 16:08:23 -07001125 if err != nil {
1126 return nil, err
1127 }
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001128 dat[suffix] = b
Brent Austinba3052e2015-04-21 16:08:23 -07001129 }
1130
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001131 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
Brent Austinba3052e2015-04-21 16:08:23 -07001132 if err != nil {
1133 return nil, err
1134 }
1135
1136 // Look for DWARF4 .debug_types sections.
1137 for i, s := range f.Sections {
1138 if s.Name == ".debug_types" {
Dan Willemsen09eb3b12015-09-16 14:34:17 -07001139 b, err := sectionData(i, s)
1140 if err != nil {
Brent Austinba3052e2015-04-21 16:08:23 -07001141 return nil, err
1142 }
1143
Brent Austinba3052e2015-04-21 16:08:23 -07001144 err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
1145 if err != nil {
1146 return nil, err
1147 }
1148 }
1149 }
1150
1151 return d, nil
1152}
1153
1154// Symbols returns the symbol table for f. The symbols will be listed in the order
1155// they appear in f.
1156//
1157// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
1158// After retrieving the symbols as symtab, an externally supplied index x
1159// corresponds to symtab[x-1], not symtab[x].
1160func (f *File) Symbols() ([]Symbol, error) {
1161 sym, _, err := f.getSymbols(SHT_SYMTAB)
1162 return sym, err
1163}
1164
1165// DynamicSymbols returns the dynamic symbol table for f. The symbols
1166// will be listed in the order they appear in f.
1167//
1168// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
1169// After retrieving the symbols as symtab, an externally supplied index x
1170// corresponds to symtab[x-1], not symtab[x].
1171func (f *File) DynamicSymbols() ([]Symbol, error) {
1172 sym, _, err := f.getSymbols(SHT_DYNSYM)
1173 return sym, err
1174}
1175
1176type ImportedSymbol struct {
1177 Name string
1178 Version string
1179 Library string
1180}
1181
1182// ImportedSymbols returns the names of all symbols
1183// referred to by the binary f that are expected to be
1184// satisfied by other libraries at dynamic load time.
1185// It does not return weak symbols.
1186func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1187 sym, str, err := f.getSymbols(SHT_DYNSYM)
1188 if err != nil {
1189 return nil, err
1190 }
1191 f.gnuVersionInit(str)
1192 var all []ImportedSymbol
1193 for i, s := range sym {
1194 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1195 all = append(all, ImportedSymbol{Name: s.Name})
1196 f.gnuVersion(i, &all[len(all)-1])
1197 }
1198 }
1199 return all, nil
1200}
1201
1202type verneed struct {
1203 File string
1204 Name string
1205}
1206
1207// gnuVersionInit parses the GNU version tables
1208// for use by calls to gnuVersion.
1209func (f *File) gnuVersionInit(str []byte) {
1210 // Accumulate verneed information.
1211 vn := f.SectionByType(SHT_GNU_VERNEED)
1212 if vn == nil {
1213 return
1214 }
1215 d, _ := vn.Data()
1216
1217 var need []verneed
1218 i := 0
1219 for {
1220 if i+16 > len(d) {
1221 break
1222 }
1223 vers := f.ByteOrder.Uint16(d[i : i+2])
1224 if vers != 1 {
1225 break
1226 }
1227 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1228 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1229 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1230 next := f.ByteOrder.Uint32(d[i+12 : i+16])
1231 file, _ := getString(str, int(fileoff))
1232
1233 var name string
1234 j := i + int(aux)
1235 for c := 0; c < int(cnt); c++ {
1236 if j+16 > len(d) {
1237 break
1238 }
1239 // hash := f.ByteOrder.Uint32(d[j:j+4])
1240 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
1241 other := f.ByteOrder.Uint16(d[j+6 : j+8])
1242 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1243 next := f.ByteOrder.Uint32(d[j+12 : j+16])
1244 name, _ = getString(str, int(nameoff))
1245 ndx := int(other)
1246 if ndx >= len(need) {
1247 a := make([]verneed, 2*(ndx+1))
1248 copy(a, need)
1249 need = a
1250 }
1251
1252 need[ndx] = verneed{file, name}
1253 if next == 0 {
1254 break
1255 }
1256 j += int(next)
1257 }
1258
1259 if next == 0 {
1260 break
1261 }
1262 i += int(next)
1263 }
1264
1265 // Versym parallels symbol table, indexing into verneed.
1266 vs := f.SectionByType(SHT_GNU_VERSYM)
1267 if vs == nil {
1268 return
1269 }
1270 d, _ = vs.Data()
1271
1272 f.gnuNeed = need
1273 f.gnuVersym = d
1274}
1275
1276// gnuVersion adds Library and Version information to sym,
1277// which came from offset i of the symbol table.
1278func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
1279 // Each entry is two bytes.
1280 i = (i + 1) * 2
1281 if i >= len(f.gnuVersym) {
1282 return
1283 }
1284 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
1285 if j < 2 || j >= len(f.gnuNeed) {
1286 return
1287 }
1288 n := &f.gnuNeed[j]
1289 sym.Library = n.File
1290 sym.Version = n.Name
1291}
1292
1293// ImportedLibraries returns the names of all libraries
1294// referred to by the binary f that are expected to be
1295// linked with the binary at dynamic link time.
1296func (f *File) ImportedLibraries() ([]string, error) {
1297 return f.DynString(DT_NEEDED)
1298}
1299
1300// DynString returns the strings listed for the given tag in the file's dynamic
1301// section.
1302//
1303// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
1304// DT_RUNPATH.
1305func (f *File) DynString(tag DynTag) ([]string, error) {
1306 switch tag {
1307 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1308 default:
1309 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1310 }
1311 ds := f.SectionByType(SHT_DYNAMIC)
1312 if ds == nil {
1313 // not dynamic, so no libraries
1314 return nil, nil
1315 }
1316 d, err := ds.Data()
1317 if err != nil {
1318 return nil, err
1319 }
1320 str, err := f.stringTable(ds.Link)
1321 if err != nil {
1322 return nil, err
1323 }
1324 var all []string
1325 for len(d) > 0 {
1326 var t DynTag
1327 var v uint64
1328 switch f.Class {
1329 case ELFCLASS32:
1330 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1331 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1332 d = d[8:]
1333 case ELFCLASS64:
1334 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1335 v = f.ByteOrder.Uint64(d[8:16])
1336 d = d[16:]
1337 }
1338 if t == tag {
1339 s, ok := getString(str, int(v))
1340 if ok {
1341 all = append(all, s)
1342 }
1343 }
1344 }
1345 return all, nil
1346}