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