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