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