github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/debug/elf/file.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // 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 176 /* 177 * ELF reader 178 */ 179 180 type FormatError struct { 181 off int64 182 msg string 183 val interface{} 184 } 185 186 func (e *FormatError) Error() string { 187 msg := e.msg 188 if e.val != nil { 189 msg += fmt.Sprintf(" '%v' ", e.val) 190 } 191 msg += fmt.Sprintf("in record at byte %#x", e.off) 192 return msg 193 } 194 195 // Open opens the named file using os.Open and prepares it for use as an ELF binary. 196 func Open(name string) (*File, error) { 197 f, err := os.Open(name) 198 if err != nil { 199 return nil, err 200 } 201 ff, err := NewFile(f) 202 if err != nil { 203 f.Close() 204 return nil, err 205 } 206 ff.closer = f 207 return ff, nil 208 } 209 210 // Close closes the File. 211 // If the File was created using NewFile directly instead of Open, 212 // Close has no effect. 213 func (f *File) Close() error { 214 var err error 215 if f.closer != nil { 216 err = f.closer.Close() 217 f.closer = nil 218 } 219 return err 220 } 221 222 // SectionByType returns the first section in f with the 223 // given type, or nil if there is no such section. 224 func (f *File) SectionByType(typ SectionType) *Section { 225 for _, s := range f.Sections { 226 if s.Type == typ { 227 return s 228 } 229 } 230 return nil 231 } 232 233 // NewFile creates a new File for accessing an ELF binary in an underlying reader. 234 // The ELF binary is expected to start at position 0 in the ReaderAt. 235 func NewFile(r io.ReaderAt) (*File, error) { 236 sr := io.NewSectionReader(r, 0, 1<<63-1) 237 // Read and decode ELF identifier 238 var ident [16]uint8 239 if _, err := r.ReadAt(ident[0:], 0); err != nil { 240 return nil, err 241 } 242 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 243 return nil, &FormatError{0, "bad magic number", ident[0:4]} 244 } 245 246 f := new(File) 247 f.Class = Class(ident[EI_CLASS]) 248 switch f.Class { 249 case ELFCLASS32: 250 case ELFCLASS64: 251 // ok 252 default: 253 return nil, &FormatError{0, "unknown ELF class", f.Class} 254 } 255 256 f.Data = Data(ident[EI_DATA]) 257 switch f.Data { 258 case ELFDATA2LSB: 259 f.ByteOrder = binary.LittleEndian 260 case ELFDATA2MSB: 261 f.ByteOrder = binary.BigEndian 262 default: 263 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 264 } 265 266 f.Version = Version(ident[EI_VERSION]) 267 if f.Version != EV_CURRENT { 268 return nil, &FormatError{0, "unknown ELF version", f.Version} 269 } 270 271 f.OSABI = OSABI(ident[EI_OSABI]) 272 f.ABIVersion = ident[EI_ABIVERSION] 273 274 // Read ELF file header 275 var phoff int64 276 var phentsize, phnum int 277 var shoff int64 278 var shentsize, shnum, shstrndx int 279 shstrndx = -1 280 switch f.Class { 281 case ELFCLASS32: 282 hdr := new(Header32) 283 sr.Seek(0, seekStart) 284 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 285 return nil, err 286 } 287 f.Type = Type(hdr.Type) 288 f.Machine = Machine(hdr.Machine) 289 f.Entry = uint64(hdr.Entry) 290 if v := Version(hdr.Version); v != f.Version { 291 return nil, &FormatError{0, "mismatched ELF version", v} 292 } 293 phoff = int64(hdr.Phoff) 294 phentsize = int(hdr.Phentsize) 295 phnum = int(hdr.Phnum) 296 shoff = int64(hdr.Shoff) 297 shentsize = int(hdr.Shentsize) 298 shnum = int(hdr.Shnum) 299 shstrndx = int(hdr.Shstrndx) 300 case ELFCLASS64: 301 hdr := new(Header64) 302 sr.Seek(0, seekStart) 303 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 304 return nil, err 305 } 306 f.Type = Type(hdr.Type) 307 f.Machine = Machine(hdr.Machine) 308 f.Entry = hdr.Entry 309 if v := Version(hdr.Version); v != f.Version { 310 return nil, &FormatError{0, "mismatched ELF version", v} 311 } 312 phoff = int64(hdr.Phoff) 313 phentsize = int(hdr.Phentsize) 314 phnum = int(hdr.Phnum) 315 shoff = int64(hdr.Shoff) 316 shentsize = int(hdr.Shentsize) 317 shnum = int(hdr.Shnum) 318 shstrndx = int(hdr.Shstrndx) 319 } 320 321 if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { 322 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 323 } 324 325 // Read program headers 326 f.Progs = make([]*Prog, phnum) 327 for i := 0; i < phnum; i++ { 328 off := phoff + int64(i)*int64(phentsize) 329 sr.Seek(off, seekStart) 330 p := new(Prog) 331 switch f.Class { 332 case ELFCLASS32: 333 ph := new(Prog32) 334 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 335 return nil, err 336 } 337 p.ProgHeader = ProgHeader{ 338 Type: ProgType(ph.Type), 339 Flags: ProgFlag(ph.Flags), 340 Off: uint64(ph.Off), 341 Vaddr: uint64(ph.Vaddr), 342 Paddr: uint64(ph.Paddr), 343 Filesz: uint64(ph.Filesz), 344 Memsz: uint64(ph.Memsz), 345 Align: uint64(ph.Align), 346 } 347 case ELFCLASS64: 348 ph := new(Prog64) 349 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 350 return nil, err 351 } 352 p.ProgHeader = ProgHeader{ 353 Type: ProgType(ph.Type), 354 Flags: ProgFlag(ph.Flags), 355 Off: ph.Off, 356 Vaddr: ph.Vaddr, 357 Paddr: ph.Paddr, 358 Filesz: ph.Filesz, 359 Memsz: ph.Memsz, 360 Align: ph.Align, 361 } 362 } 363 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 364 p.ReaderAt = p.sr 365 f.Progs[i] = p 366 } 367 368 // Read section headers 369 f.Sections = make([]*Section, shnum) 370 names := make([]uint32, shnum) 371 for i := 0; i < shnum; i++ { 372 off := shoff + int64(i)*int64(shentsize) 373 sr.Seek(off, seekStart) 374 s := new(Section) 375 switch f.Class { 376 case ELFCLASS32: 377 sh := new(Section32) 378 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 379 return nil, err 380 } 381 names[i] = sh.Name 382 s.SectionHeader = SectionHeader{ 383 Type: SectionType(sh.Type), 384 Flags: SectionFlag(sh.Flags), 385 Addr: uint64(sh.Addr), 386 Offset: uint64(sh.Off), 387 FileSize: uint64(sh.Size), 388 Link: sh.Link, 389 Info: sh.Info, 390 Addralign: uint64(sh.Addralign), 391 Entsize: uint64(sh.Entsize), 392 } 393 case ELFCLASS64: 394 sh := new(Section64) 395 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 396 return nil, err 397 } 398 names[i] = sh.Name 399 s.SectionHeader = SectionHeader{ 400 Type: SectionType(sh.Type), 401 Flags: SectionFlag(sh.Flags), 402 Offset: sh.Off, 403 FileSize: sh.Size, 404 Addr: sh.Addr, 405 Link: sh.Link, 406 Info: sh.Info, 407 Addralign: sh.Addralign, 408 Entsize: sh.Entsize, 409 } 410 } 411 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) 412 413 if s.Flags&SHF_COMPRESSED == 0 { 414 s.ReaderAt = s.sr 415 s.Size = s.FileSize 416 } else { 417 // Read the compression header. 418 switch f.Class { 419 case ELFCLASS32: 420 ch := new(Chdr32) 421 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 422 return nil, err 423 } 424 s.compressionType = CompressionType(ch.Type) 425 s.Size = uint64(ch.Size) 426 s.Addralign = uint64(ch.Addralign) 427 s.compressionOffset = int64(binary.Size(ch)) 428 case ELFCLASS64: 429 ch := new(Chdr64) 430 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { 431 return nil, err 432 } 433 s.compressionType = CompressionType(ch.Type) 434 s.Size = ch.Size 435 s.Addralign = ch.Addralign 436 s.compressionOffset = int64(binary.Size(ch)) 437 } 438 } 439 440 f.Sections[i] = s 441 } 442 443 if len(f.Sections) == 0 { 444 return f, nil 445 } 446 447 // Load section header string table. 448 shstrtab, err := f.Sections[shstrndx].Data() 449 if err != nil { 450 return nil, err 451 } 452 for i, s := range f.Sections { 453 var ok bool 454 s.Name, ok = getString(shstrtab, int(names[i])) 455 if !ok { 456 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 457 } 458 } 459 460 return f, nil 461 } 462 463 // getSymbols returns a slice of Symbols from parsing the symbol table 464 // with the given type, along with the associated string table. 465 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 466 switch f.Class { 467 case ELFCLASS64: 468 return f.getSymbols64(typ) 469 470 case ELFCLASS32: 471 return f.getSymbols32(typ) 472 } 473 474 return nil, nil, errors.New("not implemented") 475 } 476 477 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols 478 // if there is no such section in the File. 479 var ErrNoSymbols = errors.New("no symbol section") 480 481 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 482 symtabSection := f.SectionByType(typ) 483 if symtabSection == nil { 484 return nil, nil, ErrNoSymbols 485 } 486 487 data, err := symtabSection.Data() 488 if err != nil { 489 return nil, nil, errors.New("cannot load symbol section") 490 } 491 symtab := bytes.NewReader(data) 492 if symtab.Len()%Sym32Size != 0 { 493 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 494 } 495 496 strdata, err := f.stringTable(symtabSection.Link) 497 if err != nil { 498 return nil, nil, errors.New("cannot load string table section") 499 } 500 501 // The first entry is all zeros. 502 var skip [Sym32Size]byte 503 symtab.Read(skip[:]) 504 505 symbols := make([]Symbol, symtab.Len()/Sym32Size) 506 507 i := 0 508 var sym Sym32 509 for symtab.Len() > 0 { 510 binary.Read(symtab, f.ByteOrder, &sym) 511 str, _ := getString(strdata, int(sym.Name)) 512 symbols[i].Name = str 513 symbols[i].Info = sym.Info 514 symbols[i].Other = sym.Other 515 symbols[i].Section = SectionIndex(sym.Shndx) 516 symbols[i].Value = uint64(sym.Value) 517 symbols[i].Size = uint64(sym.Size) 518 i++ 519 } 520 521 return symbols, strdata, nil 522 } 523 524 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 525 symtabSection := f.SectionByType(typ) 526 if symtabSection == nil { 527 return nil, nil, ErrNoSymbols 528 } 529 530 data, err := symtabSection.Data() 531 if err != nil { 532 return nil, nil, errors.New("cannot load symbol section") 533 } 534 symtab := bytes.NewReader(data) 535 if symtab.Len()%Sym64Size != 0 { 536 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 537 } 538 539 strdata, err := f.stringTable(symtabSection.Link) 540 if err != nil { 541 return nil, nil, errors.New("cannot load string table section") 542 } 543 544 // The first entry is all zeros. 545 var skip [Sym64Size]byte 546 symtab.Read(skip[:]) 547 548 symbols := make([]Symbol, symtab.Len()/Sym64Size) 549 550 i := 0 551 var sym Sym64 552 for symtab.Len() > 0 { 553 binary.Read(symtab, f.ByteOrder, &sym) 554 str, _ := getString(strdata, int(sym.Name)) 555 symbols[i].Name = str 556 symbols[i].Info = sym.Info 557 symbols[i].Other = sym.Other 558 symbols[i].Section = SectionIndex(sym.Shndx) 559 symbols[i].Value = sym.Value 560 symbols[i].Size = sym.Size 561 i++ 562 } 563 564 return symbols, strdata, nil 565 } 566 567 // getString extracts a string from an ELF string table. 568 func getString(section []byte, start int) (string, bool) { 569 if start < 0 || start >= len(section) { 570 return "", false 571 } 572 573 for end := start; end < len(section); end++ { 574 if section[end] == 0 { 575 return string(section[start:end]), true 576 } 577 } 578 return "", false 579 } 580 581 // Section returns a section with the given name, or nil if no such 582 // section exists. 583 func (f *File) Section(name string) *Section { 584 for _, s := range f.Sections { 585 if s.Name == name { 586 return s 587 } 588 } 589 return nil 590 } 591 592 // applyRelocations applies relocations to dst. rels is a relocations section 593 // in REL or RELA format. 594 func (f *File) applyRelocations(dst []byte, rels []byte) error { 595 switch { 596 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: 597 return f.applyRelocationsAMD64(dst, rels) 598 case f.Class == ELFCLASS32 && f.Machine == EM_386: 599 return f.applyRelocations386(dst, rels) 600 case f.Class == ELFCLASS32 && f.Machine == EM_ARM: 601 return f.applyRelocationsARM(dst, rels) 602 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: 603 return f.applyRelocationsARM64(dst, rels) 604 case f.Class == ELFCLASS32 && f.Machine == EM_PPC: 605 return f.applyRelocationsPPC(dst, rels) 606 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: 607 return f.applyRelocationsPPC64(dst, rels) 608 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: 609 return f.applyRelocationsMIPS(dst, rels) 610 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: 611 return f.applyRelocationsMIPS64(dst, rels) 612 case f.Class == ELFCLASS64 && f.Machine == EM_S390: 613 return f.applyRelocationss390x(dst, rels) 614 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: 615 return f.applyRelocationsSPARC64(dst, rels) 616 default: 617 return errors.New("applyRelocations: not implemented") 618 } 619 } 620 621 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 622 // 24 is the size of Rela64. 623 if len(rels)%24 != 0 { 624 return errors.New("length of relocation section is not a multiple of 24") 625 } 626 627 symbols, _, err := f.getSymbols(SHT_SYMTAB) 628 if err != nil { 629 return err 630 } 631 632 b := bytes.NewReader(rels) 633 var rela Rela64 634 635 for b.Len() > 0 { 636 binary.Read(b, f.ByteOrder, &rela) 637 symNo := rela.Info >> 32 638 t := R_X86_64(rela.Info & 0xffff) 639 640 if symNo == 0 || symNo > uint64(len(symbols)) { 641 continue 642 } 643 sym := &symbols[symNo-1] 644 if SymType(sym.Info&0xf) != STT_SECTION { 645 // We don't handle non-section relocations for now. 646 continue 647 } 648 649 // There are relocations, so this must be a normal 650 // object file, and we only look at section symbols, 651 // so we assume that the symbol value is 0. 652 653 switch t { 654 case R_X86_64_64: 655 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 656 continue 657 } 658 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 659 case R_X86_64_32: 660 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 661 continue 662 } 663 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 664 } 665 } 666 667 return nil 668 } 669 670 func (f *File) applyRelocations386(dst []byte, rels []byte) error { 671 // 8 is the size of Rel32. 672 if len(rels)%8 != 0 { 673 return errors.New("length of relocation section is not a multiple of 8") 674 } 675 676 symbols, _, err := f.getSymbols(SHT_SYMTAB) 677 if err != nil { 678 return err 679 } 680 681 b := bytes.NewReader(rels) 682 var rel Rel32 683 684 for b.Len() > 0 { 685 binary.Read(b, f.ByteOrder, &rel) 686 symNo := rel.Info >> 8 687 t := R_386(rel.Info & 0xff) 688 689 if symNo == 0 || symNo > uint32(len(symbols)) { 690 continue 691 } 692 sym := &symbols[symNo-1] 693 694 if t == R_386_32 { 695 if rel.Off+4 >= uint32(len(dst)) { 696 continue 697 } 698 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 699 val += uint32(sym.Value) 700 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 701 } 702 } 703 704 return nil 705 } 706 707 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 708 // 8 is the size of Rel32. 709 if len(rels)%8 != 0 { 710 return errors.New("length of relocation section is not a multiple of 8") 711 } 712 713 symbols, _, err := f.getSymbols(SHT_SYMTAB) 714 if err != nil { 715 return err 716 } 717 718 b := bytes.NewReader(rels) 719 var rel Rel32 720 721 for b.Len() > 0 { 722 binary.Read(b, f.ByteOrder, &rel) 723 symNo := rel.Info >> 8 724 t := R_ARM(rel.Info & 0xff) 725 726 if symNo == 0 || symNo > uint32(len(symbols)) { 727 continue 728 } 729 sym := &symbols[symNo-1] 730 731 switch t { 732 case R_ARM_ABS32: 733 if rel.Off+4 >= uint32(len(dst)) { 734 continue 735 } 736 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 737 val += uint32(sym.Value) 738 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 739 } 740 } 741 742 return nil 743 } 744 745 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 746 // 24 is the size of Rela64. 747 if len(rels)%24 != 0 { 748 return errors.New("length of relocation section is not a multiple of 24") 749 } 750 751 symbols, _, err := f.getSymbols(SHT_SYMTAB) 752 if err != nil { 753 return err 754 } 755 756 b := bytes.NewReader(rels) 757 var rela Rela64 758 759 for b.Len() > 0 { 760 binary.Read(b, f.ByteOrder, &rela) 761 symNo := rela.Info >> 32 762 t := R_AARCH64(rela.Info & 0xffff) 763 764 if symNo == 0 || symNo > uint64(len(symbols)) { 765 continue 766 } 767 sym := &symbols[symNo-1] 768 if SymType(sym.Info&0xf) != STT_SECTION { 769 // We don't handle non-section relocations for now. 770 continue 771 } 772 773 // There are relocations, so this must be a normal 774 // object file, and we only look at section symbols, 775 // so we assume that the symbol value is 0. 776 777 switch t { 778 case R_AARCH64_ABS64: 779 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 780 continue 781 } 782 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 783 case R_AARCH64_ABS32: 784 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 785 continue 786 } 787 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 788 } 789 } 790 791 return nil 792 } 793 794 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 795 // 12 is the size of Rela32. 796 if len(rels)%12 != 0 { 797 return errors.New("length of relocation section is not a multiple of 12") 798 } 799 800 symbols, _, err := f.getSymbols(SHT_SYMTAB) 801 if err != nil { 802 return err 803 } 804 805 b := bytes.NewReader(rels) 806 var rela Rela32 807 808 for b.Len() > 0 { 809 binary.Read(b, f.ByteOrder, &rela) 810 symNo := rela.Info >> 8 811 t := R_PPC(rela.Info & 0xff) 812 813 if symNo == 0 || symNo > uint32(len(symbols)) { 814 continue 815 } 816 sym := &symbols[symNo-1] 817 if SymType(sym.Info&0xf) != STT_SECTION { 818 // We don't handle non-section relocations for now. 819 continue 820 } 821 822 switch t { 823 case R_PPC_ADDR32: 824 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 825 continue 826 } 827 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 828 } 829 } 830 831 return nil 832 } 833 834 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 835 // 24 is the size of Rela64. 836 if len(rels)%24 != 0 { 837 return errors.New("length of relocation section is not a multiple of 24") 838 } 839 840 symbols, _, err := f.getSymbols(SHT_SYMTAB) 841 if err != nil { 842 return err 843 } 844 845 b := bytes.NewReader(rels) 846 var rela Rela64 847 848 for b.Len() > 0 { 849 binary.Read(b, f.ByteOrder, &rela) 850 symNo := rela.Info >> 32 851 t := R_PPC64(rela.Info & 0xffff) 852 853 if symNo == 0 || symNo > uint64(len(symbols)) { 854 continue 855 } 856 sym := &symbols[symNo-1] 857 if SymType(sym.Info&0xf) != STT_SECTION { 858 // We don't handle non-section relocations for now. 859 continue 860 } 861 862 switch t { 863 case R_PPC64_ADDR64: 864 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 865 continue 866 } 867 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 868 case R_PPC64_ADDR32: 869 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 870 continue 871 } 872 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 873 } 874 } 875 876 return nil 877 } 878 879 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { 880 // 8 is the size of Rel32. 881 if len(rels)%8 != 0 { 882 return errors.New("length of relocation section is not a multiple of 8") 883 } 884 885 symbols, _, err := f.getSymbols(SHT_SYMTAB) 886 if err != nil { 887 return err 888 } 889 890 b := bytes.NewReader(rels) 891 var rel Rel32 892 893 for b.Len() > 0 { 894 binary.Read(b, f.ByteOrder, &rel) 895 symNo := rel.Info >> 8 896 t := R_MIPS(rel.Info & 0xff) 897 898 if symNo == 0 || symNo > uint32(len(symbols)) { 899 continue 900 } 901 sym := &symbols[symNo-1] 902 903 switch t { 904 case R_MIPS_32: 905 if rel.Off+4 >= uint32(len(dst)) { 906 continue 907 } 908 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 909 val += uint32(sym.Value) 910 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 911 } 912 } 913 914 return nil 915 } 916 917 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { 918 // 24 is the size of Rela64. 919 if len(rels)%24 != 0 { 920 return errors.New("length of relocation section is not a multiple of 24") 921 } 922 923 symbols, _, err := f.getSymbols(SHT_SYMTAB) 924 if err != nil { 925 return err 926 } 927 928 b := bytes.NewReader(rels) 929 var rela Rela64 930 931 for b.Len() > 0 { 932 binary.Read(b, f.ByteOrder, &rela) 933 var symNo uint64 934 var t R_MIPS 935 if f.ByteOrder == binary.BigEndian { 936 symNo = rela.Info >> 32 937 t = R_MIPS(rela.Info & 0xff) 938 } else { 939 symNo = rela.Info & 0xffffffff 940 t = R_MIPS(rela.Info >> 56) 941 } 942 943 if symNo == 0 || symNo > uint64(len(symbols)) { 944 continue 945 } 946 sym := &symbols[symNo-1] 947 if SymType(sym.Info&0xf) != STT_SECTION { 948 // We don't handle non-section relocations for now. 949 continue 950 } 951 952 switch t { 953 case R_MIPS_64: 954 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 955 continue 956 } 957 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 958 case R_MIPS_32: 959 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 960 continue 961 } 962 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 963 } 964 } 965 966 return nil 967 } 968 969 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { 970 // 24 is the size of Rela64. 971 if len(rels)%24 != 0 { 972 return errors.New("length of relocation section is not a multiple of 24") 973 } 974 975 symbols, _, err := f.getSymbols(SHT_SYMTAB) 976 if err != nil { 977 return err 978 } 979 980 b := bytes.NewReader(rels) 981 var rela Rela64 982 983 for b.Len() > 0 { 984 binary.Read(b, f.ByteOrder, &rela) 985 symNo := rela.Info >> 32 986 t := R_390(rela.Info & 0xffff) 987 988 if symNo == 0 || symNo > uint64(len(symbols)) { 989 continue 990 } 991 sym := &symbols[symNo-1] 992 switch SymType(sym.Info & 0xf) { 993 case STT_SECTION, STT_NOTYPE: 994 break 995 default: 996 continue 997 } 998 999 switch t { 1000 case R_390_64: 1001 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1002 continue 1003 } 1004 val := sym.Value + uint64(rela.Addend) 1005 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) 1006 case R_390_32: 1007 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1008 continue 1009 } 1010 val := uint32(sym.Value) + uint32(rela.Addend) 1011 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) 1012 } 1013 } 1014 1015 return nil 1016 } 1017 1018 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { 1019 // 24 is the size of Rela64. 1020 if len(rels)%24 != 0 { 1021 return errors.New("length of relocation section is not a multiple of 24") 1022 } 1023 1024 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1025 if err != nil { 1026 return err 1027 } 1028 1029 b := bytes.NewReader(rels) 1030 var rela Rela64 1031 1032 for b.Len() > 0 { 1033 binary.Read(b, f.ByteOrder, &rela) 1034 symNo := rela.Info >> 32 1035 t := R_SPARC(rela.Info & 0xff) 1036 1037 if symNo == 0 || symNo > uint64(len(symbols)) { 1038 continue 1039 } 1040 sym := &symbols[symNo-1] 1041 if SymType(sym.Info&0xf) != STT_SECTION { 1042 // We don't handle non-section relocations for now. 1043 continue 1044 } 1045 1046 switch t { 1047 case R_SPARC_64, R_SPARC_UA64: 1048 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1049 continue 1050 } 1051 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 1052 case R_SPARC_32, R_SPARC_UA32: 1053 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1054 continue 1055 } 1056 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 1057 } 1058 } 1059 1060 return nil 1061 } 1062 1063 func (f *File) DWARF() (*dwarf.Data, error) { 1064 // sectionData gets the data for s, checks its size, and 1065 // applies any applicable relations. 1066 sectionData := func(i int, s *Section) ([]byte, error) { 1067 b, err := s.Data() 1068 if err != nil && uint64(len(b)) < s.Size { 1069 return nil, err 1070 } 1071 1072 if len(b) >= 12 && string(b[:4]) == "ZLIB" { 1073 dlen := binary.BigEndian.Uint64(b[4:12]) 1074 dbuf := make([]byte, dlen) 1075 r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) 1076 if err != nil { 1077 return nil, err 1078 } 1079 if _, err := io.ReadFull(r, dbuf); err != nil { 1080 return nil, err 1081 } 1082 if err := r.Close(); err != nil { 1083 return nil, err 1084 } 1085 b = dbuf 1086 } 1087 1088 for _, r := range f.Sections { 1089 if r.Type != SHT_RELA && r.Type != SHT_REL { 1090 continue 1091 } 1092 if int(r.Info) != i { 1093 continue 1094 } 1095 rd, err := r.Data() 1096 if err != nil { 1097 return nil, err 1098 } 1099 err = f.applyRelocations(b, rd) 1100 if err != nil { 1101 return nil, err 1102 } 1103 } 1104 return b, nil 1105 } 1106 1107 // There are many other DWARF sections, but these 1108 // are the ones the debug/dwarf package uses. 1109 // Don't bother loading others. 1110 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} 1111 for i, s := range f.Sections { 1112 suffix := "" 1113 switch { 1114 case strings.HasPrefix(s.Name, ".debug_"): 1115 suffix = s.Name[7:] 1116 case strings.HasPrefix(s.Name, ".zdebug_"): 1117 suffix = s.Name[8:] 1118 default: 1119 continue 1120 } 1121 if _, ok := dat[suffix]; !ok { 1122 continue 1123 } 1124 b, err := sectionData(i, s) 1125 if err != nil { 1126 return nil, err 1127 } 1128 dat[suffix] = b 1129 } 1130 1131 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) 1132 if err != nil { 1133 return nil, err 1134 } 1135 1136 // Look for DWARF4 .debug_types sections. 1137 for i, s := range f.Sections { 1138 if s.Name == ".debug_types" { 1139 b, err := sectionData(i, s) 1140 if err != nil { 1141 return nil, err 1142 } 1143 1144 err = d.AddTypes(fmt.Sprintf("types-%d", i), b) 1145 if err != nil { 1146 return nil, err 1147 } 1148 } 1149 } 1150 1151 return d, nil 1152 } 1153 1154 // Symbols returns the symbol table for f. The symbols will be listed in the order 1155 // they appear in f. 1156 // 1157 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 1158 // After retrieving the symbols as symtab, an externally supplied index x 1159 // corresponds to symtab[x-1], not symtab[x]. 1160 func (f *File) Symbols() ([]Symbol, error) { 1161 sym, _, err := f.getSymbols(SHT_SYMTAB) 1162 return sym, err 1163 } 1164 1165 // DynamicSymbols returns the dynamic symbol table for f. The symbols 1166 // will be listed in the order they appear in f. 1167 // 1168 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. 1169 // After retrieving the symbols as symtab, an externally supplied index x 1170 // corresponds to symtab[x-1], not symtab[x]. 1171 func (f *File) DynamicSymbols() ([]Symbol, error) { 1172 sym, _, err := f.getSymbols(SHT_DYNSYM) 1173 return sym, err 1174 } 1175 1176 type ImportedSymbol struct { 1177 Name string 1178 Version string 1179 Library string 1180 } 1181 1182 // ImportedSymbols returns the names of all symbols 1183 // referred to by the binary f that are expected to be 1184 // satisfied by other libraries at dynamic load time. 1185 // It does not return weak symbols. 1186 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 1187 sym, str, err := f.getSymbols(SHT_DYNSYM) 1188 if err != nil { 1189 return nil, err 1190 } 1191 f.gnuVersionInit(str) 1192 var all []ImportedSymbol 1193 for i, s := range sym { 1194 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 1195 all = append(all, ImportedSymbol{Name: s.Name}) 1196 f.gnuVersion(i, &all[len(all)-1]) 1197 } 1198 } 1199 return all, nil 1200 } 1201 1202 type verneed struct { 1203 File string 1204 Name string 1205 } 1206 1207 // gnuVersionInit parses the GNU version tables 1208 // for use by calls to gnuVersion. 1209 func (f *File) gnuVersionInit(str []byte) { 1210 // Accumulate verneed information. 1211 vn := f.SectionByType(SHT_GNU_VERNEED) 1212 if vn == nil { 1213 return 1214 } 1215 d, _ := vn.Data() 1216 1217 var need []verneed 1218 i := 0 1219 for { 1220 if i+16 > len(d) { 1221 break 1222 } 1223 vers := f.ByteOrder.Uint16(d[i : i+2]) 1224 if vers != 1 { 1225 break 1226 } 1227 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 1228 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 1229 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 1230 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 1231 file, _ := getString(str, int(fileoff)) 1232 1233 var name string 1234 j := i + int(aux) 1235 for c := 0; c < int(cnt); c++ { 1236 if j+16 > len(d) { 1237 break 1238 } 1239 // hash := f.ByteOrder.Uint32(d[j:j+4]) 1240 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 1241 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 1242 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 1243 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 1244 name, _ = getString(str, int(nameoff)) 1245 ndx := int(other) 1246 if ndx >= len(need) { 1247 a := make([]verneed, 2*(ndx+1)) 1248 copy(a, need) 1249 need = a 1250 } 1251 1252 need[ndx] = verneed{file, name} 1253 if next == 0 { 1254 break 1255 } 1256 j += int(next) 1257 } 1258 1259 if next == 0 { 1260 break 1261 } 1262 i += int(next) 1263 } 1264 1265 // Versym parallels symbol table, indexing into verneed. 1266 vs := f.SectionByType(SHT_GNU_VERSYM) 1267 if vs == nil { 1268 return 1269 } 1270 d, _ = vs.Data() 1271 1272 f.gnuNeed = need 1273 f.gnuVersym = d 1274 } 1275 1276 // gnuVersion adds Library and Version information to sym, 1277 // which came from offset i of the symbol table. 1278 func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 1279 // Each entry is two bytes. 1280 i = (i + 1) * 2 1281 if i >= len(f.gnuVersym) { 1282 return 1283 } 1284 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 1285 if j < 2 || j >= len(f.gnuNeed) { 1286 return 1287 } 1288 n := &f.gnuNeed[j] 1289 sym.Library = n.File 1290 sym.Version = n.Name 1291 } 1292 1293 // ImportedLibraries returns the names of all libraries 1294 // referred to by the binary f that are expected to be 1295 // linked with the binary at dynamic link time. 1296 func (f *File) ImportedLibraries() ([]string, error) { 1297 return f.DynString(DT_NEEDED) 1298 } 1299 1300 // DynString returns the strings listed for the given tag in the file's dynamic 1301 // section. 1302 // 1303 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 1304 // DT_RUNPATH. 1305 func (f *File) DynString(tag DynTag) ([]string, error) { 1306 switch tag { 1307 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1308 default: 1309 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1310 } 1311 ds := f.SectionByType(SHT_DYNAMIC) 1312 if ds == nil { 1313 // not dynamic, so no libraries 1314 return nil, nil 1315 } 1316 d, err := ds.Data() 1317 if err != nil { 1318 return nil, err 1319 } 1320 str, err := f.stringTable(ds.Link) 1321 if err != nil { 1322 return nil, err 1323 } 1324 var all []string 1325 for len(d) > 0 { 1326 var t DynTag 1327 var v uint64 1328 switch f.Class { 1329 case ELFCLASS32: 1330 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1331 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1332 d = d[8:] 1333 case ELFCLASS64: 1334 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1335 v = f.ByteOrder.Uint64(d[8:16]) 1336 d = d[16:] 1337 } 1338 if t == tag { 1339 s, ok := getString(str, int(v)) 1340 if ok { 1341 all = append(all, s) 1342 } 1343 } 1344 } 1345 return all, nil 1346 }