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 "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. 26 type 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. 39 type 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. 49 type 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. 63 type 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. 77 func (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. 88 func (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. 96 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } 97 98 // A ProgHeader represents a single ELF program header. 99 type 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. 111 type 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. 125 func (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. 128 type Symbol struct { 129 Name string 130 Info, Other byte 131 Section SectionIndex 132 Value, Size uint64 133 } 134 135 /* 136 * ELF reader 137 */ 138 139 type FormatError struct { 140 off int64 141 msg string 142 val interface{} 143 } 144 145 func (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. 155 func 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. 172 func (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. 183 func (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. 194 func 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. 397 func (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. 411 var ErrNoSymbols = errors.New("no symbol section") 412 413 func (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 456 func (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. 500 func 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. 515 func (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. 526 func (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 default: 541 return errors.New("applyRelocations: not implemented") 542 } 543 } 544 545 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 546 // 24 is the size of Rela64. 547 if len(rels)%24 != 0 { 548 return errors.New("length of relocation section is not a multiple of 24") 549 } 550 551 symbols, _, err := f.getSymbols(SHT_SYMTAB) 552 if err != nil { 553 return err 554 } 555 556 b := bytes.NewReader(rels) 557 var rela Rela64 558 559 for b.Len() > 0 { 560 binary.Read(b, f.ByteOrder, &rela) 561 symNo := rela.Info >> 32 562 t := R_X86_64(rela.Info & 0xffff) 563 564 if symNo == 0 || symNo > uint64(len(symbols)) { 565 continue 566 } 567 sym := &symbols[symNo-1] 568 if SymType(sym.Info&0xf) != STT_SECTION { 569 // We don't handle non-section relocations for now. 570 continue 571 } 572 573 // There are relocations, so this must be a normal 574 // object file, and we only look at section symbols, 575 // so we assume that the symbol value is 0. 576 577 switch t { 578 case R_X86_64_64: 579 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 580 continue 581 } 582 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 583 case R_X86_64_32: 584 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 585 continue 586 } 587 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 588 } 589 } 590 591 return nil 592 } 593 594 func (f *File) applyRelocations386(dst []byte, rels []byte) error { 595 // 8 is the size of Rel32. 596 if len(rels)%8 != 0 { 597 return errors.New("length of relocation section is not a multiple of 8") 598 } 599 600 symbols, _, err := f.getSymbols(SHT_SYMTAB) 601 if err != nil { 602 return err 603 } 604 605 b := bytes.NewReader(rels) 606 var rel Rel32 607 608 for b.Len() > 0 { 609 binary.Read(b, f.ByteOrder, &rel) 610 symNo := rel.Info >> 8 611 t := R_386(rel.Info & 0xff) 612 613 if symNo == 0 || symNo > uint32(len(symbols)) { 614 continue 615 } 616 sym := &symbols[symNo-1] 617 618 if t == R_386_32 { 619 if rel.Off+4 >= uint32(len(dst)) { 620 continue 621 } 622 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 623 val += uint32(sym.Value) 624 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 625 } 626 } 627 628 return nil 629 } 630 631 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { 632 // 8 is the size of Rel32. 633 if len(rels)%8 != 0 { 634 return errors.New("length of relocation section is not a multiple of 8") 635 } 636 637 symbols, _, err := f.getSymbols(SHT_SYMTAB) 638 if err != nil { 639 return err 640 } 641 642 b := bytes.NewReader(rels) 643 var rel Rel32 644 645 for b.Len() > 0 { 646 binary.Read(b, f.ByteOrder, &rel) 647 symNo := rel.Info >> 8 648 t := R_ARM(rel.Info & 0xff) 649 650 if symNo == 0 || symNo > uint32(len(symbols)) { 651 continue 652 } 653 sym := &symbols[symNo-1] 654 655 switch t { 656 case R_ARM_ABS32: 657 if rel.Off+4 >= uint32(len(dst)) { 658 continue 659 } 660 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) 661 val += uint32(sym.Value) 662 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) 663 } 664 } 665 666 return nil 667 } 668 669 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { 670 // 24 is the size of Rela64. 671 if len(rels)%24 != 0 { 672 return errors.New("length of relocation section is not a multiple of 24") 673 } 674 675 symbols, _, err := f.getSymbols(SHT_SYMTAB) 676 if err != nil { 677 return err 678 } 679 680 b := bytes.NewReader(rels) 681 var rela Rela64 682 683 for b.Len() > 0 { 684 binary.Read(b, f.ByteOrder, &rela) 685 symNo := rela.Info >> 32 686 t := R_AARCH64(rela.Info & 0xffff) 687 688 if symNo == 0 || symNo > uint64(len(symbols)) { 689 continue 690 } 691 sym := &symbols[symNo-1] 692 if SymType(sym.Info&0xf) != STT_SECTION { 693 // We don't handle non-section relocations for now. 694 continue 695 } 696 697 // There are relocations, so this must be a normal 698 // object file, and we only look at section symbols, 699 // so we assume that the symbol value is 0. 700 701 switch t { 702 case R_AARCH64_ABS64: 703 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 704 continue 705 } 706 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 707 case R_AARCH64_ABS32: 708 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 709 continue 710 } 711 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 712 } 713 } 714 715 return nil 716 } 717 718 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { 719 // 12 is the size of Rela32. 720 if len(rels)%12 != 0 { 721 return errors.New("length of relocation section is not a multiple of 12") 722 } 723 724 symbols, _, err := f.getSymbols(SHT_SYMTAB) 725 if err != nil { 726 return err 727 } 728 729 b := bytes.NewReader(rels) 730 var rela Rela32 731 732 for b.Len() > 0 { 733 binary.Read(b, f.ByteOrder, &rela) 734 symNo := rela.Info >> 8 735 t := R_PPC(rela.Info & 0xff) 736 737 if symNo == 0 || symNo > uint32(len(symbols)) { 738 continue 739 } 740 sym := &symbols[symNo-1] 741 if SymType(sym.Info&0xf) != STT_SECTION { 742 // We don't handle non-section relocations for now. 743 continue 744 } 745 746 switch t { 747 case R_PPC_ADDR32: 748 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { 749 continue 750 } 751 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 752 } 753 } 754 755 return nil 756 } 757 758 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { 759 // 24 is the size of Rela64. 760 if len(rels)%24 != 0 { 761 return errors.New("length of relocation section is not a multiple of 24") 762 } 763 764 symbols, _, err := f.getSymbols(SHT_SYMTAB) 765 if err != nil { 766 return err 767 } 768 769 b := bytes.NewReader(rels) 770 var rela Rela64 771 772 for b.Len() > 0 { 773 binary.Read(b, f.ByteOrder, &rela) 774 symNo := rela.Info >> 32 775 t := R_PPC64(rela.Info & 0xffff) 776 777 if symNo == 0 || symNo > uint64(len(symbols)) { 778 continue 779 } 780 sym := &symbols[symNo-1] 781 if SymType(sym.Info&0xf) != STT_SECTION { 782 // We don't handle non-section relocations for now. 783 continue 784 } 785 786 switch t { 787 case R_PPC64_ADDR64: 788 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 789 continue 790 } 791 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 792 case R_PPC64_ADDR32: 793 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 794 continue 795 } 796 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 797 } 798 } 799 800 return nil 801 } 802 803 func (f *File) DWARF() (*dwarf.Data, error) { 804 // sectionData gets the data for s, checks its size, and 805 // applies any applicable relations. 806 sectionData := func(i int, s *Section) ([]byte, error) { 807 b, err := s.Data() 808 if err != nil && uint64(len(b)) < s.Size { 809 return nil, err 810 } 811 812 for _, r := range f.Sections { 813 if r.Type != SHT_RELA && r.Type != SHT_REL { 814 continue 815 } 816 if int(r.Info) != i { 817 continue 818 } 819 rd, err := r.Data() 820 if err != nil { 821 return nil, err 822 } 823 err = f.applyRelocations(b, rd) 824 if err != nil { 825 return nil, err 826 } 827 } 828 return b, nil 829 } 830 831 // There are many other DWARF sections, but these 832 // are the ones the debug/dwarf package uses. 833 // Don't bother loading others. 834 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil} 835 for i, s := range f.Sections { 836 if !strings.HasPrefix(s.Name, ".debug_") { 837 continue 838 } 839 if _, ok := dat[s.Name[7:]]; !ok { 840 continue 841 } 842 b, err := sectionData(i, s) 843 if err != nil { 844 return nil, err 845 } 846 dat[s.Name[7:]] = b 847 } 848 849 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, nil, dat["str"]) 850 if err != nil { 851 return nil, err 852 } 853 854 // Look for DWARF4 .debug_types sections. 855 for i, s := range f.Sections { 856 if s.Name == ".debug_types" { 857 b, err := sectionData(i, s) 858 if err != nil { 859 return nil, err 860 } 861 862 err = d.AddTypes(fmt.Sprintf("types-%d", i), b) 863 if err != nil { 864 return nil, err 865 } 866 } 867 } 868 869 return d, nil 870 } 871 872 // Symbols returns the symbol table for f. The symbols will be listed in the order 873 // they appear in f. 874 // 875 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 876 // After retrieving the symbols as symtab, an externally supplied index x 877 // corresponds to symtab[x-1], not symtab[x]. 878 func (f *File) Symbols() ([]Symbol, error) { 879 sym, _, err := f.getSymbols(SHT_SYMTAB) 880 return sym, err 881 } 882 883 // DynamicSymbols returns the dynamic symbol table for f. The symbols 884 // will be listed in the order they appear in f. 885 // 886 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. 887 // After retrieving the symbols as symtab, an externally supplied index x 888 // corresponds to symtab[x-1], not symtab[x]. 889 func (f *File) DynamicSymbols() ([]Symbol, error) { 890 sym, _, err := f.getSymbols(SHT_DYNSYM) 891 return sym, err 892 } 893 894 type ImportedSymbol struct { 895 Name string 896 Version string 897 Library string 898 } 899 900 // ImportedSymbols returns the names of all symbols 901 // referred to by the binary f that are expected to be 902 // satisfied by other libraries at dynamic load time. 903 // It does not return weak symbols. 904 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 905 sym, str, err := f.getSymbols(SHT_DYNSYM) 906 if err != nil { 907 return nil, err 908 } 909 f.gnuVersionInit(str) 910 var all []ImportedSymbol 911 for i, s := range sym { 912 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 913 all = append(all, ImportedSymbol{Name: s.Name}) 914 f.gnuVersion(i, &all[len(all)-1]) 915 } 916 } 917 return all, nil 918 } 919 920 type verneed struct { 921 File string 922 Name string 923 } 924 925 // gnuVersionInit parses the GNU version tables 926 // for use by calls to gnuVersion. 927 func (f *File) gnuVersionInit(str []byte) { 928 // Accumulate verneed information. 929 vn := f.SectionByType(SHT_GNU_VERNEED) 930 if vn == nil { 931 return 932 } 933 d, _ := vn.Data() 934 935 var need []verneed 936 i := 0 937 for { 938 if i+16 > len(d) { 939 break 940 } 941 vers := f.ByteOrder.Uint16(d[i : i+2]) 942 if vers != 1 { 943 break 944 } 945 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 946 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 947 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 948 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 949 file, _ := getString(str, int(fileoff)) 950 951 var name string 952 j := i + int(aux) 953 for c := 0; c < int(cnt); c++ { 954 if j+16 > len(d) { 955 break 956 } 957 // hash := f.ByteOrder.Uint32(d[j:j+4]) 958 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 959 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 960 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 961 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 962 name, _ = getString(str, int(nameoff)) 963 ndx := int(other) 964 if ndx >= len(need) { 965 a := make([]verneed, 2*(ndx+1)) 966 copy(a, need) 967 need = a 968 } 969 970 need[ndx] = verneed{file, name} 971 if next == 0 { 972 break 973 } 974 j += int(next) 975 } 976 977 if next == 0 { 978 break 979 } 980 i += int(next) 981 } 982 983 // Versym parallels symbol table, indexing into verneed. 984 vs := f.SectionByType(SHT_GNU_VERSYM) 985 if vs == nil { 986 return 987 } 988 d, _ = vs.Data() 989 990 f.gnuNeed = need 991 f.gnuVersym = d 992 } 993 994 // gnuVersion adds Library and Version information to sym, 995 // which came from offset i of the symbol table. 996 func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 997 // Each entry is two bytes. 998 i = (i + 1) * 2 999 if i >= len(f.gnuVersym) { 1000 return 1001 } 1002 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 1003 if j < 2 || j >= len(f.gnuNeed) { 1004 return 1005 } 1006 n := &f.gnuNeed[j] 1007 sym.Library = n.File 1008 sym.Version = n.Name 1009 } 1010 1011 // ImportedLibraries returns the names of all libraries 1012 // referred to by the binary f that are expected to be 1013 // linked with the binary at dynamic link time. 1014 func (f *File) ImportedLibraries() ([]string, error) { 1015 return f.DynString(DT_NEEDED) 1016 } 1017 1018 // DynString returns the strings listed for the given tag in the file's dynamic 1019 // section. 1020 // 1021 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 1022 // DT_RUNPATH. 1023 func (f *File) DynString(tag DynTag) ([]string, error) { 1024 switch tag { 1025 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 1026 default: 1027 return nil, fmt.Errorf("non-string-valued tag %v", tag) 1028 } 1029 ds := f.SectionByType(SHT_DYNAMIC) 1030 if ds == nil { 1031 // not dynamic, so no libraries 1032 return nil, nil 1033 } 1034 d, err := ds.Data() 1035 if err != nil { 1036 return nil, err 1037 } 1038 str, err := f.stringTable(ds.Link) 1039 if err != nil { 1040 return nil, err 1041 } 1042 var all []string 1043 for len(d) > 0 { 1044 var t DynTag 1045 var v uint64 1046 switch f.Class { 1047 case ELFCLASS32: 1048 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 1049 v = uint64(f.ByteOrder.Uint32(d[4:8])) 1050 d = d[8:] 1051 case ELFCLASS64: 1052 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 1053 v = f.ByteOrder.Uint64(d[8:16]) 1054 d = d[16:] 1055 } 1056 if t == tag { 1057 s, ok := getString(str, int(v)) 1058 if ok { 1059 all = append(all, s) 1060 } 1061 } 1062 } 1063 return all, nil 1064 } 1065