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. 6package elf 7 8import ( 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. 25const ( 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. 38type 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. 51type 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. 61type 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. 81type 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. 104func (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. 112func (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. 122func (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. 140type 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. 152type 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. 166func (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. 169type Symbol struct { 170 Name string 171 Info, Other byte 172 Section SectionIndex 173 Value, Size uint64 174} 175 176/* 177 * ELF reader 178 */ 179 180type FormatError struct { 181 off int64 182 msg string 183 val interface{} 184} 185 186func (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. 196func 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. 213func (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. 224func (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. 235func 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. 465func (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. 479var ErrNoSymbols = errors.New("no symbol section") 480 481func (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 524func (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. 568func 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. 583func (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. 594func (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 == ELFCLASS32 && (f.Machine == EM_SPARC || f.Machine == EM_SPARC32PLUS): 615 return f.applyRelocationsSPARC(dst, rels) 616 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: 617 return f.applyRelocationsSPARC64(dst, rels) 618 case f.Class == ELFCLASS64 && f.Machine == EM_ALPHA: 619 return f.applyRelocationsALPHA(dst, rels) 620 default: 621 return errors.New("applyRelocations: not implemented") 622 } 623} 624 625func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 626 // 24 is the size of Rela64. 627 if len(rels)%24 != 0 { 628 return errors.New("length of relocation section is not a multiple of 24") 629 } 630 631 symbols, _, err := f.getSymbols(SHT_SYMTAB) 632 if err != nil { 633 return err 634 } 635 636 b := bytes.NewReader(rels) 637 var rela Rela64 638 639 for b.Len() > 0 { 640 binary.Read(b, f.ByteOrder, &rela) 641 symNo := rela.Info >> 32 642 t := R_X86_64(rela.Info & 0xffff) 643 644 if symNo == 0 || symNo > uint64(len(symbols)) { 645 continue 646 } 647 sym := &symbols[symNo-1] 648 if SymType(sym.Info&0xf) != STT_SECTION { 649 // We don't handle non-section relocations for now. 650 continue 651 } 652 653 // There are relocations, so this must be a normal 654 // object file, and we only look at section symbols, 655 // so we assume that the symbol value is 0. 656 657 switch t { 658 case R_X86_64_64: 659 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 660 continue 661 } 662 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 663 case R_X86_64_32: 664 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 665 continue 666 } 667 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 668 } 669 } 670 671 return nil 672} 673 674func (f *File) applyRelocations386(dst []byte, rels []byte) error { 675 // 8 is the size of Rel32. 676 if len(rels)%8 != 0 { 677 return errors.New("length of relocation section is not a multiple of 8") 678 } 679 680 symbols, _, err := f.getSymbols(SHT_SYMTAB) 681 if err != nil { 682 return err 683 } 684 685 b := bytes.NewReader(rels) 686 var rel Rel32 687 688 for b.Len() > 0 { 689 binary.Read(b, f.ByteOrder, &rel) 690 symNo := rel.Info >> 8 691 t := R_386(rel.Info & 0xff) 692 693 if symNo == 0 || symNo > uint32(len(symbols)) { 694 continue 695 } 696 sym := &symbols[symNo-1] 697 698 if t == R_386_32 { 699 if rel.Off+4 >= uint32(len(dst)) { 700 continue 701 } 702 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 703 val += uint32(sym.Value) 704 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 705 } 706 } 707 708 return nil 709} 710 711func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 712 // 8 is the size of Rel32. 713 if len(rels)%8 != 0 { 714 return errors.New("length of relocation section is not a multiple of 8") 715 } 716 717 symbols, _, err := f.getSymbols(SHT_SYMTAB) 718 if err != nil { 719 return err 720 } 721 722 b := bytes.NewReader(rels) 723 var rel Rel32 724 725 for b.Len() > 0 { 726 binary.Read(b, f.ByteOrder, &rel) 727 symNo := rel.Info >> 8 728 t := R_ARM(rel.Info & 0xff) 729 730 if symNo == 0 || symNo > uint32(len(symbols)) { 731 continue 732 } 733 sym := &symbols[symNo-1] 734 735 switch t { 736 case R_ARM_ABS32: 737 if rel.Off+4 >= uint32(len(dst)) { 738 continue 739 } 740 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 741 val += uint32(sym.Value) 742 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 743 } 744 } 745 746 return nil 747} 748 749func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 750 // 24 is the size of Rela64. 751 if len(rels)%24 != 0 { 752 return errors.New("length of relocation section is not a multiple of 24") 753 } 754 755 symbols, _, err := f.getSymbols(SHT_SYMTAB) 756 if err != nil { 757 return err 758 } 759 760 b := bytes.NewReader(rels) 761 var rela Rela64 762 763 for b.Len() > 0 { 764 binary.Read(b, f.ByteOrder, &rela) 765 symNo := rela.Info >> 32 766 t := R_AARCH64(rela.Info & 0xffff) 767 768 if symNo == 0 || symNo > uint64(len(symbols)) { 769 continue 770 } 771 sym := &symbols[symNo-1] 772 if SymType(sym.Info&0xf) != STT_SECTION { 773 // We don't handle non-section relocations for now. 774 continue 775 } 776 777 // There are relocations, so this must be a normal 778 // object file, and we only look at section symbols, 779 // so we assume that the symbol value is 0. 780 781 switch t { 782 case R_AARCH64_ABS64: 783 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 784 continue 785 } 786 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 787 case R_AARCH64_ABS32: 788 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 789 continue 790 } 791 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 792 } 793 } 794 795 return nil 796} 797 798func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 799 // 12 is the size of Rela32. 800 if len(rels)%12 != 0 { 801 return errors.New("length of relocation section is not a multiple of 12") 802 } 803 804 symbols, _, err := f.getSymbols(SHT_SYMTAB) 805 if err != nil { 806 return err 807 } 808 809 b := bytes.NewReader(rels) 810 var rela Rela32 811 812 for b.Len() > 0 { 813 binary.Read(b, f.ByteOrder, &rela) 814 symNo := rela.Info >> 8 815 t := R_PPC(rela.Info & 0xff) 816 817 if symNo == 0 || symNo > uint32(len(symbols)) { 818 continue 819 } 820 sym := &symbols[symNo-1] 821 if SymType(sym.Info&0xf) != STT_SECTION { 822 // We don't handle non-section relocations for now. 823 continue 824 } 825 826 switch t { 827 case R_PPC_ADDR32: 828 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 829 continue 830 } 831 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 832 } 833 } 834 835 return nil 836} 837 838func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 839 // 24 is the size of Rela64. 840 if len(rels)%24 != 0 { 841 return errors.New("length of relocation section is not a multiple of 24") 842 } 843 844 symbols, _, err := f.getSymbols(SHT_SYMTAB) 845 if err != nil { 846 return err 847 } 848 849 b := bytes.NewReader(rels) 850 var rela Rela64 851 852 for b.Len() > 0 { 853 binary.Read(b, f.ByteOrder, &rela) 854 symNo := rela.Info >> 32 855 t := R_PPC64(rela.Info & 0xffff) 856 857 if symNo == 0 || symNo > uint64(len(symbols)) { 858 continue 859 } 860 sym := &symbols[symNo-1] 861 if SymType(sym.Info&0xf) != STT_SECTION { 862 // We don't handle non-section relocations for now. 863 continue 864 } 865 866 switch t { 867 case R_PPC64_ADDR64: 868 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 869 continue 870 } 871 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 872 case R_PPC64_ADDR32: 873 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 874 continue 875 } 876 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 877 } 878 } 879 880 return nil 881} 882 883func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { 884 // 8 is the size of Rel32. 885 if len(rels)%8 != 0 { 886 return errors.New("length of relocation section is not a multiple of 8") 887 } 888 889 symbols, _, err := f.getSymbols(SHT_SYMTAB) 890 if err != nil { 891 return err 892 } 893 894 b := bytes.NewReader(rels) 895 var rel Rel32 896 897 for b.Len() > 0 { 898 binary.Read(b, f.ByteOrder, &rel) 899 symNo := rel.Info >> 8 900 t := R_MIPS(rel.Info & 0xff) 901 902 if symNo == 0 || symNo > uint32(len(symbols)) { 903 continue 904 } 905 sym := &symbols[symNo-1] 906 907 switch t { 908 case R_MIPS_32: 909 if rel.Off+4 >= uint32(len(dst)) { 910 continue 911 } 912 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 913 val += uint32(sym.Value) 914 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 915 } 916 } 917 918 return nil 919} 920 921func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { 922 // 24 is the size of Rela64. 923 if len(rels)%24 != 0 { 924 return errors.New("length of relocation section is not a multiple of 24") 925 } 926 927 symbols, _, err := f.getSymbols(SHT_SYMTAB) 928 if err != nil { 929 return err 930 } 931 932 b := bytes.NewReader(rels) 933 var rela Rela64 934 935 for b.Len() > 0 { 936 binary.Read(b, f.ByteOrder, &rela) 937 var symNo uint64 938 var t R_MIPS 939 if f.ByteOrder == binary.BigEndian { 940 symNo = rela.Info >> 32 941 t = R_MIPS(rela.Info & 0xff) 942 } else { 943 symNo = rela.Info & 0xffffffff 944 t = R_MIPS(rela.Info >> 56) 945 } 946 947 if symNo == 0 || symNo > uint64(len(symbols)) { 948 continue 949 } 950 sym := &symbols[symNo-1] 951 if SymType(sym.Info&0xf) != STT_SECTION { 952 // We don't handle non-section relocations for now. 953 continue 954 } 955 956 switch t { 957 case R_MIPS_64: 958 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 959 continue 960 } 961 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 962 case R_MIPS_32: 963 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 964 continue 965 } 966 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 967 } 968 } 969 970 return nil 971} 972 973func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { 974 // 24 is the size of Rela64. 975 if len(rels)%24 != 0 { 976 return errors.New("length of relocation section is not a multiple of 24") 977 } 978 979 symbols, _, err := f.getSymbols(SHT_SYMTAB) 980 if err != nil { 981 return err 982 } 983 984 b := bytes.NewReader(rels) 985 var rela Rela64 986 987 for b.Len() > 0 { 988 binary.Read(b, f.ByteOrder, &rela) 989 symNo := rela.Info >> 32 990 t := R_390(rela.Info & 0xffff) 991 992 if symNo == 0 || symNo > uint64(len(symbols)) { 993 continue 994 } 995 sym := &symbols[symNo-1] 996 switch SymType(sym.Info & 0xf) { 997 case STT_SECTION, STT_NOTYPE: 998 break 999 default: 1000 continue 1001 } 1002 1003 switch t { 1004 case R_390_64: 1005 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1006 continue 1007 } 1008 val := sym.Value + uint64(rela.Addend) 1009 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) 1010 case R_390_32: 1011 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1012 continue 1013 } 1014 val := uint32(sym.Value) + uint32(rela.Addend) 1015 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) 1016 } 1017 } 1018 1019 return nil 1020} 1021 1022func (f *File) applyRelocationsSPARC(dst []byte, rels []byte) error { 1023 // 12 is the size of Rela32. 1024 if len(rels)%12 != 0 { 1025 return errors.New("length of relocation section is not a multiple of 12") 1026 } 1027 1028 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1029 if err != nil { 1030 return err 1031 } 1032 1033 b := bytes.NewReader(rels) 1034 var rela Rela32 1035 1036 for b.Len() > 0 { 1037 binary.Read(b, f.ByteOrder, &rela) 1038 symNo := rela.Info >> 32 1039 t := R_SPARC(rela.Info & 0xff) 1040 1041 if symNo == 0 || symNo > uint32(len(symbols)) { 1042 continue 1043 } 1044 sym := &symbols[symNo-1] 1045 if SymType(sym.Info&0xf) != STT_SECTION { 1046 // We don't handle non-section relocations for now. 1047 continue 1048 } 1049 1050 switch t { 1051 case R_SPARC_32, R_SPARC_UA32: 1052 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 1053 continue 1054 } 1055 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 1056 } 1057 } 1058 1059 return nil 1060} 1061 1062func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { 1063 // 24 is the size of Rela64. 1064 if len(rels)%24 != 0 { 1065 return errors.New("length of relocation section is not a multiple of 24") 1066 } 1067 1068 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1069 if err != nil { 1070 return err 1071 } 1072 1073 b := bytes.NewReader(rels) 1074 var rela Rela64 1075 1076 for b.Len() > 0 { 1077 binary.Read(b, f.ByteOrder, &rela) 1078 symNo := rela.Info >> 32 1079 t := R_SPARC(rela.Info & 0xff) 1080 1081 if symNo == 0 || symNo > uint64(len(symbols)) { 1082 continue 1083 } 1084 sym := &symbols[symNo-1] 1085 if SymType(sym.Info&0xf) != STT_SECTION { 1086 // We don't handle non-section relocations for now. 1087 continue 1088 } 1089 1090 switch t { 1091 case R_SPARC_64, R_SPARC_UA64: 1092 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1093 continue 1094 } 1095 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 1096 case R_SPARC_32, R_SPARC_UA32: 1097 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1098 continue 1099 } 1100 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 1101 } 1102 } 1103 1104 return nil 1105} 1106 1107func (f *File) applyRelocationsALPHA(dst []byte, rels []byte) error { 1108 // 24 is the size of Rela64. 1109 if len(rels)%24 != 0 { 1110 return errors.New("length of relocation section is not a multiple of 24") 1111 } 1112 1113 symbols, _, err := f.getSymbols(SHT_SYMTAB) 1114 if err != nil { 1115 return err 1116 } 1117 1118 b := bytes.NewReader(rels) 1119 var rela Rela64 1120 1121 for b.Len() > 0 { 1122 binary.Read(b, f.ByteOrder, &rela) 1123 symNo := rela.Info >> 32 1124 t := R_ALPHA(rela.Info & 0xffff) 1125 1126 if symNo == 0 || symNo > uint64(len(symbols)) { 1127 continue 1128 } 1129 sym := &symbols[symNo-1] 1130 if SymType(sym.Info&0xf) != STT_SECTION { 1131 // We don't handle non-section relocations for now. 1132 continue 1133 } 1134 1135 // There are relocations, so this must be a normal 1136 // object file, and we only look at section symbols, 1137 // so we assume that the symbol value is 0. 1138 1139 switch t { 1140 case R_ALPHA_REFQUAD: 1141 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 1142 continue 1143 } 1144 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 1145 case R_ALPHA_REFLONG: 1146 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 1147 continue 1148 } 1149 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 1150 } 1151 } 1152 1153 return nil 1154} 1155 1156func (f *File) DWARF() (*dwarf.Data, error) { 1157 // sectionData gets the data for s, checks its size, and 1158 // applies any applicable relations. 1159 sectionData := func(i int, s *Section) ([]byte, error) { 1160 b, err := s.Data() 1161 if err != nil && uint64(len(b)) < s.Size { 1162 return nil, err 1163 } 1164 1165 if len(b) >= 12 && string(b[:4]) == "ZLIB" { 1166 dlen := binary.BigEndian.Uint64(b[4:12]) 1167 dbuf := make([]byte, dlen) 1168 r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) 1169 if err != nil { 1170 return nil, err 1171 } 1172 if _, err := io.ReadFull(r, dbuf); err != nil { 1173 return nil, err 1174 } 1175 if err := r.Close(); err != nil { 1176 return nil, err 1177 } 1178 b = dbuf 1179 } 1180 1181 for _, r := range f.Sections { 1182 if r.Type != SHT_RELA && r.Type != SHT_REL { 1183 continue 1184 } 1185 if int(r.Info) != i { 1186 continue 1187 } 1188 rd, err := r.Data() 1189 if err != nil { 1190 return nil, err 1191 } 1192 err = f.applyRelocations(b, rd) 1193 if err != nil { 1194 return nil, err 1195 } 1196 } 1197 return b, nil 1198 } 1199 1200 // There are many other DWARF sections, but these 1201 // are the ones the debug/dwarf package uses. 1202 // Don't bother loading others. 1203 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} 1204 for i, s := range f.Sections { 1205 suffix := "" 1206 switch { 1207 case strings.HasPrefix(s.Name, ".debug_"): 1208 suffix = s.Name[7:] 1209 case strings.HasPrefix(s.Name, ".zdebug_"): 1210 suffix = s.Name[8:] 1211 default: 1212 continue 1213 } 1214 if _, ok := dat[suffix]; !ok { 1215 continue 1216 } 1217 b, err := sectionData(i, s) 1218 if err != nil { 1219 return nil, err 1220 } 1221 dat[suffix] = b 1222 } 1223 1224 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) 1225 if err != nil { 1226 return nil, err 1227 } 1228 1229 // Look for DWARF4 .debug_types sections. 1230 for i, s := range f.Sections { 1231 if s.Name == ".debug_types" { 1232 b, err := sectionData(i, s) 1233 if err != nil { 1234 return nil, err 1235 } 1236 1237 err = d.AddTypes(fmt.Sprintf("types-%d", i), b) 1238 if err != nil { 1239 return nil, err 1240 } 1241 } 1242 } 1243 1244 return d, nil 1245} 1246 1247// Symbols returns the symbol table for f. The symbols will be listed in the order 1248// they appear in f. 1249// 1250// For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 1251// After retrieving the symbols as symtab, an externally supplied index x 1252// corresponds to symtab[x-1], not symtab[x]. 1253func (f *File) Symbols() ([]Symbol, error) { 1254 sym, _, err := f.getSymbols(SHT_SYMTAB) 1255 return sym, err 1256} 1257 1258// DynamicSymbols returns the dynamic symbol table for f. The symbols 1259// will be listed in the order they appear in f. 1260// 1261// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. 1262// After retrieving the symbols as symtab, an externally supplied index x 1263// corresponds to symtab[x-1], not symtab[x]. 1264func (f *File) DynamicSymbols() ([]Symbol, error) { 1265 sym, _, err := f.getSymbols(SHT_DYNSYM) 1266 return sym, err 1267} 1268 1269type ImportedSymbol struct { 1270 Name string 1271 Version string 1272 Library string 1273} 1274 1275// ImportedSymbols returns the names of all symbols 1276// referred to by the binary f that are expected to be 1277// satisfied by other libraries at dynamic load time. 1278// It does not return weak symbols. 1279func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 1280 sym, str, err := f.getSymbols(SHT_DYNSYM) 1281 if err != nil { 1282 return nil, err 1283 } 1284 f.gnuVersionInit(str) 1285 var all []ImportedSymbol 1286 for i, s := range sym { 1287 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 1288 all = append(all, ImportedSymbol{Name: s.Name}) 1289 f.gnuVersion(i, &all[len(all)-1]) 1290 } 1291 } 1292 return all, nil 1293} 1294 1295type verneed struct { 1296 File string 1297 Name string 1298} 1299 1300// gnuVersionInit parses the GNU version tables 1301// for use by calls to gnuVersion. 1302func (f *File) gnuVersionInit(str []byte) { 1303 // Accumulate verneed information. 1304 vn := f.SectionByType(SHT_GNU_VERNEED) 1305 if vn == nil { 1306 return 1307 } 1308 d, _ := vn.Data() 1309 1310 var need []verneed 1311 i := 0 1312 for { 1313 if i+16 > len(d) { 1314 break 1315 } 1316 vers := f.ByteOrder.Uint16(d[i : i+2]) 1317 if vers != 1 { 1318 break 1319 } 1320 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 1321 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 1322 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 1323 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 1324 file, _ := getString(str, int(fileoff)) 1325 1326 var name string 1327 j := i + int(aux) 1328 for c := 0; c < int(cnt); c++ { 1329 if j+16 > len(d) { 1330 break 1331 } 1332 // hash := f.ByteOrder.Uint32(d[j:j+4]) 1333 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 1334 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 1335 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 1336 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 1337 name, _ = getString(str, int(nameoff)) 1338 ndx := int(other) 1339 if ndx >= len(need) { 1340 a := make([]verneed, 2*(ndx+1)) 1341 copy(a, need) 1342 need = a 1343 } 1344 1345 need[ndx] = verneed{file, name} 1346 if next == 0 { 1347 break 1348 } 1349 j += int(next) 1350 } 1351 1352 if next == 0 { 1353 break 1354 } 1355 i += int(next) 1356 } 1357 1358 // Versym parallels symbol table, indexing into verneed. 1359 vs := f.SectionByType(SHT_GNU_VERSYM) 1360 if vs == nil { 1361 return 1362 } 1363 d, _ = vs.Data() 1364 1365 f.gnuNeed = need 1366 f.gnuVersym = d 1367} 1368 1369// gnuVersion adds Library and Version information to sym, 1370// which came from offset i of the symbol table. 1371func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 1372 // Each entry is two bytes. 1373 i = (i + 1) * 2 1374 if i >= len(f.gnuVersym) { 1375 return 1376 } 1377 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 1378 if j < 2 || j >= len(f.gnuNeed) { 1379 return 1380 } 1381 n := &f.gnuNeed[j] 1382 sym.Library = n.File 1383 sym.Version = n.Name 1384} 1385 1386// ImportedLibraries returns the names of all libraries 1387// referred to by the binary f that are expected to be 1388// linked with the binary at dynamic link time. 1389func (f *File) ImportedLibraries() ([]string, error) { 1390 return f.DynString(DT_NEEDED) 1391} 1392 1393// DynString returns the strings listed for the given tag in the file's dynamic 1394// section. 1395// 1396// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 1397// DT_RUNPATH. 1398func (f *File) DynString(tag DynTag) ([]string, error) { 1399 switch tag { 1400 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1401 default: 1402 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1403 } 1404 ds := f.SectionByType(SHT_DYNAMIC) 1405 if ds == nil { 1406 // not dynamic, so no libraries 1407 return nil, nil 1408 } 1409 d, err := ds.Data() 1410 if err != nil { 1411 return nil, err 1412 } 1413 str, err := f.stringTable(ds.Link) 1414 if err != nil { 1415 return nil, err 1416 } 1417 var all []string 1418 for len(d) > 0 { 1419 var t DynTag 1420 var v uint64 1421 switch f.Class { 1422 case ELFCLASS32: 1423 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1424 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1425 d = d[8:] 1426 case ELFCLASS64: 1427 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1428 v = f.ByteOrder.Uint64(d[8:16]) 1429 d = d[16:] 1430 } 1431 if t == tag { 1432 s, ok := getString(str, int(v)) 1433 if ok { 1434 all = append(all, s) 1435 } 1436 } 1437 } 1438 return all, nil 1439} 1440