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