Source file src/pkg/debug/elf/file.go
1 // 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 elf implements access to ELF object files.
6 package elf
7
8 import (
9 "bytes"
10 "debug/dwarf"
11 "encoding/binary"
12 "errors"
13 "fmt"
14 "io"
15 "os"
16 )
17
18 // TODO: error reporting detail
19
20 /*
21 * Internal ELF representation
22 */
23
24 // A FileHeader represents an ELF file header.
25 type FileHeader struct {
26 Class Class
27 Data Data
28 Version Version
29 OSABI OSABI
30 ABIVersion uint8
31 ByteOrder binary.ByteOrder
32 Type Type
33 Machine Machine
34 }
35
36 // A File represents an open ELF file.
37 type File struct {
38 FileHeader
39 Sections []*Section
40 Progs []*Prog
41 closer io.Closer
42 gnuNeed []verneed
43 gnuVersym []byte
44 }
45
46 // A SectionHeader represents a single ELF section header.
47 type SectionHeader struct {
48 Name string
49 Type SectionType
50 Flags SectionFlag
51 Addr uint64
52 Offset uint64
53 Size uint64
54 Link uint32
55 Info uint32
56 Addralign uint64
57 Entsize uint64
58 }
59
60 // A Section represents a single section in an ELF file.
61 type Section struct {
62 SectionHeader
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 ELF section.
75 func (s *Section) 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 // stringTable reads and returns the string table given by the
82 // specified link value.
83 func (f *File) stringTable(link uint32) ([]byte, error) {
84 if link <= 0 || link >= uint32(len(f.Sections)) {
85 return nil, errors.New("section has invalid string table link")
86 }
87 return f.Sections[link].Data()
88 }
89
90 // Open returns a new ReadSeeker reading the ELF section.
91 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
92
93 // A ProgHeader represents a single ELF program header.
94 type ProgHeader struct {
95 Type ProgType
96 Flags ProgFlag
97 Off uint64
98 Vaddr uint64
99 Paddr uint64
100 Filesz uint64
101 Memsz uint64
102 Align uint64
103 }
104
105 // A Prog represents a single ELF program header in an ELF binary.
106 type Prog struct {
107 ProgHeader
108
109 // Embed ReaderAt for ReadAt method.
110 // Do not embed SectionReader directly
111 // to avoid having Read and Seek.
112 // If a client wants Read and Seek it must use
113 // Open() to avoid fighting over the seek offset
114 // with other clients.
115 io.ReaderAt
116 sr *io.SectionReader
117 }
118
119 // Open returns a new ReadSeeker reading the ELF program body.
120 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
121
122 // A Symbol represents an entry in an ELF symbol table section.
123 type Symbol struct {
124 Name string
125 Info, Other byte
126 Section SectionIndex
127 Value, Size uint64
128 }
129
130 /*
131 * ELF reader
132 */
133
134 type FormatError struct {
135 off int64
136 msg string
137 val interface{}
138 }
139
140 func (e *FormatError) Error() string {
141 msg := e.msg
142 if e.val != nil {
143 msg += fmt.Sprintf(" '%v' ", e.val)
144 }
145 msg += fmt.Sprintf("in record at byte %#x", e.off)
146 return msg
147 }
148
149 // Open opens the named file using os.Open and prepares it for use as an ELF binary.
150 func Open(name string) (*File, error) {
151 f, err := os.Open(name)
152 if err != nil {
153 return nil, err
154 }
155 ff, err := NewFile(f)
156 if err != nil {
157 f.Close()
158 return nil, err
159 }
160 ff.closer = f
161 return ff, nil
162 }
163
164 // Close closes the File.
165 // If the File was created using NewFile directly instead of Open,
166 // Close has no effect.
167 func (f *File) Close() error {
168 var err error
169 if f.closer != nil {
170 err = f.closer.Close()
171 f.closer = nil
172 }
173 return err
174 }
175
176 // SectionByType returns the first section in f with the
177 // given type, or nil if there is no such section.
178 func (f *File) SectionByType(typ SectionType) *Section {
179 for _, s := range f.Sections {
180 if s.Type == typ {
181 return s
182 }
183 }
184 return nil
185 }
186
187 // NewFile creates a new File for accessing an ELF binary in an underlying reader.
188 // The ELF binary is expected to start at position 0 in the ReaderAt.
189 func NewFile(r io.ReaderAt) (*File, error) {
190 sr := io.NewSectionReader(r, 0, 1<<63-1)
191 // Read and decode ELF identifier
192 var ident [16]uint8
193 if _, err := r.ReadAt(ident[0:], 0); err != nil {
194 return nil, err
195 }
196 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
197 return nil, &FormatError{0, "bad magic number", ident[0:4]}
198 }
199
200 f := new(File)
201 f.Class = Class(ident[EI_CLASS])
202 switch f.Class {
203 case ELFCLASS32:
204 case ELFCLASS64:
205 // ok
206 default:
207 return nil, &FormatError{0, "unknown ELF class", f.Class}
208 }
209
210 f.Data = Data(ident[EI_DATA])
211 switch f.Data {
212 case ELFDATA2LSB:
213 f.ByteOrder = binary.LittleEndian
214 case ELFDATA2MSB:
215 f.ByteOrder = binary.BigEndian
216 default:
217 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
218 }
219
220 f.Version = Version(ident[EI_VERSION])
221 if f.Version != EV_CURRENT {
222 return nil, &FormatError{0, "unknown ELF version", f.Version}
223 }
224
225 f.OSABI = OSABI(ident[EI_OSABI])
226 f.ABIVersion = ident[EI_ABIVERSION]
227
228 // Read ELF file header
229 var phoff int64
230 var phentsize, phnum int
231 var shoff int64
232 var shentsize, shnum, shstrndx int
233 shstrndx = -1
234 switch f.Class {
235 case ELFCLASS32:
236 hdr := new(Header32)
237 sr.Seek(0, os.SEEK_SET)
238 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
239 return nil, err
240 }
241 f.Type = Type(hdr.Type)
242 f.Machine = Machine(hdr.Machine)
243 if v := Version(hdr.Version); v != f.Version {
244 return nil, &FormatError{0, "mismatched ELF version", v}
245 }
246 phoff = int64(hdr.Phoff)
247 phentsize = int(hdr.Phentsize)
248 phnum = int(hdr.Phnum)
249 shoff = int64(hdr.Shoff)
250 shentsize = int(hdr.Shentsize)
251 shnum = int(hdr.Shnum)
252 shstrndx = int(hdr.Shstrndx)
253 case ELFCLASS64:
254 hdr := new(Header64)
255 sr.Seek(0, os.SEEK_SET)
256 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
257 return nil, err
258 }
259 f.Type = Type(hdr.Type)
260 f.Machine = Machine(hdr.Machine)
261 if v := Version(hdr.Version); v != f.Version {
262 return nil, &FormatError{0, "mismatched ELF version", v}
263 }
264 phoff = int64(hdr.Phoff)
265 phentsize = int(hdr.Phentsize)
266 phnum = int(hdr.Phnum)
267 shoff = int64(hdr.Shoff)
268 shentsize = int(hdr.Shentsize)
269 shnum = int(hdr.Shnum)
270 shstrndx = int(hdr.Shstrndx)
271 }
272 if shstrndx < 0 || shstrndx >= shnum {
273 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
274 }
275
276 // Read program headers
277 f.Progs = make([]*Prog, phnum)
278 for i := 0; i < phnum; i++ {
279 off := phoff + int64(i)*int64(phentsize)
280 sr.Seek(off, os.SEEK_SET)
281 p := new(Prog)
282 switch f.Class {
283 case ELFCLASS32:
284 ph := new(Prog32)
285 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
286 return nil, err
287 }
288 p.ProgHeader = ProgHeader{
289 Type: ProgType(ph.Type),
290 Flags: ProgFlag(ph.Flags),
291 Off: uint64(ph.Off),
292 Vaddr: uint64(ph.Vaddr),
293 Paddr: uint64(ph.Paddr),
294 Filesz: uint64(ph.Filesz),
295 Memsz: uint64(ph.Memsz),
296 Align: uint64(ph.Align),
297 }
298 case ELFCLASS64:
299 ph := new(Prog64)
300 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
301 return nil, err
302 }
303 p.ProgHeader = ProgHeader{
304 Type: ProgType(ph.Type),
305 Flags: ProgFlag(ph.Flags),
306 Off: uint64(ph.Off),
307 Vaddr: uint64(ph.Vaddr),
308 Paddr: uint64(ph.Paddr),
309 Filesz: uint64(ph.Filesz),
310 Memsz: uint64(ph.Memsz),
311 Align: uint64(ph.Align),
312 }
313 }
314 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
315 p.ReaderAt = p.sr
316 f.Progs[i] = p
317 }
318
319 // Read section headers
320 f.Sections = make([]*Section, shnum)
321 names := make([]uint32, shnum)
322 for i := 0; i < shnum; i++ {
323 off := shoff + int64(i)*int64(shentsize)
324 sr.Seek(off, os.SEEK_SET)
325 s := new(Section)
326 switch f.Class {
327 case ELFCLASS32:
328 sh := new(Section32)
329 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
330 return nil, err
331 }
332 names[i] = sh.Name
333 s.SectionHeader = SectionHeader{
334 Type: SectionType(sh.Type),
335 Flags: SectionFlag(sh.Flags),
336 Addr: uint64(sh.Addr),
337 Offset: uint64(sh.Off),
338 Size: uint64(sh.Size),
339 Link: uint32(sh.Link),
340 Info: uint32(sh.Info),
341 Addralign: uint64(sh.Addralign),
342 Entsize: uint64(sh.Entsize),
343 }
344 case ELFCLASS64:
345 sh := new(Section64)
346 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
347 return nil, err
348 }
349 names[i] = sh.Name
350 s.SectionHeader = SectionHeader{
351 Type: SectionType(sh.Type),
352 Flags: SectionFlag(sh.Flags),
353 Offset: uint64(sh.Off),
354 Size: uint64(sh.Size),
355 Addr: uint64(sh.Addr),
356 Link: uint32(sh.Link),
357 Info: uint32(sh.Info),
358 Addralign: uint64(sh.Addralign),
359 Entsize: uint64(sh.Entsize),
360 }
361 }
362 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
363 s.ReaderAt = s.sr
364 f.Sections[i] = s
365 }
366
367 // Load section header string table.
368 shstrtab, err := f.Sections[shstrndx].Data()
369 if err != nil {
370 return nil, err
371 }
372 for i, s := range f.Sections {
373 var ok bool
374 s.Name, ok = getString(shstrtab, int(names[i]))
375 if !ok {
376 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
377 }
378 }
379
380 return f, nil
381 }
382
383 // getSymbols returns a slice of Symbols from parsing the symbol table
384 // with the given type, along with the associated string table.
385 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
386 switch f.Class {
387 case ELFCLASS64:
388 return f.getSymbols64(typ)
389
390 case ELFCLASS32:
391 return f.getSymbols32(typ)
392 }
393
394 return nil, nil, errors.New("not implemented")
395 }
396
397 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
398 symtabSection := f.SectionByType(typ)
399 if symtabSection == nil {
400 return nil, nil, errors.New("no symbol section")
401 }
402
403 data, err := symtabSection.Data()
404 if err != nil {
405 return nil, nil, errors.New("cannot load symbol section")
406 }
407 symtab := bytes.NewBuffer(data)
408 if symtab.Len()%Sym32Size != 0 {
409 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
410 }
411
412 strdata, err := f.stringTable(symtabSection.Link)
413 if err != nil {
414 return nil, nil, errors.New("cannot load string table section")
415 }
416
417 // The first entry is all zeros.
418 var skip [Sym32Size]byte
419 symtab.Read(skip[0:])
420
421 symbols := make([]Symbol, symtab.Len()/Sym32Size)
422
423 i := 0
424 var sym Sym32
425 for symtab.Len() > 0 {
426 binary.Read(symtab, f.ByteOrder, &sym)
427 str, _ := getString(strdata, int(sym.Name))
428 symbols[i].Name = str
429 symbols[i].Info = sym.Info
430 symbols[i].Other = sym.Other
431 symbols[i].Section = SectionIndex(sym.Shndx)
432 symbols[i].Value = uint64(sym.Value)
433 symbols[i].Size = uint64(sym.Size)
434 i++
435 }
436
437 return symbols, strdata, nil
438 }
439
440 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
441 symtabSection := f.SectionByType(typ)
442 if symtabSection == nil {
443 return nil, nil, errors.New("no symbol section")
444 }
445
446 data, err := symtabSection.Data()
447 if err != nil {
448 return nil, nil, errors.New("cannot load symbol section")
449 }
450 symtab := bytes.NewBuffer(data)
451 if symtab.Len()%Sym64Size != 0 {
452 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
453 }
454
455 strdata, err := f.stringTable(symtabSection.Link)
456 if err != nil {
457 return nil, nil, errors.New("cannot load string table section")
458 }
459
460 // The first entry is all zeros.
461 var skip [Sym64Size]byte
462 symtab.Read(skip[0:])
463
464 symbols := make([]Symbol, symtab.Len()/Sym64Size)
465
466 i := 0
467 var sym Sym64
468 for symtab.Len() > 0 {
469 binary.Read(symtab, f.ByteOrder, &sym)
470 str, _ := getString(strdata, int(sym.Name))
471 symbols[i].Name = str
472 symbols[i].Info = sym.Info
473 symbols[i].Other = sym.Other
474 symbols[i].Section = SectionIndex(sym.Shndx)
475 symbols[i].Value = sym.Value
476 symbols[i].Size = sym.Size
477 i++
478 }
479
480 return symbols, strdata, nil
481 }
482
483 // getString extracts a string from an ELF string table.
484 func getString(section []byte, start int) (string, bool) {
485 if start < 0 || start >= len(section) {
486 return "", false
487 }
488
489 for end := start; end < len(section); end++ {
490 if section[end] == 0 {
491 return string(section[start:end]), true
492 }
493 }
494 return "", false
495 }
496
497 // Section returns a section with the given name, or nil if no such
498 // section exists.
499 func (f *File) Section(name string) *Section {
500 for _, s := range f.Sections {
501 if s.Name == name {
502 return s
503 }
504 }
505 return nil
506 }
507
508 // applyRelocations applies relocations to dst. rels is a relocations section
509 // in RELA format.
510 func (f *File) applyRelocations(dst []byte, rels []byte) error {
511 if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
512 return f.applyRelocationsAMD64(dst, rels)
513 }
514
515 return errors.New("not implemented")
516 }
517
518 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
519 if len(rels)%Sym64Size != 0 {
520 return errors.New("length of relocation section is not a multiple of Sym64Size")
521 }
522
523 symbols, _, err := f.getSymbols(SHT_SYMTAB)
524 if err != nil {
525 return err
526 }
527
528 b := bytes.NewBuffer(rels)
529 var rela Rela64
530
531 for b.Len() > 0 {
532 binary.Read(b, f.ByteOrder, &rela)
533 symNo := rela.Info >> 32
534 t := R_X86_64(rela.Info & 0xffff)
535
536 if symNo >= uint64(len(symbols)) {
537 continue
538 }
539 sym := &symbols[symNo]
540 if SymType(sym.Info&0xf) != STT_SECTION {
541 // We don't handle non-section relocations for now.
542 continue
543 }
544
545 switch t {
546 case R_X86_64_64:
547 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
548 continue
549 }
550 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
551 case R_X86_64_32:
552 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
553 continue
554 }
555 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
556 }
557 }
558
559 return nil
560 }
561
562 func (f *File) DWARF() (*dwarf.Data, error) {
563 // There are many other DWARF sections, but these
564 // are the required ones, and the debug/dwarf package
565 // does not use the others, so don't bother loading them.
566 var names = [...]string{"abbrev", "info", "str"}
567 var dat [len(names)][]byte
568 for i, name := range names {
569 name = ".debug_" + name
570 s := f.Section(name)
571 if s == nil {
572 continue
573 }
574 b, err := s.Data()
575 if err != nil && uint64(len(b)) < s.Size {
576 return nil, err
577 }
578 dat[i] = b
579 }
580
581 // If there's a relocation table for .debug_info, we have to process it
582 // now otherwise the data in .debug_info is invalid for x86-64 objects.
583 rela := f.Section(".rela.debug_info")
584 if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
585 data, err := rela.Data()
586 if err != nil {
587 return nil, err
588 }
589 err = f.applyRelocations(dat[1], data)
590 if err != nil {
591 return nil, err
592 }
593 }
594
595 abbrev, info, str := dat[0], dat[1], dat[2]
596 return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
597 }
598
599 // Symbols returns the symbol table for f.
600 func (f *File) Symbols() ([]Symbol, error) {
601 sym, _, err := f.getSymbols(SHT_SYMTAB)
602 return sym, err
603 }
604
605 type ImportedSymbol struct {
606 Name string
607 Version string
608 Library string
609 }
610
611 // ImportedSymbols returns the names of all symbols
612 // referred to by the binary f that are expected to be
613 // satisfied by other libraries at dynamic load time.
614 // It does not return weak symbols.
615 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
616 sym, str, err := f.getSymbols(SHT_DYNSYM)
617 if err != nil {
618 return nil, err
619 }
620 f.gnuVersionInit(str)
621 var all []ImportedSymbol
622 for i, s := range sym {
623 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
624 all = append(all, ImportedSymbol{Name: s.Name})
625 f.gnuVersion(i, &all[len(all)-1])
626 }
627 }
628 return all, nil
629 }
630
631 type verneed struct {
632 File string
633 Name string
634 }
635
636 // gnuVersionInit parses the GNU version tables
637 // for use by calls to gnuVersion.
638 func (f *File) gnuVersionInit(str []byte) {
639 // Accumulate verneed information.
640 vn := f.SectionByType(SHT_GNU_VERNEED)
641 if vn == nil {
642 return
643 }
644 d, _ := vn.Data()
645
646 var need []verneed
647 i := 0
648 for {
649 if i+16 > len(d) {
650 break
651 }
652 vers := f.ByteOrder.Uint16(d[i : i+2])
653 if vers != 1 {
654 break
655 }
656 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
657 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
658 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
659 next := f.ByteOrder.Uint32(d[i+12 : i+16])
660 file, _ := getString(str, int(fileoff))
661
662 var name string
663 j := i + int(aux)
664 for c := 0; c < int(cnt); c++ {
665 if j+16 > len(d) {
666 break
667 }
668 // hash := f.ByteOrder.Uint32(d[j:j+4])
669 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
670 other := f.ByteOrder.Uint16(d[j+6 : j+8])
671 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
672 next := f.ByteOrder.Uint32(d[j+12 : j+16])
673 name, _ = getString(str, int(nameoff))
674 ndx := int(other)
675 if ndx >= len(need) {
676 a := make([]verneed, 2*(ndx+1))
677 copy(a, need)
678 need = a
679 }
680
681 need[ndx] = verneed{file, name}
682 if next == 0 {
683 break
684 }
685 j += int(next)
686 }
687
688 if next == 0 {
689 break
690 }
691 i += int(next)
692 }
693
694 // Versym parallels symbol table, indexing into verneed.
695 vs := f.SectionByType(SHT_GNU_VERSYM)
696 if vs == nil {
697 return
698 }
699 d, _ = vs.Data()
700
701 f.gnuNeed = need
702 f.gnuVersym = d
703 }
704
705 // gnuVersion adds Library and Version information to sym,
706 // which came from offset i of the symbol table.
707 func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
708 // Each entry is two bytes; skip undef entry at beginning.
709 i = (i + 1) * 2
710 if i >= len(f.gnuVersym) {
711 return
712 }
713 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
714 if j < 2 || j >= len(f.gnuNeed) {
715 return
716 }
717 n := &f.gnuNeed[j]
718 sym.Library = n.File
719 sym.Version = n.Name
720 }
721
722 // ImportedLibraries returns the names of all libraries
723 // referred to by the binary f that are expected to be
724 // linked with the binary at dynamic link time.
725 func (f *File) ImportedLibraries() ([]string, error) {
726 ds := f.SectionByType(SHT_DYNAMIC)
727 if ds == nil {
728 // not dynamic, so no libraries
729 return nil, nil
730 }
731 d, err := ds.Data()
732 if err != nil {
733 return nil, err
734 }
735 str, err := f.stringTable(ds.Link)
736 if err != nil {
737 return nil, err
738 }
739 var all []string
740 for len(d) > 0 {
741 var tag DynTag
742 var value uint64
743 switch f.Class {
744 case ELFCLASS32:
745 tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
746 value = uint64(f.ByteOrder.Uint32(d[4:8]))
747 d = d[8:]
748 case ELFCLASS64:
749 tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
750 value = f.ByteOrder.Uint64(d[8:16])
751 d = d[16:]
752 }
753 if tag == DT_NEEDED {
754 s, ok := getString(str, int(value))
755 if ok {
756 all = append(all, s)
757 }
758 }
759 }
760
761 return all, nil
762 }