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