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.
6package elf
7
8import (
9	"bytes"
10	"compress/zlib"
11	"debug/dwarf"
12	"encoding/binary"
13	"errors"
14	"fmt"
15	"io"
16	"os"
17	"strings"
18)
19
20// 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
31// 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
72
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
78}
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.
90	//
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.
94	io.ReaderAt
95	sr *io.SectionReader
96
97	compressionType   CompressionType
98	compressionOffset int64
99}
100
101// Data reads and returns the contents of the ELF section.
102// Even if the section is stored compressed in the ELF file,
103// Data returns uncompressed data.
104func (s *Section) Data() ([]byte, error) {
105	dat := make([]byte, s.Size)
106	n, err := io.ReadFull(s.Open(), dat)
107	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.
120// 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}
138
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	// Version and Library are present only for the dynamic symbol
176	// table.
177	Version string
178	Library string
179}
180
181/*
182 * ELF reader
183 */
184
185type FormatError struct {
186	off int64
187	msg string
188	val interface{}
189}
190
191func (e *FormatError) Error() string {
192	msg := e.msg
193	if e.val != nil {
194		msg += fmt.Sprintf(" '%v' ", e.val)
195	}
196	msg += fmt.Sprintf("in record at byte %#x", e.off)
197	return msg
198}
199
200// Open opens the named file using os.Open and prepares it for use as an ELF binary.
201func Open(name string) (*File, error) {
202	f, err := os.Open(name)
203	if err != nil {
204		return nil, err
205	}
206	ff, err := NewFile(f)
207	if err != nil {
208		f.Close()
209		return nil, err
210	}
211	ff.closer = f
212	return ff, nil
213}
214
215// Close closes the File.
216// If the File was created using NewFile directly instead of Open,
217// Close has no effect.
218func (f *File) Close() error {
219	var err error
220	if f.closer != nil {
221		err = f.closer.Close()
222		f.closer = nil
223	}
224	return err
225}
226
227// SectionByType returns the first section in f with the
228// given type, or nil if there is no such section.
229func (f *File) SectionByType(typ SectionType) *Section {
230	for _, s := range f.Sections {
231		if s.Type == typ {
232			return s
233		}
234	}
235	return nil
236}
237
238// NewFile creates a new File for accessing an ELF binary in an underlying reader.
239// The ELF binary is expected to start at position 0 in the ReaderAt.
240func NewFile(r io.ReaderAt) (*File, error) {
241	sr := io.NewSectionReader(r, 0, 1<<63-1)
242	// Read and decode ELF identifier
243	var ident [16]uint8
244	if _, err := r.ReadAt(ident[0:], 0); err != nil {
245		return nil, err
246	}
247	if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
248		return nil, &FormatError{0, "bad magic number", ident[0:4]}
249	}
250
251	f := new(File)
252	f.Class = Class(ident[EI_CLASS])
253	switch f.Class {
254	case ELFCLASS32:
255	case ELFCLASS64:
256		// ok
257	default:
258		return nil, &FormatError{0, "unknown ELF class", f.Class}
259	}
260
261	f.Data = Data(ident[EI_DATA])
262	switch f.Data {
263	case ELFDATA2LSB:
264		f.ByteOrder = binary.LittleEndian
265	case ELFDATA2MSB:
266		f.ByteOrder = binary.BigEndian
267	default:
268		return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
269	}
270
271	f.Version = Version(ident[EI_VERSION])
272	if f.Version != EV_CURRENT {
273		return nil, &FormatError{0, "unknown ELF version", f.Version}
274	}
275
276	f.OSABI = OSABI(ident[EI_OSABI])
277	f.ABIVersion = ident[EI_ABIVERSION]
278
279	// Read ELF file header
280	var phoff int64
281	var phentsize, phnum int
282	var shoff int64
283	var shentsize, shnum, shstrndx int
284	switch f.Class {
285	case ELFCLASS32:
286		hdr := new(Header32)
287		sr.Seek(0, seekStart)
288		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
289			return nil, err
290		}
291		f.Type = Type(hdr.Type)
292		f.Machine = Machine(hdr.Machine)
293		f.Entry = uint64(hdr.Entry)
294		if v := Version(hdr.Version); v != f.Version {
295			return nil, &FormatError{0, "mismatched ELF version", v}
296		}
297		phoff = int64(hdr.Phoff)
298		phentsize = int(hdr.Phentsize)
299		phnum = int(hdr.Phnum)
300		shoff = int64(hdr.Shoff)
301		shentsize = int(hdr.Shentsize)
302		shnum = int(hdr.Shnum)
303		shstrndx = int(hdr.Shstrndx)
304	case ELFCLASS64:
305		hdr := new(Header64)
306		sr.Seek(0, seekStart)
307		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
308			return nil, err
309		}
310		f.Type = Type(hdr.Type)
311		f.Machine = Machine(hdr.Machine)
312		f.Entry = hdr.Entry
313		if v := Version(hdr.Version); v != f.Version {
314			return nil, &FormatError{0, "mismatched ELF version", v}
315		}
316		phoff = int64(hdr.Phoff)
317		phentsize = int(hdr.Phentsize)
318		phnum = int(hdr.Phnum)
319		shoff = int64(hdr.Shoff)
320		shentsize = int(hdr.Shentsize)
321		shnum = int(hdr.Shnum)
322		shstrndx = int(hdr.Shstrndx)
323	}
324
325	if shoff == 0 && shnum != 0 {
326		return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}
327	}
328
329	if shnum > 0 && shstrndx >= shnum {
330		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
331	}
332
333	// Read program headers
334	f.Progs = make([]*Prog, phnum)
335	for i := 0; i < phnum; i++ {
336		off := phoff + int64(i)*int64(phentsize)
337		sr.Seek(off, seekStart)
338		p := new(Prog)
339		switch f.Class {
340		case ELFCLASS32:
341			ph := new(Prog32)
342			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
343				return nil, err
344			}
345			p.ProgHeader = ProgHeader{
346				Type:   ProgType(ph.Type),
347				Flags:  ProgFlag(ph.Flags),
348				Off:    uint64(ph.Off),
349				Vaddr:  uint64(ph.Vaddr),
350				Paddr:  uint64(ph.Paddr),
351				Filesz: uint64(ph.Filesz),
352				Memsz:  uint64(ph.Memsz),
353				Align:  uint64(ph.Align),
354			}
355		case ELFCLASS64:
356			ph := new(Prog64)
357			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
358				return nil, err
359			}
360			p.ProgHeader = ProgHeader{
361				Type:   ProgType(ph.Type),
362				Flags:  ProgFlag(ph.Flags),
363				Off:    ph.Off,
364				Vaddr:  ph.Vaddr,
365				Paddr:  ph.Paddr,
366				Filesz: ph.Filesz,
367				Memsz:  ph.Memsz,
368				Align:  ph.Align,
369			}
370		}
371		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
372		p.ReaderAt = p.sr
373		f.Progs[i] = p
374	}
375
376	// Read section headers
377	f.Sections = make([]*Section, shnum)
378	names := make([]uint32, shnum)
379	for i := 0; i < shnum; i++ {
380		off := shoff + int64(i)*int64(shentsize)
381		sr.Seek(off, seekStart)
382		s := new(Section)
383		switch f.Class {
384		case ELFCLASS32:
385			sh := new(Section32)
386			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
387				return nil, err
388			}
389			names[i] = sh.Name
390			s.SectionHeader = SectionHeader{
391				Type:      SectionType(sh.Type),
392				Flags:     SectionFlag(sh.Flags),
393				Addr:      uint64(sh.Addr),
394				Offset:    uint64(sh.Off),
395				FileSize:  uint64(sh.Size),
396				Link:      sh.Link,
397				Info:      sh.Info,
398				Addralign: uint64(sh.Addralign),
399				Entsize:   uint64(sh.Entsize),
400			}
401		case ELFCLASS64:
402			sh := new(Section64)
403			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
404				return nil, err
405			}
406			names[i] = sh.Name
407			s.SectionHeader = SectionHeader{
408				Type:      SectionType(sh.Type),
409				Flags:     SectionFlag(sh.Flags),
410				Offset:    sh.Off,
411				FileSize:  sh.Size,
412				Addr:      sh.Addr,
413				Link:      sh.Link,
414				Info:      sh.Info,
415				Addralign: sh.Addralign,
416				Entsize:   sh.Entsize,
417			}
418		}
419		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
420
421		if s.Flags&SHF_COMPRESSED == 0 {
422			s.ReaderAt = s.sr
423			s.Size = s.FileSize
424		} else {
425			// Read the compression header.
426			switch f.Class {
427			case ELFCLASS32:
428				ch := new(Chdr32)
429				if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
430					return nil, err
431				}
432				s.compressionType = CompressionType(ch.Type)
433				s.Size = uint64(ch.Size)
434				s.Addralign = uint64(ch.Addralign)
435				s.compressionOffset = int64(binary.Size(ch))
436			case ELFCLASS64:
437				ch := new(Chdr64)
438				if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
439					return nil, err
440				}
441				s.compressionType = CompressionType(ch.Type)
442				s.Size = ch.Size
443				s.Addralign = ch.Addralign
444				s.compressionOffset = int64(binary.Size(ch))
445			}
446		}
447
448		f.Sections[i] = s
449	}
450
451	if len(f.Sections) == 0 {
452		return f, nil
453	}
454
455	// Load section header string table.
456	shstrtab, err := f.Sections[shstrndx].Data()
457	if err != nil {
458		return nil, err
459	}
460	for i, s := range f.Sections {
461		var ok bool
462		s.Name, ok = getString(shstrtab, int(names[i]))
463		if !ok {
464			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
465		}
466	}
467
468	return f, nil
469}
470
471// getSymbols returns a slice of Symbols from parsing the symbol table
472// with the given type, along with the associated string table.
473func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
474	switch f.Class {
475	case ELFCLASS64:
476		return f.getSymbols64(typ)
477
478	case ELFCLASS32:
479		return f.getSymbols32(typ)
480	}
481
482	return nil, nil, errors.New("not implemented")
483}
484
485// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
486// if there is no such section in the File.
487var ErrNoSymbols = errors.New("no symbol section")
488
489func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
490	symtabSection := f.SectionByType(typ)
491	if symtabSection == nil {
492		return nil, nil, ErrNoSymbols
493	}
494
495	data, err := symtabSection.Data()
496	if err != nil {
497		return nil, nil, errors.New("cannot load symbol section")
498	}
499	symtab := bytes.NewReader(data)
500	if symtab.Len()%Sym32Size != 0 {
501		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
502	}
503
504	strdata, err := f.stringTable(symtabSection.Link)
505	if err != nil {
506		return nil, nil, errors.New("cannot load string table section")
507	}
508
509	// The first entry is all zeros.
510	var skip [Sym32Size]byte
511	symtab.Read(skip[:])
512
513	symbols := make([]Symbol, symtab.Len()/Sym32Size)
514
515	i := 0
516	var sym Sym32
517	for symtab.Len() > 0 {
518		binary.Read(symtab, f.ByteOrder, &sym)
519		str, _ := getString(strdata, int(sym.Name))
520		symbols[i].Name = str
521		symbols[i].Info = sym.Info
522		symbols[i].Other = sym.Other
523		symbols[i].Section = SectionIndex(sym.Shndx)
524		symbols[i].Value = uint64(sym.Value)
525		symbols[i].Size = uint64(sym.Size)
526		i++
527	}
528
529	return symbols, strdata, nil
530}
531
532func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
533	symtabSection := f.SectionByType(typ)
534	if symtabSection == nil {
535		return nil, nil, ErrNoSymbols
536	}
537
538	data, err := symtabSection.Data()
539	if err != nil {
540		return nil, nil, errors.New("cannot load symbol section")
541	}
542	symtab := bytes.NewReader(data)
543	if symtab.Len()%Sym64Size != 0 {
544		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
545	}
546
547	strdata, err := f.stringTable(symtabSection.Link)
548	if err != nil {
549		return nil, nil, errors.New("cannot load string table section")
550	}
551
552	// The first entry is all zeros.
553	var skip [Sym64Size]byte
554	symtab.Read(skip[:])
555
556	symbols := make([]Symbol, symtab.Len()/Sym64Size)
557
558	i := 0
559	var sym Sym64
560	for symtab.Len() > 0 {
561		binary.Read(symtab, f.ByteOrder, &sym)
562		str, _ := getString(strdata, int(sym.Name))
563		symbols[i].Name = str
564		symbols[i].Info = sym.Info
565		symbols[i].Other = sym.Other
566		symbols[i].Section = SectionIndex(sym.Shndx)
567		symbols[i].Value = sym.Value
568		symbols[i].Size = sym.Size
569		i++
570	}
571
572	return symbols, strdata, nil
573}
574
575// getString extracts a string from an ELF string table.
576func getString(section []byte, start int) (string, bool) {
577	if start < 0 || start >= len(section) {
578		return "", false
579	}
580
581	for end := start; end < len(section); end++ {
582		if section[end] == 0 {
583			return string(section[start:end]), true
584		}
585	}
586	return "", false
587}
588
589// Section returns a section with the given name, or nil if no such
590// section exists.
591func (f *File) Section(name string) *Section {
592	for _, s := range f.Sections {
593		if s.Name == name {
594			return s
595		}
596	}
597	return nil
598}
599
600// applyRelocations applies relocations to dst. rels is a relocations section
601// in REL or RELA format.
602func (f *File) applyRelocations(dst []byte, rels []byte) error {
603	switch {
604	case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
605		return f.applyRelocationsAMD64(dst, rels)
606	case f.Class == ELFCLASS32 && f.Machine == EM_386:
607		return f.applyRelocations386(dst, rels)
608	case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
609		return f.applyRelocationsARM(dst, rels)
610	case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
611		return f.applyRelocationsARM64(dst, rels)
612	case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
613		return f.applyRelocationsPPC(dst, rels)
614	case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
615		return f.applyRelocationsPPC64(dst, rels)
616	case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
617		return f.applyRelocationsMIPS(dst, rels)
618	case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
619		return f.applyRelocationsMIPS64(dst, rels)
620	case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:
621		return f.applyRelocationsRISCV64(dst, rels)
622	case f.Class == ELFCLASS64 && f.Machine == EM_S390:
623		return f.applyRelocationss390x(dst, rels)
624	case f.Class == ELFCLASS32 && (f.Machine == EM_SPARC || f.Machine == EM_SPARC32PLUS):
625		return f.applyRelocationsSPARC(dst, rels)
626	case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
627		return f.applyRelocationsSPARC64(dst, rels)
628	case f.Class == ELFCLASS64 && f.Machine == EM_ALPHA:
629		return f.applyRelocationsALPHA(dst, rels)
630	default:
631		return errors.New("applyRelocations: not implemented")
632	}
633}
634
635// relocSymbolTargetOK decides whether we should try to apply a
636// relocation to a DWARF data section, given a pointer to the symbol
637// targeted by the relocation. Most relocations in DWARF data tend to
638// be section-relative, but some target non-section symbols (for
639// example, low_PC attrs on subprogram or compilation unit DIEs that
640// target function symbols), and we need to include these as well.
641// Return value is a pair (X,Y) where X is a boolean indicating
642// whether the relocation is needed, and Y is the symbol value in the
643// case of a non-section relocation that needs to be applied.
644func relocSymbolTargetOK(sym *Symbol) (bool, uint64) {
645	if ST_TYPE(sym.Info) == STT_SECTION {
646		return true, 0
647	}
648	if sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE {
649		return true, sym.Value
650	}
651	return false, 0
652}
653
654func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
655	// 24 is the size of Rela64.
656	if len(rels)%24 != 0 {
657		return errors.New("length of relocation section is not a multiple of 24")
658	}
659
660	symbols, _, err := f.getSymbols(SHT_SYMTAB)
661	if err != nil {
662		return err
663	}
664
665	b := bytes.NewReader(rels)
666	var rela Rela64
667
668	for b.Len() > 0 {
669		binary.Read(b, f.ByteOrder, &rela)
670		symNo := rela.Info >> 32
671		t := R_X86_64(rela.Info & 0xffff)
672
673		if symNo == 0 || symNo > uint64(len(symbols)) {
674			continue
675		}
676		sym := &symbols[symNo-1]
677		needed, val := relocSymbolTargetOK(sym)
678		if !needed {
679			continue
680		}
681
682		// There are relocations, so this must be a normal
683		// object file.  The code below handles only basic relocations
684		// of the form S + A (symbol plus addend).
685
686		switch t {
687		case R_X86_64_64:
688			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
689				continue
690			}
691			val64 := val + uint64(rela.Addend)
692			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
693		case R_X86_64_32:
694			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
695				continue
696			}
697			val32 := uint32(val) + uint32(rela.Addend)
698			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
699		}
700	}
701
702	return nil
703}
704
705func (f *File) applyRelocations386(dst []byte, rels []byte) error {
706	// 8 is the size of Rel32.
707	if len(rels)%8 != 0 {
708		return errors.New("length of relocation section is not a multiple of 8")
709	}
710
711	symbols, _, err := f.getSymbols(SHT_SYMTAB)
712	if err != nil {
713		return err
714	}
715
716	b := bytes.NewReader(rels)
717	var rel Rel32
718
719	for b.Len() > 0 {
720		binary.Read(b, f.ByteOrder, &rel)
721		symNo := rel.Info >> 8
722		t := R_386(rel.Info & 0xff)
723
724		if symNo == 0 || symNo > uint32(len(symbols)) {
725			continue
726		}
727		sym := &symbols[symNo-1]
728
729		if t == R_386_32 {
730			if rel.Off+4 >= uint32(len(dst)) {
731				continue
732			}
733			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
734			val += uint32(sym.Value)
735			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
736		}
737	}
738
739	return nil
740}
741
742func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
743	// 8 is the size of Rel32.
744	if len(rels)%8 != 0 {
745		return errors.New("length of relocation section is not a multiple of 8")
746	}
747
748	symbols, _, err := f.getSymbols(SHT_SYMTAB)
749	if err != nil {
750		return err
751	}
752
753	b := bytes.NewReader(rels)
754	var rel Rel32
755
756	for b.Len() > 0 {
757		binary.Read(b, f.ByteOrder, &rel)
758		symNo := rel.Info >> 8
759		t := R_ARM(rel.Info & 0xff)
760
761		if symNo == 0 || symNo > uint32(len(symbols)) {
762			continue
763		}
764		sym := &symbols[symNo-1]
765
766		switch t {
767		case R_ARM_ABS32:
768			if rel.Off+4 >= uint32(len(dst)) {
769				continue
770			}
771			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
772			val += uint32(sym.Value)
773			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
774		}
775	}
776
777	return nil
778}
779
780func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
781	// 24 is the size of Rela64.
782	if len(rels)%24 != 0 {
783		return errors.New("length of relocation section is not a multiple of 24")
784	}
785
786	symbols, _, err := f.getSymbols(SHT_SYMTAB)
787	if err != nil {
788		return err
789	}
790
791	b := bytes.NewReader(rels)
792	var rela Rela64
793
794	for b.Len() > 0 {
795		binary.Read(b, f.ByteOrder, &rela)
796		symNo := rela.Info >> 32
797		t := R_AARCH64(rela.Info & 0xffff)
798
799		if symNo == 0 || symNo > uint64(len(symbols)) {
800			continue
801		}
802		sym := &symbols[symNo-1]
803		needed, val := relocSymbolTargetOK(sym)
804		if !needed {
805			continue
806		}
807
808		// There are relocations, so this must be a normal
809		// object file.  The code below handles only basic relocations
810		// of the form S + A (symbol plus addend).
811
812		switch t {
813		case R_AARCH64_ABS64:
814			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
815				continue
816			}
817			val64 := uint64(val) + uint64(rela.Addend)
818			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
819		case R_AARCH64_ABS32:
820			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
821				continue
822			}
823			val32 := uint32(val) + uint32(rela.Addend)
824			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
825		}
826	}
827
828	return nil
829}
830
831func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
832	// 12 is the size of Rela32.
833	if len(rels)%12 != 0 {
834		return errors.New("length of relocation section is not a multiple of 12")
835	}
836
837	symbols, _, err := f.getSymbols(SHT_SYMTAB)
838	if err != nil {
839		return err
840	}
841
842	b := bytes.NewReader(rels)
843	var rela Rela32
844
845	for b.Len() > 0 {
846		binary.Read(b, f.ByteOrder, &rela)
847		symNo := rela.Info >> 8
848		t := R_PPC(rela.Info & 0xff)
849
850		if symNo == 0 || symNo > uint32(len(symbols)) {
851			continue
852		}
853		sym := &symbols[symNo-1]
854		needed, val := relocSymbolTargetOK(sym)
855		if !needed {
856			continue
857		}
858
859		switch t {
860		case R_PPC_ADDR32:
861			if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
862				continue
863			}
864			val32 := uint32(val) + uint32(rela.Addend)
865			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
866		}
867	}
868
869	return nil
870}
871
872func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
873	// 24 is the size of Rela64.
874	if len(rels)%24 != 0 {
875		return errors.New("length of relocation section is not a multiple of 24")
876	}
877
878	symbols, _, err := f.getSymbols(SHT_SYMTAB)
879	if err != nil {
880		return err
881	}
882
883	b := bytes.NewReader(rels)
884	var rela Rela64
885
886	for b.Len() > 0 {
887		binary.Read(b, f.ByteOrder, &rela)
888		symNo := rela.Info >> 32
889		t := R_PPC64(rela.Info & 0xffff)
890
891		if symNo == 0 || symNo > uint64(len(symbols)) {
892			continue
893		}
894		sym := &symbols[symNo-1]
895		needed, val := relocSymbolTargetOK(sym)
896		if !needed {
897			continue
898		}
899
900		switch t {
901		case R_PPC64_ADDR64:
902			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
903				continue
904			}
905			val64 := val + uint64(rela.Addend)
906			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
907		case R_PPC64_ADDR32:
908			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
909				continue
910			}
911			val32 := uint32(val) + uint32(rela.Addend)
912			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
913		}
914	}
915
916	return nil
917}
918
919func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
920	// 8 is the size of Rel32.
921	if len(rels)%8 != 0 {
922		return errors.New("length of relocation section is not a multiple of 8")
923	}
924
925	symbols, _, err := f.getSymbols(SHT_SYMTAB)
926	if err != nil {
927		return err
928	}
929
930	b := bytes.NewReader(rels)
931	var rel Rel32
932
933	for b.Len() > 0 {
934		binary.Read(b, f.ByteOrder, &rel)
935		symNo := rel.Info >> 8
936		t := R_MIPS(rel.Info & 0xff)
937
938		if symNo == 0 || symNo > uint32(len(symbols)) {
939			continue
940		}
941		sym := &symbols[symNo-1]
942
943		switch t {
944		case R_MIPS_32:
945			if rel.Off+4 >= uint32(len(dst)) {
946				continue
947			}
948			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
949			val += uint32(sym.Value)
950			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
951		}
952	}
953
954	return nil
955}
956
957func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
958	// 24 is the size of Rela64.
959	if len(rels)%24 != 0 {
960		return errors.New("length of relocation section is not a multiple of 24")
961	}
962
963	symbols, _, err := f.getSymbols(SHT_SYMTAB)
964	if err != nil {
965		return err
966	}
967
968	b := bytes.NewReader(rels)
969	var rela Rela64
970
971	for b.Len() > 0 {
972		binary.Read(b, f.ByteOrder, &rela)
973		var symNo uint64
974		var t R_MIPS
975		if f.ByteOrder == binary.BigEndian {
976			symNo = rela.Info >> 32
977			t = R_MIPS(rela.Info & 0xff)
978		} else {
979			symNo = rela.Info & 0xffffffff
980			t = R_MIPS(rela.Info >> 56)
981		}
982
983		if symNo == 0 || symNo > uint64(len(symbols)) {
984			continue
985		}
986		sym := &symbols[symNo-1]
987		needed, val := relocSymbolTargetOK(sym)
988		if !needed {
989			continue
990		}
991
992		switch t {
993		case R_MIPS_64:
994			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
995				continue
996			}
997			val64 := val + uint64(rela.Addend)
998			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
999		case R_MIPS_32:
1000			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1001				continue
1002			}
1003			val32 := uint32(val) + uint32(rela.Addend)
1004			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1005		}
1006	}
1007
1008	return nil
1009}
1010
1011func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
1012	// 24 is the size of Rela64.
1013	if len(rels)%24 != 0 {
1014		return errors.New("length of relocation section is not a multiple of 24")
1015	}
1016
1017	symbols, _, err := f.getSymbols(SHT_SYMTAB)
1018	if err != nil {
1019		return err
1020	}
1021
1022	b := bytes.NewReader(rels)
1023	var rela Rela64
1024
1025	for b.Len() > 0 {
1026		binary.Read(b, f.ByteOrder, &rela)
1027		symNo := rela.Info >> 32
1028		t := R_RISCV(rela.Info & 0xffff)
1029
1030		if symNo == 0 || symNo > uint64(len(symbols)) {
1031			continue
1032		}
1033		sym := &symbols[symNo-1]
1034		needed, val := relocSymbolTargetOK(sym)
1035		if !needed {
1036			continue
1037		}
1038
1039		switch t {
1040		case R_RISCV_64:
1041			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1042				continue
1043			}
1044			val64 := val + uint64(rela.Addend)
1045			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1046		case R_RISCV_32:
1047			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1048				continue
1049			}
1050			val32 := uint32(val) + uint32(rela.Addend)
1051			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1052		}
1053	}
1054
1055	return nil
1056}
1057
1058func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
1059	// 24 is the size of Rela64.
1060	if len(rels)%24 != 0 {
1061		return errors.New("length of relocation section is not a multiple of 24")
1062	}
1063
1064	symbols, _, err := f.getSymbols(SHT_SYMTAB)
1065	if err != nil {
1066		return err
1067	}
1068
1069	b := bytes.NewReader(rels)
1070	var rela Rela64
1071
1072	for b.Len() > 0 {
1073		binary.Read(b, f.ByteOrder, &rela)
1074		symNo := rela.Info >> 32
1075		t := R_390(rela.Info & 0xffff)
1076
1077		if symNo == 0 || symNo > uint64(len(symbols)) {
1078			continue
1079		}
1080		sym := &symbols[symNo-1]
1081		needed, val := relocSymbolTargetOK(sym)
1082		if !needed {
1083			continue
1084		}
1085
1086		switch t {
1087		case R_390_64:
1088			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1089				continue
1090			}
1091			val64 := val + uint64(rela.Addend)
1092			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1093		case R_390_32:
1094			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1095				continue
1096			}
1097			val32 := uint32(val) + uint32(rela.Addend)
1098			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1099		}
1100	}
1101
1102	return nil
1103}
1104
1105func (f *File) applyRelocationsSPARC(dst []byte, rels []byte) error {
1106	// 12 is the size of Rela32.
1107	if len(rels)%12 != 0 {
1108		return errors.New("length of relocation section is not a multiple of 12")
1109	}
1110
1111	symbols, _, err := f.getSymbols(SHT_SYMTAB)
1112	if err != nil {
1113		return err
1114	}
1115
1116	b := bytes.NewReader(rels)
1117	var rela Rela32
1118
1119	for b.Len() > 0 {
1120		binary.Read(b, f.ByteOrder, &rela)
1121		symNo := rela.Info >> 32
1122		t := R_SPARC(rela.Info & 0xff)
1123
1124		if symNo == 0 || symNo > uint32(len(symbols)) {
1125			continue
1126		}
1127		sym := &symbols[symNo-1]
1128		if SymType(sym.Info&0xf) != STT_SECTION {
1129			// We don't handle non-section relocations for now.
1130			continue
1131		}
1132
1133		switch t {
1134		case R_SPARC_32, R_SPARC_UA32:
1135			if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
1136				continue
1137			}
1138			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
1139		}
1140	}
1141
1142	return nil
1143}
1144
1145func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1146	// 24 is the size of Rela64.
1147	if len(rels)%24 != 0 {
1148		return errors.New("length of relocation section is not a multiple of 24")
1149	}
1150
1151	symbols, _, err := f.getSymbols(SHT_SYMTAB)
1152	if err != nil {
1153		return err
1154	}
1155
1156	b := bytes.NewReader(rels)
1157	var rela Rela64
1158
1159	for b.Len() > 0 {
1160		binary.Read(b, f.ByteOrder, &rela)
1161		symNo := rela.Info >> 32
1162		t := R_SPARC(rela.Info & 0xff)
1163
1164		if symNo == 0 || symNo > uint64(len(symbols)) {
1165			continue
1166		}
1167		sym := &symbols[symNo-1]
1168		needed, val := relocSymbolTargetOK(sym)
1169		if !needed {
1170			continue
1171		}
1172
1173		switch t {
1174		case R_SPARC_64, R_SPARC_UA64:
1175			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1176				continue
1177			}
1178			val64 := val + uint64(rela.Addend)
1179			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1180		case R_SPARC_32, R_SPARC_UA32:
1181			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1182				continue
1183			}
1184			val32 := uint32(val) + uint32(rela.Addend)
1185			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1186		}
1187	}
1188
1189	return nil
1190}
1191
1192func (f *File) applyRelocationsALPHA(dst []byte, rels []byte) error {
1193	// 24 is the size of Rela64.
1194	if len(rels)%24 != 0 {
1195		return errors.New("length of relocation section is not a multiple of 24")
1196	}
1197
1198	symbols, _, err := f.getSymbols(SHT_SYMTAB)
1199	if err != nil {
1200		return err
1201	}
1202
1203	b := bytes.NewReader(rels)
1204	var rela Rela64
1205
1206	for b.Len() > 0 {
1207		binary.Read(b, f.ByteOrder, &rela)
1208		symNo := rela.Info >> 32
1209		t := R_ALPHA(rela.Info & 0xffff)
1210
1211		if symNo == 0 || symNo > uint64(len(symbols)) {
1212			continue
1213		}
1214		sym := &symbols[symNo-1]
1215		if SymType(sym.Info&0xf) != STT_SECTION {
1216			// We don't handle non-section relocations for now.
1217			continue
1218		}
1219
1220		// There are relocations, so this must be a normal
1221		// object file, and we only look at section symbols,
1222		// so we assume that the symbol value is 0.
1223
1224		switch t {
1225		case R_ALPHA_REFQUAD:
1226			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1227				continue
1228			}
1229			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
1230		case R_ALPHA_REFLONG:
1231			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1232				continue
1233			}
1234			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
1235		}
1236	}
1237
1238	return nil
1239}
1240
1241func (f *File) DWARF() (*dwarf.Data, error) {
1242	dwarfSuffix := func(s *Section) string {
1243		switch {
1244		case strings.HasPrefix(s.Name, ".debug_"):
1245			return s.Name[7:]
1246		case strings.HasPrefix(s.Name, ".zdebug_"):
1247			return s.Name[8:]
1248		default:
1249			return ""
1250		}
1251
1252	}
1253	// sectionData gets the data for s, checks its size, and
1254	// applies any applicable relations.
1255	sectionData := func(i int, s *Section) ([]byte, error) {
1256		b, err := s.Data()
1257		if err != nil && uint64(len(b)) < s.Size {
1258			return nil, err
1259		}
1260
1261		if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1262			dlen := binary.BigEndian.Uint64(b[4:12])
1263			dbuf := make([]byte, dlen)
1264			r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1265			if err != nil {
1266				return nil, err
1267			}
1268			if _, err := io.ReadFull(r, dbuf); err != nil {
1269				return nil, err
1270			}
1271			if err := r.Close(); err != nil {
1272				return nil, err
1273			}
1274			b = dbuf
1275		}
1276
1277		for _, r := range f.Sections {
1278			if r.Type != SHT_RELA && r.Type != SHT_REL {
1279				continue
1280			}
1281			if int(r.Info) != i {
1282				continue
1283			}
1284			rd, err := r.Data()
1285			if err != nil {
1286				return nil, err
1287			}
1288			err = f.applyRelocations(b, rd)
1289			if err != nil {
1290				return nil, err
1291			}
1292		}
1293		return b, nil
1294	}
1295
1296	// There are many DWARf sections, but these are the ones
1297	// the debug/dwarf package started with.
1298	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1299	for i, s := range f.Sections {
1300		suffix := dwarfSuffix(s)
1301		if suffix == "" {
1302			continue
1303		}
1304		if _, ok := dat[suffix]; !ok {
1305			continue
1306		}
1307		b, err := sectionData(i, s)
1308		if err != nil {
1309			return nil, err
1310		}
1311		dat[suffix] = b
1312	}
1313
1314	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1315	if err != nil {
1316		return nil, err
1317	}
1318
1319	// Look for DWARF4 .debug_types sections and DWARF5 sections.
1320	for i, s := range f.Sections {
1321		suffix := dwarfSuffix(s)
1322		if suffix == "" {
1323			continue
1324		}
1325		if _, ok := dat[suffix]; ok {
1326			// Already handled.
1327			continue
1328		}
1329
1330		b, err := sectionData(i, s)
1331		if err != nil {
1332			return nil, err
1333		}
1334
1335		if suffix == "types" {
1336			if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
1337				return nil, err
1338			}
1339		} else {
1340			if err := d.AddSection(".debug_"+suffix, b); err != nil {
1341				return nil, err
1342			}
1343		}
1344	}
1345
1346	return d, nil
1347}
1348
1349// Symbols returns the symbol table for f. The symbols will be listed in the order
1350// they appear in f.
1351//
1352// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
1353// After retrieving the symbols as symtab, an externally supplied index x
1354// corresponds to symtab[x-1], not symtab[x].
1355func (f *File) Symbols() ([]Symbol, error) {
1356	sym, _, err := f.getSymbols(SHT_SYMTAB)
1357	return sym, err
1358}
1359
1360// DynamicSymbols returns the dynamic symbol table for f. The symbols
1361// will be listed in the order they appear in f.
1362//
1363// If f has a symbol version table, the returned Symbols will have
1364// initialized Version and Library fields.
1365//
1366// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
1367// After retrieving the symbols as symtab, an externally supplied index x
1368// corresponds to symtab[x-1], not symtab[x].
1369func (f *File) DynamicSymbols() ([]Symbol, error) {
1370	sym, str, err := f.getSymbols(SHT_DYNSYM)
1371	if err != nil {
1372		return nil, err
1373	}
1374	if f.gnuVersionInit(str) {
1375		for i := range sym {
1376			sym[i].Library, sym[i].Version = f.gnuVersion(i)
1377		}
1378	}
1379	return sym, nil
1380}
1381
1382type ImportedSymbol struct {
1383	Name    string
1384	Version string
1385	Library string
1386}
1387
1388// ImportedSymbols returns the names of all symbols
1389// referred to by the binary f that are expected to be
1390// satisfied by other libraries at dynamic load time.
1391// It does not return weak symbols.
1392func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1393	sym, str, err := f.getSymbols(SHT_DYNSYM)
1394	if err != nil {
1395		return nil, err
1396	}
1397	f.gnuVersionInit(str)
1398	var all []ImportedSymbol
1399	for i, s := range sym {
1400		if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1401			all = append(all, ImportedSymbol{Name: s.Name})
1402			sym := &all[len(all)-1]
1403			sym.Library, sym.Version = f.gnuVersion(i)
1404		}
1405	}
1406	return all, nil
1407}
1408
1409type verneed struct {
1410	File string
1411	Name string
1412}
1413
1414// gnuVersionInit parses the GNU version tables
1415// for use by calls to gnuVersion.
1416func (f *File) gnuVersionInit(str []byte) bool {
1417	if f.gnuNeed != nil {
1418		// Already initialized
1419		return true
1420	}
1421
1422	// Accumulate verneed information.
1423	vn := f.SectionByType(SHT_GNU_VERNEED)
1424	if vn == nil {
1425		return false
1426	}
1427	d, _ := vn.Data()
1428
1429	var need []verneed
1430	i := 0
1431	for {
1432		if i+16 > len(d) {
1433			break
1434		}
1435		vers := f.ByteOrder.Uint16(d[i : i+2])
1436		if vers != 1 {
1437			break
1438		}
1439		cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1440		fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1441		aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1442		next := f.ByteOrder.Uint32(d[i+12 : i+16])
1443		file, _ := getString(str, int(fileoff))
1444
1445		var name string
1446		j := i + int(aux)
1447		for c := 0; c < int(cnt); c++ {
1448			if j+16 > len(d) {
1449				break
1450			}
1451			// hash := f.ByteOrder.Uint32(d[j:j+4])
1452			// flags := f.ByteOrder.Uint16(d[j+4:j+6])
1453			other := f.ByteOrder.Uint16(d[j+6 : j+8])
1454			nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1455			next := f.ByteOrder.Uint32(d[j+12 : j+16])
1456			name, _ = getString(str, int(nameoff))
1457			ndx := int(other)
1458			if ndx >= len(need) {
1459				a := make([]verneed, 2*(ndx+1))
1460				copy(a, need)
1461				need = a
1462			}
1463
1464			need[ndx] = verneed{file, name}
1465			if next == 0 {
1466				break
1467			}
1468			j += int(next)
1469		}
1470
1471		if next == 0 {
1472			break
1473		}
1474		i += int(next)
1475	}
1476
1477	// Versym parallels symbol table, indexing into verneed.
1478	vs := f.SectionByType(SHT_GNU_VERSYM)
1479	if vs == nil {
1480		return false
1481	}
1482	d, _ = vs.Data()
1483
1484	f.gnuNeed = need
1485	f.gnuVersym = d
1486	return true
1487}
1488
1489// gnuVersion adds Library and Version information to sym,
1490// which came from offset i of the symbol table.
1491func (f *File) gnuVersion(i int) (library string, version string) {
1492	// Each entry is two bytes.
1493	i = (i + 1) * 2
1494	if i >= len(f.gnuVersym) {
1495		return
1496	}
1497	j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
1498	if j < 2 || j >= len(f.gnuNeed) {
1499		return
1500	}
1501	n := &f.gnuNeed[j]
1502	return n.File, n.Name
1503}
1504
1505// ImportedLibraries returns the names of all libraries
1506// referred to by the binary f that are expected to be
1507// linked with the binary at dynamic link time.
1508func (f *File) ImportedLibraries() ([]string, error) {
1509	return f.DynString(DT_NEEDED)
1510}
1511
1512// DynString returns the strings listed for the given tag in the file's dynamic
1513// section.
1514//
1515// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
1516// DT_RUNPATH.
1517func (f *File) DynString(tag DynTag) ([]string, error) {
1518	switch tag {
1519	case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1520	default:
1521		return nil, fmt.Errorf("non-string-valued tag %v", tag)
1522	}
1523	ds := f.SectionByType(SHT_DYNAMIC)
1524	if ds == nil {
1525		// not dynamic, so no libraries
1526		return nil, nil
1527	}
1528	d, err := ds.Data()
1529	if err != nil {
1530		return nil, err
1531	}
1532	str, err := f.stringTable(ds.Link)
1533	if err != nil {
1534		return nil, err
1535	}
1536	var all []string
1537	for len(d) > 0 {
1538		var t DynTag
1539		var v uint64
1540		switch f.Class {
1541		case ELFCLASS32:
1542			t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1543			v = uint64(f.ByteOrder.Uint32(d[4:8]))
1544			d = d[8:]
1545		case ELFCLASS64:
1546			t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1547			v = f.ByteOrder.Uint64(d[8:16])
1548			d = d[16:]
1549		}
1550		if t == tag {
1551			s, ok := getString(str, int(v))
1552			if ok {
1553				all = append(all, s)
1554			}
1555		}
1556	}
1557	return all, nil
1558}
1559