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