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