github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 "internal/zstd" 27 "io" 28 "os" 29 "strings" 30 ) 31 32 // seekStart, seekCurrent, seekEnd are copies of 33 // io.SeekStart, io.SeekCurrent, and io.SeekEnd. 34 // We can't use the ones from package io because 35 // we want this code to build with Go 1.4 during 36 // cmd/dist bootstrap. 37 const ( 38 seekStart int = 0 39 seekCurrent int = 1 40 seekEnd int = 2 41 ) 42 43 // TODO: error reporting detail 44 45 /* 46 * Internal ELF representation 47 */ 48 49 // A FileHeader represents an ELF file header. 50 type FileHeader struct { 51 Class Class 52 Data Data 53 Version Version 54 OSABI OSABI 55 ABIVersion uint8 56 ByteOrder binary.ByteOrder 57 Type Type 58 Machine Machine 59 Entry uint64 60 } 61 62 // A File represents an open ELF file. 63 type File struct { 64 FileHeader 65 Sections []*Section 66 Progs []*Prog 67 closer io.Closer 68 gnuNeed []verneed 69 gnuVersym []byte 70 } 71 72 // A SectionHeader represents a single ELF section header. 73 type SectionHeader struct { 74 Name string 75 Type SectionType 76 Flags SectionFlag 77 Addr uint64 78 Offset uint64 79 Size uint64 80 Link uint32 81 Info uint32 82 Addralign uint64 83 Entsize uint64 84 85 // FileSize is the size of this section in the file in bytes. 86 // If a section is compressed, FileSize is the size of the 87 // compressed data, while Size (above) is the size of the 88 // uncompressed data. 89 FileSize uint64 90 } 91 92 // A Section represents a single section in an ELF file. 93 type Section struct { 94 SectionHeader 95 96 // Embed ReaderAt for ReadAt method. 97 // Do not embed SectionReader directly 98 // to avoid having Read and Seek. 99 // If a client wants Read and Seek it must use 100 // Open() to avoid fighting over the seek offset 101 // with other clients. 102 // 103 // ReaderAt may be nil if the section is not easily available 104 // in a random-access form. For example, a compressed section 105 // may have a nil ReaderAt. 106 io.ReaderAt 107 sr *io.SectionReader 108 109 compressionType CompressionType 110 compressionOffset int64 111 } 112 113 // Data reads and returns the contents of the ELF section. 114 // Even if the section is stored compressed in the ELF file, 115 // Data returns uncompressed data. 116 // 117 // For an SHT_NOBITS section, Data always returns a non-nil error. 118 func (s *Section) Data() ([]byte, error) { 119 return saferio.ReadData(s.Open(), s.Size) 120 } 121 122 // stringTable reads and returns the string table given by the 123 // specified link value. 124 func (f *File) stringTable(link uint32) ([]byte, error) { 125 if link <= 0 || link >= uint32(len(f.Sections)) { 126 return nil, errors.New("section has invalid string table link") 127 } 128 return f.Sections[link].Data() 129 } 130 131 // Open returns a new ReadSeeker reading the ELF section. 132 // Even if the section is stored compressed in the ELF file, 133 // the ReadSeeker reads uncompressed data. 134 // 135 // For an SHT_NOBITS section, all calls to the opened reader 136 // will return a non-nil error. 137 func (s *Section) Open() io.ReadSeeker { 138 if s.Type == SHT_NOBITS { 139 return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size)) 140 } 141 142 var zrd func(io.Reader) (io.ReadCloser, error) 143 if s.Flags&SHF_COMPRESSED == 0 { 144 145 if !strings.HasPrefix(s.Name, ".zdebug") { 146 return io.NewSectionReader(s.sr, 0, 1<<63-1) 147 } 148 149 b := make([]byte, 12) 150 n, _ := s.sr.ReadAt(b, 0) 151 if n != 12 || string(b[:4]) != "ZLIB" { 152 return io.NewSectionReader(s.sr, 0, 1<<63-1) 153 } 154 155 s.compressionOffset = 12 156 s.compressionType = COMPRESS_ZLIB 157 s.Size = binary.BigEndian.Uint64(b[4:12]) 158 zrd = zlib.NewReader 159 160 } else if s.Flags&SHF_ALLOC != 0 { 161 return errorReader{&FormatError{int64(s.Offset), 162 "SHF_COMPRESSED applies only to non-allocable sections", s.compressionType}} 163 } 164 165 switch s.compressionType { 166 case COMPRESS_ZLIB: 167 zrd = zlib.NewReader 168 case COMPRESS_ZSTD: 169 zrd = func(r io.Reader) (io.ReadCloser, error) { 170 return io.NopCloser(zstd.NewReader(r)), nil 171 } 172 } 173 174 if zrd == nil { 175 return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}} 176 } 177 178 return &readSeekerFromReader{ 179 reset: func() (io.Reader, error) { 180 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset) 181 return zrd(fr) 182 }, 183 size: int64(s.Size), 184 } 185 } 186 187 // A ProgHeader represents a single ELF program header. 188 type ProgHeader struct { 189 Type ProgType 190 Flags ProgFlag 191 Off uint64 192 Vaddr uint64 193 Paddr uint64 194 Filesz uint64 195 Memsz uint64 196 Align uint64 197 } 198 199 // A Prog represents a single ELF program header in an ELF binary. 200 type Prog struct { 201 ProgHeader 202 203 // Embed ReaderAt for ReadAt method. 204 // Do not embed SectionReader directly 205 // to avoid having Read and Seek. 206 // If a client wants Read and Seek it must use 207 // Open() to avoid fighting over the seek offset 208 // with other clients. 209 io.ReaderAt 210 sr *io.SectionReader 211 } 212 213 // Open returns a new ReadSeeker reading the ELF program body. 214 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } 215 216 // A Symbol represents an entry in an ELF symbol table section. 217 type Symbol struct { 218 Name string 219 Info, Other byte 220 Section SectionIndex 221 Value, Size uint64 222 223 // Version and Library are present only for the dynamic symbol 224 // table. 225 Version string 226 Library string 227 } 228 229 /* 230 * ELF reader 231 */ 232 233 type FormatError struct { 234 off int64 235 msg string 236 val any 237 } 238 239 func (e *FormatError) Error() string { 240 msg := e.msg 241 if e.val != nil { 242 msg += fmt.Sprintf(" '%v' ", e.val) 243 } 244 msg += fmt.Sprintf("in record at byte %#x", e.off) 245 return msg 246 } 247 248 // Open opens the named file using os.Open and prepares it for use as an ELF binary. 249 func Open(name string) (*File, error) { 250 f, err := os.Open(name) 251 if err != nil { 252 return nil, err 253 } 254 ff, err := NewFile(f) 255 if err != nil { 256 f.Close() 257 return nil, err 258 } 259 ff.closer = f 260 return ff, nil 261 } 262 263 // Close closes the File. 264 // If the File was created using NewFile directly instead of Open, 265 // Close has no effect. 266 func (f *File) Close() error { 267 var err error 268 if f.closer != nil { 269 err = f.closer.Close() 270 f.closer = nil 271 } 272 return err 273 } 274 275 // SectionByType returns the first section in f with the 276 // given type, or nil if there is no such section. 277 func (f *File) SectionByType(typ SectionType) *Section { 278 for _, s := range f.Sections { 279 if s.Type == typ { 280 return s 281 } 282 } 283 return nil 284 } 285 286 // NewFile creates a new File for accessing an ELF binary in an underlying reader. 287 // The ELF binary is expected to start at position 0 in the ReaderAt. 288 func NewFile(r io.ReaderAt) (*File, error) { 289 sr := io.NewSectionReader(r, 0, 1<<63-1) 290 // Read and decode ELF identifier 291 var ident [16]uint8 292 if _, err := r.ReadAt(ident[0:], 0); err != nil { 293 return nil, err 294 } 295 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 296 return nil, &FormatError{0, "bad magic number", ident[0:4]} 297 } 298 299 f := new(File) 300 f.Class = Class(ident[EI_CLASS]) 301 switch f.Class { 302 case ELFCLASS32: 303 case ELFCLASS64: 304 // ok 305 default: 306 return nil, &FormatError{0, "unknown ELF class", f.Class} 307 } 308 309 f.Data = Data(ident[EI_DATA]) 310 switch f.Data { 311 case ELFDATA2LSB: 312 f.ByteOrder = binary.LittleEndian 313 case ELFDATA2MSB: 314 f.ByteOrder = binary.BigEndian 315 default: 316 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 317 } 318 319 f.Version = Version(ident[EI_VERSION]) 320 if f.Version != EV_CURRENT { 321 return nil, &FormatError{0, "unknown ELF version", f.Version} 322 } 323 324 f.OSABI = OSABI(ident[EI_OSABI]) 325 f.ABIVersion = ident[EI_ABIVERSION] 326 327 // Read ELF file header 328 var phoff int64 329 var phentsize, phnum int 330 var shoff int64 331 var shentsize, shnum, shstrndx int 332 switch f.Class { 333 case ELFCLASS32: 334 hdr := new(Header32) 335 sr.Seek(0, seekStart) 336 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 337 return nil, err 338 } 339 f.Type = Type(hdr.Type) 340 f.Machine = Machine(hdr.Machine) 341 f.Entry = uint64(hdr.Entry) 342 if v := Version(hdr.Version); v != f.Version { 343 return nil, &FormatError{0, "mismatched ELF version", v} 344 } 345 phoff = int64(hdr.Phoff) 346 phentsize = int(hdr.Phentsize) 347 phnum = int(hdr.Phnum) 348 shoff = int64(hdr.Shoff) 349 shentsize = int(hdr.Shentsize) 350 shnum = int(hdr.Shnum) 351 shstrndx = int(hdr.Shstrndx) 352 case ELFCLASS64: 353 hdr := new(Header64) 354 sr.Seek(0, seekStart) 355 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 356 return nil, err 357 } 358 f.Type = Type(hdr.Type) 359 f.Machine = Machine(hdr.Machine) 360 f.Entry = hdr.Entry 361 if v := Version(hdr.Version); v != f.Version { 362 return nil, &FormatError{0, "mismatched ELF version", v} 363 } 364 phoff = int64(hdr.Phoff) 365 phentsize = int(hdr.Phentsize) 366 phnum = int(hdr.Phnum) 367 shoff = int64(hdr.Shoff) 368 shentsize = int(hdr.Shentsize) 369 shnum = int(hdr.Shnum) 370 shstrndx = int(hdr.Shstrndx) 371 } 372 373 if shoff < 0 { 374 return nil, &FormatError{0, "invalid shoff", shoff} 375 } 376 if phoff < 0 { 377 return nil, &FormatError{0, "invalid phoff", phoff} 378 } 379 380 if shoff == 0 && shnum != 0 { 381 return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum} 382 } 383 384 if shnum > 0 && shstrndx >= shnum { 385 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 386 } 387 388 var wantPhentsize, wantShentsize int 389 switch f.Class { 390 case ELFCLASS32: 391 wantPhentsize = 8 * 4 392 wantShentsize = 10 * 4 393 case ELFCLASS64: 394 wantPhentsize = 2*4 + 6*8 395 wantShentsize = 4*4 + 6*8 396 } 397 if phnum > 0 && phentsize < wantPhentsize { 398 return nil, &FormatError{0, "invalid ELF phentsize", phentsize} 399 } 400 401 // Read program headers 402 f.Progs = make([]*Prog, phnum) 403 for i := 0; i < phnum; i++ { 404 off := phoff + int64(i)*int64(phentsize) 405 sr.Seek(off, seekStart) 406 p := new(Prog) 407 switch f.Class { 408 case ELFCLASS32: 409 ph := new(Prog32) 410 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 411 return nil, err 412 } 413 p.ProgHeader = ProgHeader{ 414 Type: ProgType(ph.Type), 415 Flags: ProgFlag(ph.Flags), 416 Off: uint64(ph.Off), 417 Vaddr: uint64(ph.Vaddr), 418 Paddr: uint64(ph.Paddr), 419 Filesz: uint64(ph.Filesz), 420 Memsz: uint64(ph.Memsz), 421 Align: uint64(ph.Align), 422 } 423 case ELFCLASS64: 424 ph := new(Prog64) 425 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 426 return nil, err 427 } 428 p.ProgHeader = ProgHeader{ 429 Type: ProgType(ph.Type), 430 Flags: ProgFlag(ph.Flags), 431 Off: ph.Off, 432 Vaddr: ph.Vaddr, 433 Paddr: ph.Paddr, 434 Filesz: ph.Filesz, 435 Memsz: ph.Memsz, 436 Align: ph.Align, 437 } 438 } 439 if int64(p.Off) < 0 { 440 return nil, &FormatError{off, "invalid program header offset", p.Off} 441 } 442 if int64(p.Filesz) < 0 { 443 return nil, &FormatError{off, "invalid program header file size", p.Filesz} 444 } 445 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 446 p.ReaderAt = p.sr 447 f.Progs[i] = p 448 } 449 450 // If the number of sections is greater than or equal to SHN_LORESERVE 451 // (0xff00), shnum has the value zero and the actual number of section 452 // header table entries is contained in the sh_size field of the section 453 // header at index 0. 454 if shoff > 0 && shnum == 0 { 455 var typ, link uint32 456 sr.Seek(shoff, seekStart) 457 switch f.Class { 458 case ELFCLASS32: 459 sh := new(Section32) 460 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 461 return nil, err 462 } 463 shnum = int(sh.Size) 464 typ = sh.Type 465 link = sh.Link 466 case ELFCLASS64: 467 sh := new(Section64) 468 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 469 return nil, err 470 } 471 shnum = int(sh.Size) 472 typ = sh.Type 473 link = sh.Link 474 } 475 if SectionType(typ) != SHT_NULL { 476 return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)} 477 } 478 479 if shnum < int(SHN_LORESERVE) { 480 return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum} 481 } 482 483 // If the section name string table section index is greater than or 484 // equal to SHN_LORESERVE (0xff00), this member has the value 485 // SHN_XINDEX (0xffff) and the actual index of the section name 486 // string table section is contained in the sh_link field of the 487 // section header at index 0. 488 if shstrndx == int(SHN_XINDEX) { 489 shstrndx = int(link) 490 if shstrndx < int(SHN_LORESERVE) { 491 return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx} 492 } 493 } 494 } 495 496 if shnum > 0 && shentsize < wantShentsize { 497 return nil, &FormatError{0, "invalid ELF shentsize", shentsize} 498 } 499 500 // Read section headers 501 c := saferio.SliceCap((*Section)(nil), uint64(shnum)) 502 if c < 0 { 503 return nil, &FormatError{0, "too many sections", shnum} 504 } 505 f.Sections = make([]*Section, 0, c) 506 names := make([]uint32, 0, c) 507 for i := 0; i < shnum; i++ { 508 off := shoff + int64(i)*int64(shentsize) 509 sr.Seek(off, seekStart) 510 s := new(Section) 511 switch f.Class { 512 case ELFCLASS32: 513 sh := new(Section32) 514 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 515 return nil, err 516 } 517 names = append(names, sh.Name) 518 s.SectionHeader = SectionHeader{ 519 Type: SectionType(sh.Type), 520 Flags: SectionFlag(sh.Flags), 521 Addr: uint64(sh.Addr), 522 Offset: uint64(sh.Off), 523 FileSize: uint64(sh.Size), 524 Link: sh.Link, 525 Info: sh.Info, 526 Addralign: uint64(sh.Addralign), 527 Entsize: uint64(sh.Entsize), 528 } 529 case ELFCLASS64: 530 sh := new(Section64) 531 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 532 return nil, err 533 } 534 names = append(names, sh.Name) 535 s.SectionHeader = SectionHeader{ 536 Type: SectionType(sh.Type), 537 Flags: SectionFlag(sh.Flags), 538 Offset: sh.Off, 539 FileSize: sh.Size, 540 Addr: sh.Addr, 541 Link: sh.Link, 542 Info: sh.Info, 543 Addralign: sh.Addralign, 544 Entsize: sh.Entsize, 545 } 546 } 547 if int64(s.Offset) < 0 { 548 return nil, &FormatError{off, "invalid section offset", int64(s.Offset)} 549 } 550 if int64(s.FileSize) < 0 { 551 return nil, &FormatError{off, "invalid section size", int64(s.FileSize)} 552 } 553 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) 554 555 if s.Flags&SHF_COMPRESSED == 0 { 556 s.ReaderAt = s.sr 557 s.Size = s.FileSize 558 } else { 559 // Read the compression header. 560 switch f.Class { 561 case ELFCLASS32: 562 ch := new(Chdr32) 563 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 564 return nil, err 565 } 566 s.compressionType = CompressionType(ch.Type) 567 s.Size = uint64(ch.Size) 568 s.Addralign = uint64(ch.Addralign) 569 s.compressionOffset = int64(binary.Size(ch)) 570 case ELFCLASS64: 571 ch := new(Chdr64) 572 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 573 return nil, err 574 } 575 s.compressionType = CompressionType(ch.Type) 576 s.Size = ch.Size 577 s.Addralign = ch.Addralign 578 s.compressionOffset = int64(binary.Size(ch)) 579 } 580 } 581 582 f.Sections = append(f.Sections, s) 583 } 584 585 if len(f.Sections) == 0 { 586 return f, nil 587 } 588 589 // Load section header string table. 590 if shstrndx == 0 { 591 // If the file has no section name string table, 592 // shstrndx holds the value SHN_UNDEF (0). 593 return f, nil 594 } 595 shstr := f.Sections[shstrndx] 596 if shstr.Type != SHT_STRTAB { 597 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type} 598 } 599 shstrtab, err := shstr.Data() 600 if err != nil { 601 return nil, err 602 } 603 for i, s := range f.Sections { 604 var ok bool 605 s.Name, ok = getString(shstrtab, int(names[i])) 606 if !ok { 607 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 608 } 609 } 610 611 return f, nil 612 } 613 614 // getSymbols returns a slice of Symbols from parsing the symbol table 615 // with the given type, along with the associated string table. 616 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 617 switch f.Class { 618 case ELFCLASS64: 619 return f.getSymbols64(typ) 620 621 case ELFCLASS32: 622 return f.getSymbols32(typ) 623 } 624 625 return nil, nil, errors.New("not implemented") 626 } 627 628 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols 629 // if there is no such section in the File. 630 var ErrNoSymbols = errors.New("no symbol section") 631 632 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 633 symtabSection := f.SectionByType(typ) 634 if symtabSection == nil { 635 return nil, nil, ErrNoSymbols 636 } 637 638 data, err := symtabSection.Data() 639 if err != nil { 640 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 641 } 642 symtab := bytes.NewReader(data) 643 if symtab.Len()%Sym32Size != 0 { 644 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 645 } 646 647 strdata, err := f.stringTable(symtabSection.Link) 648 if err != nil { 649 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 650 } 651 652 // The first entry is all zeros. 653 var skip [Sym32Size]byte 654 symtab.Read(skip[:]) 655 656 symbols := make([]Symbol, symtab.Len()/Sym32Size) 657 658 i := 0 659 var sym Sym32 660 for symtab.Len() > 0 { 661 binary.Read(symtab, f.ByteOrder, &sym) 662 str, _ := getString(strdata, int(sym.Name)) 663 symbols[i].Name = str 664 symbols[i].Info = sym.Info 665 symbols[i].Other = sym.Other 666 symbols[i].Section = SectionIndex(sym.Shndx) 667 symbols[i].Value = uint64(sym.Value) 668 symbols[i].Size = uint64(sym.Size) 669 i++ 670 } 671 672 return symbols, strdata, nil 673 } 674 675 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 676 symtabSection := f.SectionByType(typ) 677 if symtabSection == nil { 678 return nil, nil, ErrNoSymbols 679 } 680 681 data, err := symtabSection.Data() 682 if err != nil { 683 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err) 684 } 685 symtab := bytes.NewReader(data) 686 if symtab.Len()%Sym64Size != 0 { 687 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 688 } 689 690 strdata, err := f.stringTable(symtabSection.Link) 691 if err != nil { 692 return nil, nil, fmt.Errorf("cannot load string table section: %w", err) 693 } 694 695 // The first entry is all zeros. 696 var skip [Sym64Size]byte 697 symtab.Read(skip[:]) 698 699 symbols := make([]Symbol, symtab.Len()/Sym64Size) 700 701 i := 0 702 var sym Sym64 703 for symtab.Len() > 0 { 704 binary.Read(symtab, f.ByteOrder, &sym) 705 str, _ := getString(strdata, int(sym.Name)) 706 symbols[i].Name = str 707 symbols[i].Info = sym.Info 708 symbols[i].Other = sym.Other 709 symbols[i].Section = SectionIndex(sym.Shndx) 710 symbols[i].Value = sym.Value 711 symbols[i].Size = sym.Size 712 i++ 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 Symbols will have 1438 // initialized Version and Library fields. 1439 // 1440 // For compatibility with Symbols, 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 str, err := f.stringTable(ds.Link) 1611 if err != nil { 1612 return nil, err 1613 } 1614 var all []string 1615 for len(d) > 0 { 1616 var t DynTag 1617 var v uint64 1618 switch f.Class { 1619 case ELFCLASS32: 1620 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1621 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1622 d = d[8:] 1623 case ELFCLASS64: 1624 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1625 v = f.ByteOrder.Uint64(d[8:16]) 1626 d = d[16:] 1627 } 1628 if t == tag { 1629 s, ok := getString(str, int(v)) 1630 if ok { 1631 all = append(all, s) 1632 } 1633 } 1634 } 1635 return all, nil 1636 } 1637 1638 // DynValue returns the values listed for the given tag in the file's dynamic 1639 // section. 1640 func (f *File) DynValue(tag DynTag) ([]uint64, error) { 1641 ds := f.SectionByType(SHT_DYNAMIC) 1642 if ds == nil { 1643 return nil, nil 1644 } 1645 d, err := ds.Data() 1646 if err != nil { 1647 return nil, err 1648 } 1649 1650 // Parse the .dynamic section as a string of bytes. 1651 var vals []uint64 1652 for len(d) > 0 { 1653 var t DynTag 1654 var v uint64 1655 switch f.Class { 1656 case ELFCLASS32: 1657 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1658 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1659 d = d[8:] 1660 case ELFCLASS64: 1661 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1662 v = f.ByteOrder.Uint64(d[8:16]) 1663 d = d[16:] 1664 } 1665 if t == tag { 1666 vals = append(vals, v) 1667 } 1668 } 1669 return vals, nil 1670 } 1671 1672 type nobitsSectionReader struct{} 1673 1674 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) { 1675 return 0, errors.New("unexpected read from SHT_NOBITS section") 1676 }