github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 "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 f.Sections = make([]*Section, shnum) 471 names := make([]uint32, shnum) 472 for i := 0; i < shnum; i++ { 473 off := shoff + int64(i)*int64(shentsize) 474 sr.Seek(off, seekStart) 475 s := new(Section) 476 switch f.Class { 477 case ELFCLASS32: 478 sh := new(Section32) 479 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 480 return nil, err 481 } 482 names[i] = sh.Name 483 s.SectionHeader = SectionHeader{ 484 Type: SectionType(sh.Type), 485 Flags: SectionFlag(sh.Flags), 486 Addr: uint64(sh.Addr), 487 Offset: uint64(sh.Off), 488 FileSize: uint64(sh.Size), 489 Link: sh.Link, 490 Info: sh.Info, 491 Addralign: uint64(sh.Addralign), 492 Entsize: uint64(sh.Entsize), 493 } 494 case ELFCLASS64: 495 sh := new(Section64) 496 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 497 return nil, err 498 } 499 names[i] = sh.Name 500 s.SectionHeader = SectionHeader{ 501 Type: SectionType(sh.Type), 502 Flags: SectionFlag(sh.Flags), 503 Offset: sh.Off, 504 FileSize: sh.Size, 505 Addr: sh.Addr, 506 Link: sh.Link, 507 Info: sh.Info, 508 Addralign: sh.Addralign, 509 Entsize: sh.Entsize, 510 } 511 } 512 if int64(s.Offset) < 0 { 513 return nil, &FormatError{off, "invalid section offset", int64(s.Offset)} 514 } 515 if int64(s.FileSize) < 0 { 516 return nil, &FormatError{off, "invalid section size", int64(s.FileSize)} 517 } 518 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) 519 520 if s.Flags&SHF_COMPRESSED == 0 { 521 s.ReaderAt = s.sr 522 s.Size = s.FileSize 523 } else { 524 // Read the compression header. 525 switch f.Class { 526 case ELFCLASS32: 527 ch := new(Chdr32) 528 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 529 return nil, err 530 } 531 s.compressionType = CompressionType(ch.Type) 532 s.Size = uint64(ch.Size) 533 s.Addralign = uint64(ch.Addralign) 534 s.compressionOffset = int64(binary.Size(ch)) 535 case ELFCLASS64: 536 ch := new(Chdr64) 537 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 538 return nil, err 539 } 540 s.compressionType = CompressionType(ch.Type) 541 s.Size = ch.Size 542 s.Addralign = ch.Addralign 543 s.compressionOffset = int64(binary.Size(ch)) 544 } 545 } 546 547 f.Sections[i] = s 548 } 549 550 if len(f.Sections) == 0 { 551 return f, nil 552 } 553 554 // Load section header string table. 555 if shstrndx == 0 { 556 // If the file has no section name string table, 557 // shstrndx holds the value SHN_UNDEF (0). 558 return f, nil 559 } 560 shstr := f.Sections[shstrndx] 561 if shstr.Type != SHT_STRTAB { 562 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type} 563 } 564 shstrtab, err := shstr.Data() 565 if err != nil { 566 return nil, err 567 } 568 for i, s := range f.Sections { 569 var ok bool 570 s.Name, ok = getString(shstrtab, int(names[i])) 571 if !ok { 572 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 573 } 574 } 575 576 return f, nil 577 } 578 579 // getSymbols returns a slice of Symbols from parsing the symbol table 580 // with the given type, along with the associated string table. 581 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 582 switch f.Class { 583 case ELFCLASS64: 584 return f.getSymbols64(typ) 585 586 case ELFCLASS32: 587 return f.getSymbols32(typ) 588 } 589 590 return nil, nil, errors.New("not implemented") 591 } 592 593 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols 594 // if there is no such section in the File. 595 var ErrNoSymbols = errors.New("no symbol section") 596 597 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 598 symtabSection := f.SectionByType(typ) 599 if symtabSection == nil { 600 return nil, nil, ErrNoSymbols 601 } 602 603 data, err := symtabSection.Data() 604 if err != nil { 605 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 606 } 607 symtab := bytes.NewReader(data) 608 if symtab.Len()%Sym32Size != 0 { 609 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 610 } 611 612 strdata, err := f.stringTable(symtabSection.Link) 613 if err != nil { 614 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 615 } 616 617 // The first entry is all zeros. 618 var skip [Sym32Size]byte 619 symtab.Read(skip[:]) 620 621 symbols := make([]Symbol, symtab.Len()/Sym32Size) 622 623 i := 0 624 var sym Sym32 625 for symtab.Len() > 0 { 626 binary.Read(symtab, f.ByteOrder, &sym) 627 str, _ := getString(strdata, int(sym.Name)) 628 symbols[i].Name = str 629 symbols[i].Info = sym.Info 630 symbols[i].Other = sym.Other 631 symbols[i].Section = SectionIndex(sym.Shndx) 632 symbols[i].Value = uint64(sym.Value) 633 symbols[i].Size = uint64(sym.Size) 634 i++ 635 } 636 637 return symbols, strdata, nil 638 } 639 640 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 641 symtabSection := f.SectionByType(typ) 642 if symtabSection == nil { 643 return nil, nil, ErrNoSymbols 644 } 645 646 data, err := symtabSection.Data() 647 if err != nil { 648 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 649 } 650 symtab := bytes.NewReader(data) 651 if symtab.Len()%Sym64Size != 0 { 652 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 653 } 654 655 strdata, err := f.stringTable(symtabSection.Link) 656 if err != nil { 657 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 658 } 659 660 // The first entry is all zeros. 661 var skip [Sym64Size]byte 662 symtab.Read(skip[:]) 663 664 symbols := make([]Symbol, symtab.Len()/Sym64Size) 665 666 i := 0 667 var sym Sym64 668 for symtab.Len() > 0 { 669 binary.Read(symtab, f.ByteOrder, &sym) 670 str, _ := getString(strdata, int(sym.Name)) 671 symbols[i].Name = str 672 symbols[i].Info = sym.Info 673 symbols[i].Other = sym.Other 674 symbols[i].Section = SectionIndex(sym.Shndx) 675 symbols[i].Value = sym.Value 676 symbols[i].Size = sym.Size 677 i++ 678 } 679 680 return symbols, strdata, nil 681 } 682 683 // getString extracts a string from an ELF string table. 684 func getString(section []byte, start int) (string, bool) { 685 if start < 0 || start >= len(section) { 686 return "", false 687 } 688 689 for end := start; end < len(section); end++ { 690 if section[end] == 0 { 691 return string(section[start:end]), true 692 } 693 } 694 return "", false 695 } 696 697 // Section returns a section with the given name, or nil if no such 698 // section exists. 699 func (f *File) Section(name string) *Section { 700 for _, s := range f.Sections { 701 if s.Name == name { 702 return s 703 } 704 } 705 return nil 706 } 707 708 // applyRelocations applies relocations to dst. rels is a relocations section 709 // in REL or RELA format. 710 func (f *File) applyRelocations(dst []byte, rels []byte) error { 711 switch { 712 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: 713 return f.applyRelocationsAMD64(dst, rels) 714 case f.Class == ELFCLASS32 && f.Machine == EM_386: 715 return f.applyRelocations386(dst, rels) 716 case f.Class == ELFCLASS32 && f.Machine == EM_ARM: 717 return f.applyRelocationsARM(dst, rels) 718 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: 719 return f.applyRelocationsARM64(dst, rels) 720 case f.Class == ELFCLASS32 && f.Machine == EM_PPC: 721 return f.applyRelocationsPPC(dst, rels) 722 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: 723 return f.applyRelocationsPPC64(dst, rels) 724 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: 725 return f.applyRelocationsMIPS(dst, rels) 726 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: 727 return f.applyRelocationsMIPS64(dst, rels) 728 case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH: 729 return f.applyRelocationsLOONG64(dst, rels) 730 case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: 731 return f.applyRelocationsRISCV64(dst, rels) 732 case f.Class == ELFCLASS64 && f.Machine == EM_S390: 733 return f.applyRelocationss390x(dst, rels) 734 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: 735 return f.applyRelocationsSPARC64(dst, rels) 736 default: 737 return errors.New("applyRelocations: not implemented") 738 } 739 } 740 741 // canApplyRelocation reports whether we should try to apply a 742 // relocation to a DWARF data section, given a pointer to the symbol 743 // targeted by the relocation. 744 // Most relocations in DWARF data tend to be section-relative, but 745 // some target non-section symbols (for example, low_PC attrs on 746 // subprogram or compilation unit DIEs that target function symbols). 747 func canApplyRelocation(sym *Symbol) bool { 748 return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE 749 } 750 751 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 752 // 24 is the size of Rela64. 753 if len(rels)%24 != 0 { 754 return errors.New("length of relocation section is not a multiple of 24") 755 } 756 757 symbols, _, err := f.getSymbols(SHT_SYMTAB) 758 if err != nil { 759 return err 760 } 761 762 b := bytes.NewReader(rels) 763 var rela Rela64 764 765 for b.Len() > 0 { 766 binary.Read(b, f.ByteOrder, &rela) 767 symNo := rela.Info >> 32 768 t := R_X86_64(rela.Info & 0xffff) 769 770 if symNo == 0 || symNo > uint64(len(symbols)) { 771 continue 772 } 773 sym := &symbols[symNo-1] 774 if !canApplyRelocation(sym) { 775 continue 776 } 777 778 // There are relocations, so this must be a normal 779 // object file. The code below handles only basic relocations 780 // of the form S + A (symbol plus addend). 781 782 switch t { 783 case R_X86_64_64: 784 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 785 continue 786 } 787 val64 := sym.Value + uint64(rela.Addend) 788 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 789 case R_X86_64_32: 790 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 791 continue 792 } 793 val32 := uint32(sym.Value) + uint32(rela.Addend) 794 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 795 } 796 } 797 798 return nil 799 } 800 801 func (f *File) applyRelocations386(dst []byte, rels []byte) error { 802 // 8 is the size of Rel32. 803 if len(rels)%8 != 0 { 804 return errors.New("length of relocation section is not a multiple of 8") 805 } 806 807 symbols, _, err := f.getSymbols(SHT_SYMTAB) 808 if err != nil { 809 return err 810 } 811 812 b := bytes.NewReader(rels) 813 var rel Rel32 814 815 for b.Len() > 0 { 816 binary.Read(b, f.ByteOrder, &rel) 817 symNo := rel.Info >> 8 818 t := R_386(rel.Info & 0xff) 819 820 if symNo == 0 || symNo > uint32(len(symbols)) { 821 continue 822 } 823 sym := &symbols[symNo-1] 824 825 if t == R_386_32 { 826 if rel.Off+4 >= uint32(len(dst)) { 827 continue 828 } 829 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 830 val += uint32(sym.Value) 831 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 832 } 833 } 834 835 return nil 836 } 837 838 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 839 // 8 is the size of Rel32. 840 if len(rels)%8 != 0 { 841 return errors.New("length of relocation section is not a multiple of 8") 842 } 843 844 symbols, _, err := f.getSymbols(SHT_SYMTAB) 845 if err != nil { 846 return err 847 } 848 849 b := bytes.NewReader(rels) 850 var rel Rel32 851 852 for b.Len() > 0 { 853 binary.Read(b, f.ByteOrder, &rel) 854 symNo := rel.Info >> 8 855 t := R_ARM(rel.Info & 0xff) 856 857 if symNo == 0 || symNo > uint32(len(symbols)) { 858 continue 859 } 860 sym := &symbols[symNo-1] 861 862 switch t { 863 case R_ARM_ABS32: 864 if rel.Off+4 >= uint32(len(dst)) { 865 continue 866 } 867 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 868 val += uint32(sym.Value) 869 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 870 } 871 } 872 873 return nil 874 } 875 876 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 877 // 24 is the size of Rela64. 878 if len(rels)%24 != 0 { 879 return errors.New("length of relocation section is not a multiple of 24") 880 } 881 882 symbols, _, err := f.getSymbols(SHT_SYMTAB) 883 if err != nil { 884 return err 885 } 886 887 b := bytes.NewReader(rels) 888 var rela Rela64 889 890 for b.Len() > 0 { 891 binary.Read(b, f.ByteOrder, &rela) 892 symNo := rela.Info >> 32 893 t := R_AARCH64(rela.Info & 0xffff) 894 895 if symNo == 0 || symNo > uint64(len(symbols)) { 896 continue 897 } 898 sym := &symbols[symNo-1] 899 if !canApplyRelocation(sym) { 900 continue 901 } 902 903 // There are relocations, so this must be a normal 904 // object file. The code below handles only basic relocations 905 // of the form S + A (symbol plus addend). 906 907 switch t { 908 case R_AARCH64_ABS64: 909 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 910 continue 911 } 912 val64 := sym.Value + uint64(rela.Addend) 913 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 914 case R_AARCH64_ABS32: 915 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 916 continue 917 } 918 val32 := uint32(sym.Value) + uint32(rela.Addend) 919 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 920 } 921 } 922 923 return nil 924 } 925 926 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 927 // 12 is the size of Rela32. 928 if len(rels)%12 != 0 { 929 return errors.New("length of relocation section is not a multiple of 12") 930 } 931 932 symbols, _, err := f.getSymbols(SHT_SYMTAB) 933 if err != nil { 934 return err 935 } 936 937 b := bytes.NewReader(rels) 938 var rela Rela32 939 940 for b.Len() > 0 { 941 binary.Read(b, f.ByteOrder, &rela) 942 symNo := rela.Info >> 8 943 t := R_PPC(rela.Info & 0xff) 944 945 if symNo == 0 || symNo > uint32(len(symbols)) { 946 continue 947 } 948 sym := &symbols[symNo-1] 949 if !canApplyRelocation(sym) { 950 continue 951 } 952 953 switch t { 954 case R_PPC_ADDR32: 955 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 956 continue 957 } 958 val32 := uint32(sym.Value) + uint32(rela.Addend) 959 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 960 } 961 } 962 963 return nil 964 } 965 966 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 967 // 24 is the size of Rela64. 968 if len(rels)%24 != 0 { 969 return errors.New("length of relocation section is not a multiple of 24") 970 } 971 972 symbols, _, err := f.getSymbols(SHT_SYMTAB) 973 if err != nil { 974 return err 975 } 976 977 b := bytes.NewReader(rels) 978 var rela Rela64 979 980 for b.Len() > 0 { 981 binary.Read(b, f.ByteOrder, &rela) 982 symNo := rela.Info >> 32 983 t := R_PPC64(rela.Info & 0xffff) 984 985 if symNo == 0 || symNo > uint64(len(symbols)) { 986 continue 987 } 988 sym := &symbols[symNo-1] 989 if !canApplyRelocation(sym) { 990 continue 991 } 992 993 switch t { 994 case R_PPC64_ADDR64: 995 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 996 continue 997 } 998 val64 := sym.Value + uint64(rela.Addend) 999 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1000 case R_PPC64_ADDR32: 1001 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1002 continue 1003 } 1004 val32 := uint32(sym.Value) + uint32(rela.Addend) 1005 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1006 } 1007 } 1008 1009 return nil 1010 } 1011 1012 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { 1013 // 8 is the size of Rel32. 1014 if len(rels)%8 != 0 { 1015 return errors.New("length of relocation section is not a multiple of 8") 1016 } 1017 1018 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1019 if err != nil { 1020 return err 1021 } 1022 1023 b := bytes.NewReader(rels) 1024 var rel Rel32 1025 1026 for b.Len() > 0 { 1027 binary.Read(b, f.ByteOrder, &rel) 1028 symNo := rel.Info >> 8 1029 t := R_MIPS(rel.Info & 0xff) 1030 1031 if symNo == 0 || symNo > uint32(len(symbols)) { 1032 continue 1033 } 1034 sym := &symbols[symNo-1] 1035 1036 switch t { 1037 case R_MIPS_32: 1038 if rel.Off+4 >= uint32(len(dst)) { 1039 continue 1040 } 1041 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 1042 val += uint32(sym.Value) 1043 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 1044 } 1045 } 1046 1047 return nil 1048 } 1049 1050 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { 1051 // 24 is the size of Rela64. 1052 if len(rels)%24 != 0 { 1053 return errors.New("length of relocation section is not a multiple of 24") 1054 } 1055 1056 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1057 if err != nil { 1058 return err 1059 } 1060 1061 b := bytes.NewReader(rels) 1062 var rela Rela64 1063 1064 for b.Len() > 0 { 1065 binary.Read(b, f.ByteOrder, &rela) 1066 var symNo uint64 1067 var t R_MIPS 1068 if f.ByteOrder == binary.BigEndian { 1069 symNo = rela.Info >> 32 1070 t = R_MIPS(rela.Info & 0xff) 1071 } else { 1072 symNo = rela.Info & 0xffffffff 1073 t = R_MIPS(rela.Info >> 56) 1074 } 1075 1076 if symNo == 0 || symNo > uint64(len(symbols)) { 1077 continue 1078 } 1079 sym := &symbols[symNo-1] 1080 if !canApplyRelocation(sym) { 1081 continue 1082 } 1083 1084 switch t { 1085 case R_MIPS_64: 1086 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1087 continue 1088 } 1089 val64 := sym.Value + uint64(rela.Addend) 1090 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1091 case R_MIPS_32: 1092 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1093 continue 1094 } 1095 val32 := uint32(sym.Value) + uint32(rela.Addend) 1096 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1097 } 1098 } 1099 1100 return nil 1101 } 1102 1103 func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error { 1104 // 24 is the size of Rela64. 1105 if len(rels)%24 != 0 { 1106 return errors.New("length of relocation section is not a multiple of 24") 1107 } 1108 1109 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1110 if err != nil { 1111 return err 1112 } 1113 1114 b := bytes.NewReader(rels) 1115 var rela Rela64 1116 1117 for b.Len() > 0 { 1118 binary.Read(b, f.ByteOrder, &rela) 1119 var symNo uint64 1120 var t R_LARCH 1121 symNo = rela.Info >> 32 1122 t = R_LARCH(rela.Info & 0xffff) 1123 1124 if symNo == 0 || symNo > uint64(len(symbols)) { 1125 continue 1126 } 1127 sym := &symbols[symNo-1] 1128 if !canApplyRelocation(sym) { 1129 continue 1130 } 1131 1132 switch t { 1133 case R_LARCH_64: 1134 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1135 continue 1136 } 1137 val64 := sym.Value + uint64(rela.Addend) 1138 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1139 case R_LARCH_32: 1140 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1141 continue 1142 } 1143 val32 := uint32(sym.Value) + uint32(rela.Addend) 1144 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1145 } 1146 } 1147 1148 return nil 1149 } 1150 1151 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { 1152 // 24 is the size of Rela64. 1153 if len(rels)%24 != 0 { 1154 return errors.New("length of relocation section is not a multiple of 24") 1155 } 1156 1157 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1158 if err != nil { 1159 return err 1160 } 1161 1162 b := bytes.NewReader(rels) 1163 var rela Rela64 1164 1165 for b.Len() > 0 { 1166 binary.Read(b, f.ByteOrder, &rela) 1167 symNo := rela.Info >> 32 1168 t := R_RISCV(rela.Info & 0xffff) 1169 1170 if symNo == 0 || symNo > uint64(len(symbols)) { 1171 continue 1172 } 1173 sym := &symbols[symNo-1] 1174 if !canApplyRelocation(sym) { 1175 continue 1176 } 1177 1178 switch t { 1179 case R_RISCV_64: 1180 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1181 continue 1182 } 1183 val64 := sym.Value + uint64(rela.Addend) 1184 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1185 case R_RISCV_32: 1186 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1187 continue 1188 } 1189 val32 := uint32(sym.Value) + uint32(rela.Addend) 1190 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1191 } 1192 } 1193 1194 return nil 1195 } 1196 1197 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { 1198 // 24 is the size of Rela64. 1199 if len(rels)%24 != 0 { 1200 return errors.New("length of relocation section is not a multiple of 24") 1201 } 1202 1203 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1204 if err != nil { 1205 return err 1206 } 1207 1208 b := bytes.NewReader(rels) 1209 var rela Rela64 1210 1211 for b.Len() > 0 { 1212 binary.Read(b, f.ByteOrder, &rela) 1213 symNo := rela.Info >> 32 1214 t := R_390(rela.Info & 0xffff) 1215 1216 if symNo == 0 || symNo > uint64(len(symbols)) { 1217 continue 1218 } 1219 sym := &symbols[symNo-1] 1220 if !canApplyRelocation(sym) { 1221 continue 1222 } 1223 1224 switch t { 1225 case R_390_64: 1226 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1227 continue 1228 } 1229 val64 := sym.Value + uint64(rela.Addend) 1230 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1231 case R_390_32: 1232 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1233 continue 1234 } 1235 val32 := uint32(sym.Value) + uint32(rela.Addend) 1236 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1237 } 1238 } 1239 1240 return nil 1241 } 1242 1243 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { 1244 // 24 is the size of Rela64. 1245 if len(rels)%24 != 0 { 1246 return errors.New("length of relocation section is not a multiple of 24") 1247 } 1248 1249 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1250 if err != nil { 1251 return err 1252 } 1253 1254 b := bytes.NewReader(rels) 1255 var rela Rela64 1256 1257 for b.Len() > 0 { 1258 binary.Read(b, f.ByteOrder, &rela) 1259 symNo := rela.Info >> 32 1260 t := R_SPARC(rela.Info & 0xff) 1261 1262 if symNo == 0 || symNo > uint64(len(symbols)) { 1263 continue 1264 } 1265 sym := &symbols[symNo-1] 1266 if !canApplyRelocation(sym) { 1267 continue 1268 } 1269 1270 switch t { 1271 case R_SPARC_64, R_SPARC_UA64: 1272 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1273 continue 1274 } 1275 val64 := sym.Value + uint64(rela.Addend) 1276 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) 1277 case R_SPARC_32, R_SPARC_UA32: 1278 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1279 continue 1280 } 1281 val32 := uint32(sym.Value) + uint32(rela.Addend) 1282 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) 1283 } 1284 } 1285 1286 return nil 1287 } 1288 1289 func (f *File) DWARF() (*dwarf.Data, error) { 1290 dwarfSuffix := func(s *Section) string { 1291 switch { 1292 case strings.HasPrefix(s.Name, ".debug_"): 1293 return s.Name[7:] 1294 case strings.HasPrefix(s.Name, ".zdebug_"): 1295 return s.Name[8:] 1296 default: 1297 return "" 1298 } 1299 1300 } 1301 // sectionData gets the data for s, checks its size, and 1302 // applies any applicable relations. 1303 sectionData := func(i int, s *Section) ([]byte, error) { 1304 b, err := s.Data() 1305 if err != nil && uint64(len(b)) < s.Size { 1306 return nil, err 1307 } 1308 var dlen uint64 1309 if len(b) >= 12 && string(b[:4]) == "ZLIB" { 1310 dlen = binary.BigEndian.Uint64(b[4:12]) 1311 s.compressionOffset = 12 1312 } 1313 if dlen == 0 && len(b) >= 12 && s.Flags&SHF_COMPRESSED != 0 && 1314 s.Flags&SHF_ALLOC == 0 && 1315 f.FileHeader.ByteOrder.Uint32(b[:]) == uint32(COMPRESS_ZLIB) { 1316 s.compressionType = COMPRESS_ZLIB 1317 switch f.FileHeader.Class { 1318 case ELFCLASS32: 1319 // Chdr32.Size offset 1320 dlen = uint64(f.FileHeader.ByteOrder.Uint32(b[4:])) 1321 s.compressionOffset = 12 1322 case ELFCLASS64: 1323 if len(b) < 24 { 1324 return nil, errors.New("invalid compress header 64") 1325 } 1326 // Chdr64.Size offset 1327 dlen = f.FileHeader.ByteOrder.Uint64(b[8:]) 1328 s.compressionOffset = 24 1329 default: 1330 return nil, fmt.Errorf("unsupported compress header:%s", f.FileHeader.Class) 1331 } 1332 } 1333 if dlen > 0 { 1334 r, err := zlib.NewReader(bytes.NewBuffer(b[s.compressionOffset:])) 1335 if err != nil { 1336 return nil, err 1337 } 1338 b, err = saferio.ReadData(r, dlen) 1339 if err != nil { 1340 return nil, err 1341 } 1342 if err := r.Close(); err != nil { 1343 return nil, err 1344 } 1345 } 1346 1347 if f.Type == ET_EXEC { 1348 // Do not apply relocations to DWARF sections for ET_EXEC binaries. 1349 // Relocations should already be applied, and .rela sections may 1350 // contain incorrect data. 1351 return b, nil 1352 } 1353 1354 for _, r := range f.Sections { 1355 if r.Type != SHT_RELA && r.Type != SHT_REL { 1356 continue 1357 } 1358 if int(r.Info) != i { 1359 continue 1360 } 1361 rd, err := r.Data() 1362 if err != nil { 1363 return nil, err 1364 } 1365 err = f.applyRelocations(b, rd) 1366 if err != nil { 1367 return nil, err 1368 } 1369 } 1370 return b, nil 1371 } 1372 1373 // There are many DWARf sections, but these are the ones 1374 // the debug/dwarf package started with. 1375 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} 1376 for i, s := range f.Sections { 1377 suffix := dwarfSuffix(s) 1378 if suffix == "" { 1379 continue 1380 } 1381 if _, ok := dat[suffix]; !ok { 1382 continue 1383 } 1384 b, err := sectionData(i, s) 1385 if err != nil { 1386 return nil, err 1387 } 1388 dat[suffix] = b 1389 } 1390 1391 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) 1392 if err != nil { 1393 return nil, err 1394 } 1395 1396 // Look for DWARF4 .debug_types sections and DWARF5 sections. 1397 for i, s := range f.Sections { 1398 suffix := dwarfSuffix(s) 1399 if suffix == "" { 1400 continue 1401 } 1402 if _, ok := dat[suffix]; ok { 1403 // Already handled. 1404 continue 1405 } 1406 1407 b, err := sectionData(i, s) 1408 if err != nil { 1409 return nil, err 1410 } 1411 1412 if suffix == "types" { 1413 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil { 1414 return nil, err 1415 } 1416 } else { 1417 if err := d.AddSection(".debug_"+suffix, b); err != nil { 1418 return nil, err 1419 } 1420 } 1421 } 1422 1423 return d, nil 1424 } 1425 1426 // Symbols returns the symbol table for f. The symbols will be listed in the order 1427 // they appear in f. 1428 // 1429 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 1430 // After retrieving the symbols as symtab, an externally supplied index x 1431 // corresponds to symtab[x-1], not symtab[x]. 1432 func (f *File) Symbols() ([]Symbol, error) { 1433 sym, _, err := f.getSymbols(SHT_SYMTAB) 1434 return sym, err 1435 } 1436 1437 // DynamicSymbols returns the dynamic symbol table for f. The symbols 1438 // will be listed in the order they appear in f. 1439 // 1440 // If f has a symbol version table, the returned Symbols will have 1441 // initialized Version and Library fields. 1442 // 1443 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. 1444 // After retrieving the symbols as symtab, an externally supplied index x 1445 // corresponds to symtab[x-1], not symtab[x]. 1446 func (f *File) DynamicSymbols() ([]Symbol, error) { 1447 sym, str, err := f.getSymbols(SHT_DYNSYM) 1448 if err != nil { 1449 return nil, err 1450 } 1451 if f.gnuVersionInit(str) { 1452 for i := range sym { 1453 sym[i].Library, sym[i].Version = f.gnuVersion(i) 1454 } 1455 } 1456 return sym, nil 1457 } 1458 1459 type ImportedSymbol struct { 1460 Name string 1461 Version string 1462 Library string 1463 } 1464 1465 // ImportedSymbols returns the names of all symbols 1466 // referred to by the binary f that are expected to be 1467 // satisfied by other libraries at dynamic load time. 1468 // It does not return weak symbols. 1469 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 1470 sym, str, err := f.getSymbols(SHT_DYNSYM) 1471 if err != nil { 1472 return nil, err 1473 } 1474 f.gnuVersionInit(str) 1475 var all []ImportedSymbol 1476 for i, s := range sym { 1477 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 1478 all = append(all, ImportedSymbol{Name: s.Name}) 1479 sym := &all[len(all)-1] 1480 sym.Library, sym.Version = f.gnuVersion(i) 1481 } 1482 } 1483 return all, nil 1484 } 1485 1486 type verneed struct { 1487 File string 1488 Name string 1489 } 1490 1491 // gnuVersionInit parses the GNU version tables 1492 // for use by calls to gnuVersion. 1493 func (f *File) gnuVersionInit(str []byte) bool { 1494 if f.gnuNeed != nil { 1495 // Already initialized 1496 return true 1497 } 1498 1499 // Accumulate verneed information. 1500 vn := f.SectionByType(SHT_GNU_VERNEED) 1501 if vn == nil { 1502 return false 1503 } 1504 d, _ := vn.Data() 1505 1506 var need []verneed 1507 i := 0 1508 for { 1509 if i+16 > len(d) { 1510 break 1511 } 1512 vers := f.ByteOrder.Uint16(d[i : i+2]) 1513 if vers != 1 { 1514 break 1515 } 1516 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 1517 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 1518 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 1519 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 1520 file, _ := getString(str, int(fileoff)) 1521 1522 var name string 1523 j := i + int(aux) 1524 for c := 0; c < int(cnt); c++ { 1525 if j+16 > len(d) { 1526 break 1527 } 1528 // hash := f.ByteOrder.Uint32(d[j:j+4]) 1529 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 1530 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 1531 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 1532 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 1533 name, _ = getString(str, int(nameoff)) 1534 ndx := int(other) 1535 if ndx >= len(need) { 1536 a := make([]verneed, 2*(ndx+1)) 1537 copy(a, need) 1538 need = a 1539 } 1540 1541 need[ndx] = verneed{file, name} 1542 if next == 0 { 1543 break 1544 } 1545 j += int(next) 1546 } 1547 1548 if next == 0 { 1549 break 1550 } 1551 i += int(next) 1552 } 1553 1554 // Versym parallels symbol table, indexing into verneed. 1555 vs := f.SectionByType(SHT_GNU_VERSYM) 1556 if vs == nil { 1557 return false 1558 } 1559 d, _ = vs.Data() 1560 1561 f.gnuNeed = need 1562 f.gnuVersym = d 1563 return true 1564 } 1565 1566 // gnuVersion adds Library and Version information to sym, 1567 // which came from offset i of the symbol table. 1568 func (f *File) gnuVersion(i int) (library string, version string) { 1569 // Each entry is two bytes. 1570 i = (i + 1) * 2 1571 if i >= len(f.gnuVersym) { 1572 return 1573 } 1574 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 1575 if j < 2 || j >= len(f.gnuNeed) { 1576 return 1577 } 1578 n := &f.gnuNeed[j] 1579 return n.File, n.Name 1580 } 1581 1582 // ImportedLibraries returns the names of all libraries 1583 // referred to by the binary f that are expected to be 1584 // linked with the binary at dynamic link time. 1585 func (f *File) ImportedLibraries() ([]string, error) { 1586 return f.DynString(DT_NEEDED) 1587 } 1588 1589 // DynString returns the strings listed for the given tag in the file's dynamic 1590 // section. 1591 // 1592 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 1593 // DT_RUNPATH. 1594 func (f *File) DynString(tag DynTag) ([]string, error) { 1595 switch tag { 1596 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1597 default: 1598 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1599 } 1600 ds := f.SectionByType(SHT_DYNAMIC) 1601 if ds == nil { 1602 // not dynamic, so no libraries 1603 return nil, nil 1604 } 1605 d, err := ds.Data() 1606 if err != nil { 1607 return nil, err 1608 } 1609 str, err := f.stringTable(ds.Link) 1610 if err != nil { 1611 return nil, err 1612 } 1613 var all []string 1614 for len(d) > 0 { 1615 var t DynTag 1616 var v uint64 1617 switch f.Class { 1618 case ELFCLASS32: 1619 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1620 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1621 d = d[8:] 1622 case ELFCLASS64: 1623 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1624 v = f.ByteOrder.Uint64(d[8:16]) 1625 d = d[16:] 1626 } 1627 if t == tag { 1628 s, ok := getString(str, int(v)) 1629 if ok { 1630 all = append(all, s) 1631 } 1632 } 1633 } 1634 return all, nil 1635 } 1636 1637 type nobitsSectionReader struct{} 1638 1639 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) { 1640 return 0, errors.New("unexpected read from SHT_NOBITS section") 1641 }