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.
5 // Package elf implements access to ELF object files.
18 // TODO: error reporting detail
21 * Internal ELF representation
24 // A FileHeader represents an ELF file header.
25 type FileHeader
struct {
31 ByteOrder binary
.ByteOrder
37 // A File represents an open ELF file.
47 // A SectionHeader represents a single ELF section header.
48 type SectionHeader
struct {
61 // A Section represents a single section in an ELF file.
65 // Embed ReaderAt for ReadAt method.
66 // Do not embed SectionReader directly
67 // to avoid having Read and Seek.
68 // If a client wants Read and Seek it must use
69 // Open() to avoid fighting over the seek offset
70 // with other clients.
75 // Data reads and returns the contents of the ELF section.
76 func (s
*Section
) Data() ([]byte, error
) {
77 dat
:= make([]byte, s
.sr
.Size())
78 n
, err
:= s
.sr
.ReadAt(dat
, 0)
85 // stringTable reads and returns the string table given by the
86 // specified link value.
87 func (f
*File
) stringTable(link
uint32) ([]byte, error
) {
88 if link
<= 0 || link
>= uint32(len(f
.Sections
)) {
89 return nil, errors
.New("section has invalid string table link")
91 return f
.Sections
[link
].Data()
94 // Open returns a new ReadSeeker reading the ELF section.
95 func (s
*Section
) Open() io
.ReadSeeker
{ return io
.NewSectionReader(s
.sr
, 0, 1<<63-1) }
97 // A ProgHeader represents a single ELF program header.
98 type ProgHeader
struct {
109 // A Prog represents a single ELF program header in an ELF binary.
113 // Embed ReaderAt for ReadAt method.
114 // Do not embed SectionReader directly
115 // to avoid having Read and Seek.
116 // If a client wants Read and Seek it must use
117 // Open() to avoid fighting over the seek offset
118 // with other clients.
123 // Open returns a new ReadSeeker reading the ELF program body.
124 func (p
*Prog
) Open() io
.ReadSeeker
{ return io
.NewSectionReader(p
.sr
, 0, 1<<63-1) }
126 // A Symbol represents an entry in an ELF symbol table section.
138 type FormatError
struct {
144 func (e
*FormatError
) Error() string {
147 msg
+= fmt
.Sprintf(" '%v' ", e
.val
)
149 msg
+= fmt
.Sprintf("in record at byte %#x", e
.off
)
153 // Open opens the named file using os.Open and prepares it for use as an ELF binary.
154 func Open(name
string) (*File
, error
) {
155 f
, err
:= os
.Open(name
)
159 ff
, err
:= NewFile(f
)
168 // Close closes the File.
169 // If the File was created using NewFile directly instead of Open,
170 // Close has no effect.
171 func (f
*File
) Close() error
{
174 err
= f
.closer
.Close()
180 // SectionByType returns the first section in f with the
181 // given type, or nil if there is no such section.
182 func (f
*File
) SectionByType(typ SectionType
) *Section
{
183 for _
, s
:= range f
.Sections
{
191 // NewFile creates a new File for accessing an ELF binary in an underlying reader.
192 // The ELF binary is expected to start at position 0 in the ReaderAt.
193 func NewFile(r io
.ReaderAt
) (*File
, error
) {
194 sr
:= io
.NewSectionReader(r
, 0, 1<<63-1)
195 // Read and decode ELF identifier
197 if _
, err
:= r
.ReadAt(ident
[0:], 0); err
!= nil {
200 if ident
[0] != '\x7f' || ident
[1] != 'E' || ident
[2] != 'L' || ident
[3] != 'F' {
201 return nil, &FormatError
{0, "bad magic number", ident
[0:4]}
205 f
.Class
= Class(ident
[EI_CLASS
])
211 return nil, &FormatError
{0, "unknown ELF class", f
.Class
}
214 f
.Data
= Data(ident
[EI_DATA
])
217 f
.ByteOrder
= binary
.LittleEndian
219 f
.ByteOrder
= binary
.BigEndian
221 return nil, &FormatError
{0, "unknown ELF data encoding", f
.Data
}
224 f
.Version
= Version(ident
[EI_VERSION
])
225 if f
.Version
!= EV_CURRENT
{
226 return nil, &FormatError
{0, "unknown ELF version", f
.Version
}
229 f
.OSABI
= OSABI(ident
[EI_OSABI
])
230 f
.ABIVersion
= ident
[EI_ABIVERSION
]
232 // Read ELF file header
234 var phentsize
, phnum
int
236 var shentsize
, shnum
, shstrndx
int
241 sr
.Seek(0, os
.SEEK_SET
)
242 if err
:= binary
.Read(sr
, f
.ByteOrder
, hdr
); err
!= nil {
245 f
.Type
= Type(hdr
.Type
)
246 f
.Machine
= Machine(hdr
.Machine
)
247 f
.Entry
= uint64(hdr
.Entry
)
248 if v
:= Version(hdr
.Version
); v
!= f
.Version
{
249 return nil, &FormatError
{0, "mismatched ELF version", v
}
251 phoff
= int64(hdr
.Phoff
)
252 phentsize
= int(hdr
.Phentsize
)
253 phnum
= int(hdr
.Phnum
)
254 shoff
= int64(hdr
.Shoff
)
255 shentsize
= int(hdr
.Shentsize
)
256 shnum
= int(hdr
.Shnum
)
257 shstrndx
= int(hdr
.Shstrndx
)
260 sr
.Seek(0, os
.SEEK_SET
)
261 if err
:= binary
.Read(sr
, f
.ByteOrder
, hdr
); err
!= nil {
264 f
.Type
= Type(hdr
.Type
)
265 f
.Machine
= Machine(hdr
.Machine
)
266 f
.Entry
= uint64(hdr
.Entry
)
267 if v
:= Version(hdr
.Version
); v
!= f
.Version
{
268 return nil, &FormatError
{0, "mismatched ELF version", v
}
270 phoff
= int64(hdr
.Phoff
)
271 phentsize
= int(hdr
.Phentsize
)
272 phnum
= int(hdr
.Phnum
)
273 shoff
= int64(hdr
.Shoff
)
274 shentsize
= int(hdr
.Shentsize
)
275 shnum
= int(hdr
.Shnum
)
276 shstrndx
= int(hdr
.Shstrndx
)
279 if shnum
> 0 && shoff
> 0 && (shstrndx
< 0 || shstrndx
>= shnum
) {
280 return nil, &FormatError
{0, "invalid ELF shstrndx", shstrndx
}
283 // Read program headers
284 f
.Progs
= make([]*Prog
, phnum
)
285 for i
:= 0; i
< phnum
; i
++ {
286 off
:= phoff
+ int64(i
)*int64(phentsize
)
287 sr
.Seek(off
, os
.SEEK_SET
)
292 if err
:= binary
.Read(sr
, f
.ByteOrder
, ph
); err
!= nil {
295 p
.ProgHeader
= ProgHeader
{
296 Type
: ProgType(ph
.Type
),
297 Flags
: ProgFlag(ph
.Flags
),
299 Vaddr
: uint64(ph
.Vaddr
),
300 Paddr
: uint64(ph
.Paddr
),
301 Filesz
: uint64(ph
.Filesz
),
302 Memsz
: uint64(ph
.Memsz
),
303 Align
: uint64(ph
.Align
),
307 if err
:= binary
.Read(sr
, f
.ByteOrder
, ph
); err
!= nil {
310 p
.ProgHeader
= ProgHeader
{
311 Type
: ProgType(ph
.Type
),
312 Flags
: ProgFlag(ph
.Flags
),
314 Vaddr
: uint64(ph
.Vaddr
),
315 Paddr
: uint64(ph
.Paddr
),
316 Filesz
: uint64(ph
.Filesz
),
317 Memsz
: uint64(ph
.Memsz
),
318 Align
: uint64(ph
.Align
),
321 p
.sr
= io
.NewSectionReader(r
, int64(p
.Off
), int64(p
.Filesz
))
326 // Read section headers
327 f
.Sections
= make([]*Section
, shnum
)
328 names
:= make([]uint32, shnum
)
329 for i
:= 0; i
< shnum
; i
++ {
330 off
:= shoff
+ int64(i
)*int64(shentsize
)
331 sr
.Seek(off
, os
.SEEK_SET
)
336 if err
:= binary
.Read(sr
, f
.ByteOrder
, sh
); err
!= nil {
340 s
.SectionHeader
= SectionHeader
{
341 Type
: SectionType(sh
.Type
),
342 Flags
: SectionFlag(sh
.Flags
),
343 Addr
: uint64(sh
.Addr
),
344 Offset
: uint64(sh
.Off
),
345 Size
: uint64(sh
.Size
),
346 Link
: uint32(sh
.Link
),
347 Info
: uint32(sh
.Info
),
348 Addralign
: uint64(sh
.Addralign
),
349 Entsize
: uint64(sh
.Entsize
),
353 if err
:= binary
.Read(sr
, f
.ByteOrder
, sh
); err
!= nil {
357 s
.SectionHeader
= SectionHeader
{
358 Type
: SectionType(sh
.Type
),
359 Flags
: SectionFlag(sh
.Flags
),
360 Offset
: uint64(sh
.Off
),
361 Size
: uint64(sh
.Size
),
362 Addr
: uint64(sh
.Addr
),
363 Link
: uint32(sh
.Link
),
364 Info
: uint32(sh
.Info
),
365 Addralign
: uint64(sh
.Addralign
),
366 Entsize
: uint64(sh
.Entsize
),
369 s
.sr
= io
.NewSectionReader(r
, int64(s
.Offset
), int64(s
.Size
))
374 if len(f
.Sections
) == 0 {
378 // Load section header string table.
379 shstrtab
, err
:= f
.Sections
[shstrndx
].Data()
383 for i
, s
:= range f
.Sections
{
385 s
.Name
, ok
= getString(shstrtab
, int(names
[i
]))
387 return nil, &FormatError
{shoff
+ int64(i
*shentsize
), "bad section name index", names
[i
]}
394 // getSymbols returns a slice of Symbols from parsing the symbol table
395 // with the given type, along with the associated string table.
396 func (f
*File
) getSymbols(typ SectionType
) ([]Symbol
, []byte, error
) {
399 return f
.getSymbols64(typ
)
402 return f
.getSymbols32(typ
)
405 return nil, nil, errors
.New("not implemented")
408 func (f
*File
) getSymbols32(typ SectionType
) ([]Symbol
, []byte, error
) {
409 symtabSection
:= f
.SectionByType(typ
)
410 if symtabSection
== nil {
411 return nil, nil, errors
.New("no symbol section")
414 data
, err
:= symtabSection
.Data()
416 return nil, nil, errors
.New("cannot load symbol section")
418 symtab
:= bytes
.NewReader(data
)
419 if symtab
.Len()%Sym
32Size
!= 0 {
420 return nil, nil, errors
.New("length of symbol section is not a multiple of SymSize")
423 strdata
, err
:= f
.stringTable(symtabSection
.Link
)
425 return nil, nil, errors
.New("cannot load string table section")
428 // The first entry is all zeros.
429 var skip
[Sym32Size
]byte
432 symbols
:= make([]Symbol
, symtab
.Len()/Sym32Size
)
436 for symtab
.Len() > 0 {
437 binary
.Read(symtab
, f
.ByteOrder
, &sym
)
438 str
, _
:= getString(strdata
, int(sym
.Name
))
439 symbols
[i
].Name
= str
440 symbols
[i
].Info
= sym
.Info
441 symbols
[i
].Other
= sym
.Other
442 symbols
[i
].Section
= SectionIndex(sym
.Shndx
)
443 symbols
[i
].Value
= uint64(sym
.Value
)
444 symbols
[i
].Size
= uint64(sym
.Size
)
448 return symbols
, strdata
, nil
451 func (f
*File
) getSymbols64(typ SectionType
) ([]Symbol
, []byte, error
) {
452 symtabSection
:= f
.SectionByType(typ
)
453 if symtabSection
== nil {
454 return nil, nil, errors
.New("no symbol section")
457 data
, err
:= symtabSection
.Data()
459 return nil, nil, errors
.New("cannot load symbol section")
461 symtab
:= bytes
.NewReader(data
)
462 if symtab
.Len()%Sym
64Size
!= 0 {
463 return nil, nil, errors
.New("length of symbol section is not a multiple of Sym64Size")
466 strdata
, err
:= f
.stringTable(symtabSection
.Link
)
468 return nil, nil, errors
.New("cannot load string table section")
471 // The first entry is all zeros.
472 var skip
[Sym64Size
]byte
475 symbols
:= make([]Symbol
, symtab
.Len()/Sym64Size
)
479 for symtab
.Len() > 0 {
480 binary
.Read(symtab
, f
.ByteOrder
, &sym
)
481 str
, _
:= getString(strdata
, int(sym
.Name
))
482 symbols
[i
].Name
= str
483 symbols
[i
].Info
= sym
.Info
484 symbols
[i
].Other
= sym
.Other
485 symbols
[i
].Section
= SectionIndex(sym
.Shndx
)
486 symbols
[i
].Value
= sym
.Value
487 symbols
[i
].Size
= sym
.Size
491 return symbols
, strdata
, nil
494 // getString extracts a string from an ELF string table.
495 func getString(section
[]byte, start
int) (string, bool) {
496 if start
< 0 || start
>= len(section
) {
500 for end
:= start
; end
< len(section
); end
++ {
501 if section
[end
] == 0 {
502 return string(section
[start
:end
]), true
508 // Section returns a section with the given name, or nil if no such
510 func (f
*File
) Section(name
string) *Section
{
511 for _
, s
:= range f
.Sections
{
519 // applyRelocations applies relocations to dst. rels is a relocations section
521 func (f
*File
) applyRelocations(dst
[]byte, rels
[]byte) error
{
522 if f
.Class
== ELFCLASS64
&& f
.Machine
== EM_X86_64
{
523 return f
.applyRelocationsAMD64(dst
, rels
)
525 if f
.Class
== ELFCLASS32
&& f
.Machine
== EM_386
{
526 return f
.applyRelocations386(dst
, rels
)
529 return errors
.New("not implemented")
532 func (f
*File
) applyRelocationsAMD64(dst
[]byte, rels
[]byte) error
{
533 // 24 is the size of Rela64.
534 if len(rels
)%24
!= 0 {
535 return errors
.New("length of relocation section is not a multiple of 24")
538 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
543 b
:= bytes
.NewReader(rels
)
547 binary
.Read(b
, f
.ByteOrder
, &rela
)
548 symNo
:= rela
.Info
>> 32
549 t
:= R_X86_64(rela
.Info
& 0xffff)
551 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
554 sym
:= &symbols
[symNo
-1]
555 if SymType(sym
.Info
&0xf) != STT_SECTION
{
556 // We don't handle non-section relocations for now.
562 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
565 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
567 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
570 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
577 func (f
*File
) applyRelocations386(dst
[]byte, rels
[]byte) error
{
578 // 8 is the size of Rel32.
579 if len(rels
)%8
!= 0 {
580 return errors
.New("length of relocation section is not a multiple of 8")
583 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
588 b
:= bytes
.NewReader(rels
)
592 binary
.Read(b
, f
.ByteOrder
, &rel
)
593 symNo
:= rel
.Info
>> 8
594 t
:= R_386(rel
.Info
& 0xff)
596 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
599 sym
:= &symbols
[symNo
-1]
602 if rel
.Off
+4 >= uint32(len(dst
)) {
605 val
:= f
.ByteOrder
.Uint32(dst
[rel
.Off
: rel
.Off
+4])
606 val
+= uint32(sym
.Value
)
607 f
.ByteOrder
.PutUint32(dst
[rel
.Off
:rel
.Off
+4], val
)
614 func (f
*File
) DWARF() (*dwarf
.Data
, error
) {
615 // There are many other DWARF sections, but these
616 // are the required ones, and the debug/dwarf package
617 // does not use the others, so don't bother loading them.
618 var names
= [...]string{"abbrev", "info", "line", "ranges", "str"}
619 var dat
[len(names
)][]byte
620 for i
, name
:= range names
{
621 name
= ".debug_" + name
627 if err
!= nil && uint64(len(b
)) < s
.Size
{
633 // If there's a relocation table for .debug_info, we have to process it
634 // now otherwise the data in .debug_info is invalid for x86-64 objects.
635 rela
:= f
.Section(".rela.debug_info")
636 if rela
!= nil && rela
.Type
== SHT_RELA
&& f
.Machine
== EM_X86_64
{
637 data
, err
:= rela
.Data()
641 err
= f
.applyRelocations(dat
[1], data
)
647 // When using clang we need to process relocations even for 386.
648 rel
:= f
.Section(".rel.debug_info")
649 if rel
!= nil && rel
.Type
== SHT_REL
&& f
.Machine
== EM_386
{
650 data
, err
:= rel
.Data()
654 err
= f
.applyRelocations(dat
[1], data
)
660 abbrev
, info
, line
, ranges
, str
:= dat
[0], dat
[1], dat
[2], dat
[3], dat
[4]
661 d
, err
:= dwarf
.New(abbrev
, nil, nil, info
, line
, nil, ranges
, str
)
666 // Look for DWARF4 .debug_types sections.
667 for i
, s
:= range f
.Sections
{
668 if s
.Name
== ".debug_types" {
670 if err
!= nil && uint64(len(b
)) < s
.Size
{
674 for _
, r
:= range f
.Sections
{
675 if r
.Type
!= SHT_RELA
&& r
.Type
!= SHT_REL
{
678 if int(r
.Info
) != i
{
685 err
= f
.applyRelocations(b
, rd
)
691 err
= d
.AddTypes(fmt
.Sprintf("types-%d", i
), b
)
701 // Symbols returns the symbol table for f.
703 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
704 // After retrieving the symbols as symtab, an externally supplied index x
705 // corresponds to symtab[x-1], not symtab[x].
706 func (f
*File
) Symbols() ([]Symbol
, error
) {
707 sym
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
711 type ImportedSymbol
struct {
717 // ImportedSymbols returns the names of all symbols
718 // referred to by the binary f that are expected to be
719 // satisfied by other libraries at dynamic load time.
720 // It does not return weak symbols.
721 func (f
*File
) ImportedSymbols() ([]ImportedSymbol
, error
) {
722 sym
, str
, err
:= f
.getSymbols(SHT_DYNSYM
)
726 f
.gnuVersionInit(str
)
727 var all
[]ImportedSymbol
728 for i
, s
:= range sym
{
729 if ST_BIND(s
.Info
) == STB_GLOBAL
&& s
.Section
== SHN_UNDEF
{
730 all
= append(all
, ImportedSymbol
{Name
: s
.Name
})
731 f
.gnuVersion(i
, &all
[len(all
)-1])
737 type verneed
struct {
742 // gnuVersionInit parses the GNU version tables
743 // for use by calls to gnuVersion.
744 func (f
*File
) gnuVersionInit(str
[]byte) {
745 // Accumulate verneed information.
746 vn
:= f
.SectionByType(SHT_GNU_VERNEED
)
758 vers
:= f
.ByteOrder
.Uint16(d
[i
: i
+2])
762 cnt
:= f
.ByteOrder
.Uint16(d
[i
+2 : i
+4])
763 fileoff
:= f
.ByteOrder
.Uint32(d
[i
+4 : i
+8])
764 aux
:= f
.ByteOrder
.Uint32(d
[i
+8 : i
+12])
765 next
:= f
.ByteOrder
.Uint32(d
[i
+12 : i
+16])
766 file
, _
:= getString(str
, int(fileoff
))
770 for c
:= 0; c
< int(cnt
); c
++ {
774 // hash := f.ByteOrder.Uint32(d[j:j+4])
775 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
776 other
:= f
.ByteOrder
.Uint16(d
[j
+6 : j
+8])
777 nameoff
:= f
.ByteOrder
.Uint32(d
[j
+8 : j
+12])
778 next
:= f
.ByteOrder
.Uint32(d
[j
+12 : j
+16])
779 name
, _
= getString(str
, int(nameoff
))
781 if ndx
>= len(need
) {
782 a
:= make([]verneed
, 2*(ndx
+1))
787 need
[ndx
] = verneed
{file
, name
}
800 // Versym parallels symbol table, indexing into verneed.
801 vs
:= f
.SectionByType(SHT_GNU_VERSYM
)
811 // gnuVersion adds Library and Version information to sym,
812 // which came from offset i of the symbol table.
813 func (f
*File
) gnuVersion(i
int, sym
*ImportedSymbol
) {
814 // Each entry is two bytes.
816 if i
>= len(f
.gnuVersym
) {
819 j
:= int(f
.ByteOrder
.Uint16(f
.gnuVersym
[i
:]))
820 if j
< 2 || j
>= len(f
.gnuNeed
) {
828 // ImportedLibraries returns the names of all libraries
829 // referred to by the binary f that are expected to be
830 // linked with the binary at dynamic link time.
831 func (f
*File
) ImportedLibraries() ([]string, error
) {
832 return f
.DynString(DT_NEEDED
)
835 // DynString returns the strings listed for the given tag in the file's dynamic
838 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
840 func (f
*File
) DynString(tag DynTag
) ([]string, error
) {
842 case DT_NEEDED
, DT_SONAME
, DT_RPATH
, DT_RUNPATH
:
844 return nil, fmt
.Errorf("non-string-valued tag %v", tag
)
846 ds
:= f
.SectionByType(SHT_DYNAMIC
)
848 // not dynamic, so no libraries
855 str
, err
:= f
.stringTable(ds
.Link
)
865 t
= DynTag(f
.ByteOrder
.Uint32(d
[0:4]))
866 v
= uint64(f
.ByteOrder
.Uint32(d
[4:8]))
869 t
= DynTag(f
.ByteOrder
.Uint64(d
[0:8]))
870 v
= f
.ByteOrder
.Uint64(d
[8:16])
874 s
, ok
:= getString(str
, int(v
))