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