github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/debug/elf/file.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package elf implements access to ELF object files. 6 package elf 7 8 import ( 9 "bytes" 10 "debug/dwarf" 11 "encoding/binary" 12 "errors" 13 "fmt" 14 "io" 15 "os" 16 ) 17 18 // TODO: error reporting detail 19 20 /* 21 * Internal ELF representation 22 */ 23 24 // A FileHeader represents an ELF file header. 25 type FileHeader struct { 26 Class Class 27 Data Data 28 Version Version 29 OSABI OSABI 30 ABIVersion uint8 31 ByteOrder binary.ByteOrder 32 Type Type 33 Machine Machine 34 Entry uint64 35 } 36 37 // A File represents an open ELF file. 38 type File struct { 39 FileHeader 40 Sections []*Section 41 Progs []*Prog 42 closer io.Closer 43 gnuNeed []verneed 44 gnuVersym []byte 45 } 46 47 // A SectionHeader represents a single ELF section header. 48 type SectionHeader struct { 49 Name string 50 Type SectionType 51 Flags SectionFlag 52 Addr uint64 53 Offset uint64 54 Size uint64 55 Link uint32 56 Info uint32 57 Addralign uint64 58 Entsize uint64 59 } 60 61 // A Section represents a single section in an ELF file. 62 type Section struct { 63 SectionHeader 64 65 // Embed ReaderAt for ReadAt method. 66 // Do not embed SectionReader directly 67 // to avoid having Read and Seek. 68 // If a client wants Read and Seek it must use 69 // Open() to avoid fighting over the seek offset 70 // with other clients. 71 io.ReaderAt 72 sr *io.SectionReader 73 } 74 75 // Data reads and returns the contents of the ELF section. 76 func (s *Section) Data() ([]byte, error) { 77 dat := make([]byte, s.sr.Size()) 78 n, err := s.sr.ReadAt(dat, 0) 79 return dat[0:n], err 80 } 81 82 // stringTable reads and returns the string table given by the 83 // specified link value. 84 func (f *File) stringTable(link uint32) ([]byte, error) { 85 if link <= 0 || link >= uint32(len(f.Sections)) { 86 return nil, errors.New("section has invalid string table link") 87 } 88 return f.Sections[link].Data() 89 } 90 91 // Open returns a new ReadSeeker reading the ELF section. 92 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } 93 94 // A ProgHeader represents a single ELF program header. 95 type ProgHeader struct { 96 Type ProgType 97 Flags ProgFlag 98 Off uint64 99 Vaddr uint64 100 Paddr uint64 101 Filesz uint64 102 Memsz uint64 103 Align uint64 104 } 105 106 // A Prog represents a single ELF program header in an ELF binary. 107 type Prog struct { 108 ProgHeader 109 110 // Embed ReaderAt for ReadAt method. 111 // Do not embed SectionReader directly 112 // to avoid having Read and Seek. 113 // If a client wants Read and Seek it must use 114 // Open() to avoid fighting over the seek offset 115 // with other clients. 116 io.ReaderAt 117 sr *io.SectionReader 118 } 119 120 // Open returns a new ReadSeeker reading the ELF program body. 121 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } 122 123 // A Symbol represents an entry in an ELF symbol table section. 124 type Symbol struct { 125 Name string 126 Info, Other byte 127 Section SectionIndex 128 Value, Size uint64 129 } 130 131 /* 132 * ELF reader 133 */ 134 135 type FormatError struct { 136 off int64 137 msg string 138 val interface{} 139 } 140 141 func (e *FormatError) Error() string { 142 msg := e.msg 143 if e.val != nil { 144 msg += fmt.Sprintf(" '%v' ", e.val) 145 } 146 msg += fmt.Sprintf("in record at byte %#x", e.off) 147 return msg 148 } 149 150 // Open opens the named file using os.Open and prepares it for use as an ELF binary. 151 func Open(name string) (*File, error) { 152 f, err := os.Open(name) 153 if err != nil { 154 return nil, err 155 } 156 ff, err := NewFile(f) 157 if err != nil { 158 f.Close() 159 return nil, err 160 } 161 ff.closer = f 162 return ff, nil 163 } 164 165 // Close closes the File. 166 // If the File was created using NewFile directly instead of Open, 167 // Close has no effect. 168 func (f *File) Close() error { 169 var err error 170 if f.closer != nil { 171 err = f.closer.Close() 172 f.closer = nil 173 } 174 return err 175 } 176 177 // SectionByType returns the first section in f with the 178 // given type, or nil if there is no such section. 179 func (f *File) SectionByType(typ SectionType) *Section { 180 for _, s := range f.Sections { 181 if s.Type == typ { 182 return s 183 } 184 } 185 return nil 186 } 187 188 // NewFile creates a new File for accessing an ELF binary in an underlying reader. 189 // The ELF binary is expected to start at position 0 in the ReaderAt. 190 func NewFile(r io.ReaderAt) (*File, error) { 191 sr := io.NewSectionReader(r, 0, 1<<63-1) 192 // Read and decode ELF identifier 193 var ident [16]uint8 194 if _, err := r.ReadAt(ident[0:], 0); err != nil { 195 return nil, err 196 } 197 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { 198 return nil, &FormatError{0, "bad magic number", ident[0:4]} 199 } 200 201 f := new(File) 202 f.Class = Class(ident[EI_CLASS]) 203 switch f.Class { 204 case ELFCLASS32: 205 case ELFCLASS64: 206 // ok 207 default: 208 return nil, &FormatError{0, "unknown ELF class", f.Class} 209 } 210 211 f.Data = Data(ident[EI_DATA]) 212 switch f.Data { 213 case ELFDATA2LSB: 214 f.ByteOrder = binary.LittleEndian 215 case ELFDATA2MSB: 216 f.ByteOrder = binary.BigEndian 217 default: 218 return nil, &FormatError{0, "unknown ELF data encoding", f.Data} 219 } 220 221 f.Version = Version(ident[EI_VERSION]) 222 if f.Version != EV_CURRENT { 223 return nil, &FormatError{0, "unknown ELF version", f.Version} 224 } 225 226 f.OSABI = OSABI(ident[EI_OSABI]) 227 f.ABIVersion = ident[EI_ABIVERSION] 228 229 // Read ELF file header 230 var phoff int64 231 var phentsize, phnum int 232 var shoff int64 233 var shentsize, shnum, shstrndx int 234 shstrndx = -1 235 switch f.Class { 236 case ELFCLASS32: 237 hdr := new(Header32) 238 sr.Seek(0, os.SEEK_SET) 239 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 240 return nil, err 241 } 242 f.Type = Type(hdr.Type) 243 f.Machine = Machine(hdr.Machine) 244 f.Entry = uint64(hdr.Entry) 245 if v := Version(hdr.Version); v != f.Version { 246 return nil, &FormatError{0, "mismatched ELF version", v} 247 } 248 phoff = int64(hdr.Phoff) 249 phentsize = int(hdr.Phentsize) 250 phnum = int(hdr.Phnum) 251 shoff = int64(hdr.Shoff) 252 shentsize = int(hdr.Shentsize) 253 shnum = int(hdr.Shnum) 254 shstrndx = int(hdr.Shstrndx) 255 case ELFCLASS64: 256 hdr := new(Header64) 257 sr.Seek(0, os.SEEK_SET) 258 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { 259 return nil, err 260 } 261 f.Type = Type(hdr.Type) 262 f.Machine = Machine(hdr.Machine) 263 f.Entry = uint64(hdr.Entry) 264 if v := Version(hdr.Version); v != f.Version { 265 return nil, &FormatError{0, "mismatched ELF version", v} 266 } 267 phoff = int64(hdr.Phoff) 268 phentsize = int(hdr.Phentsize) 269 phnum = int(hdr.Phnum) 270 shoff = int64(hdr.Shoff) 271 shentsize = int(hdr.Shentsize) 272 shnum = int(hdr.Shnum) 273 shstrndx = int(hdr.Shstrndx) 274 } 275 276 if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { 277 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} 278 } 279 280 // Read program headers 281 f.Progs = make([]*Prog, phnum) 282 for i := 0; i < phnum; i++ { 283 off := phoff + int64(i)*int64(phentsize) 284 sr.Seek(off, os.SEEK_SET) 285 p := new(Prog) 286 switch f.Class { 287 case ELFCLASS32: 288 ph := new(Prog32) 289 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 290 return nil, err 291 } 292 p.ProgHeader = ProgHeader{ 293 Type: ProgType(ph.Type), 294 Flags: ProgFlag(ph.Flags), 295 Off: uint64(ph.Off), 296 Vaddr: uint64(ph.Vaddr), 297 Paddr: uint64(ph.Paddr), 298 Filesz: uint64(ph.Filesz), 299 Memsz: uint64(ph.Memsz), 300 Align: uint64(ph.Align), 301 } 302 case ELFCLASS64: 303 ph := new(Prog64) 304 if err := binary.Read(sr, f.ByteOrder, ph); err != nil { 305 return nil, err 306 } 307 p.ProgHeader = ProgHeader{ 308 Type: ProgType(ph.Type), 309 Flags: ProgFlag(ph.Flags), 310 Off: uint64(ph.Off), 311 Vaddr: uint64(ph.Vaddr), 312 Paddr: uint64(ph.Paddr), 313 Filesz: uint64(ph.Filesz), 314 Memsz: uint64(ph.Memsz), 315 Align: uint64(ph.Align), 316 } 317 } 318 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) 319 p.ReaderAt = p.sr 320 f.Progs[i] = p 321 } 322 323 // Read section headers 324 f.Sections = make([]*Section, shnum) 325 names := make([]uint32, shnum) 326 for i := 0; i < shnum; i++ { 327 off := shoff + int64(i)*int64(shentsize) 328 sr.Seek(off, os.SEEK_SET) 329 s := new(Section) 330 switch f.Class { 331 case ELFCLASS32: 332 sh := new(Section32) 333 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 334 return nil, err 335 } 336 names[i] = sh.Name 337 s.SectionHeader = SectionHeader{ 338 Type: SectionType(sh.Type), 339 Flags: SectionFlag(sh.Flags), 340 Addr: uint64(sh.Addr), 341 Offset: uint64(sh.Off), 342 Size: uint64(sh.Size), 343 Link: uint32(sh.Link), 344 Info: uint32(sh.Info), 345 Addralign: uint64(sh.Addralign), 346 Entsize: uint64(sh.Entsize), 347 } 348 case ELFCLASS64: 349 sh := new(Section64) 350 if err := binary.Read(sr, f.ByteOrder, sh); err != nil { 351 return nil, err 352 } 353 names[i] = sh.Name 354 s.SectionHeader = SectionHeader{ 355 Type: SectionType(sh.Type), 356 Flags: SectionFlag(sh.Flags), 357 Offset: uint64(sh.Off), 358 Size: uint64(sh.Size), 359 Addr: uint64(sh.Addr), 360 Link: uint32(sh.Link), 361 Info: uint32(sh.Info), 362 Addralign: uint64(sh.Addralign), 363 Entsize: uint64(sh.Entsize), 364 } 365 } 366 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) 367 s.ReaderAt = s.sr 368 f.Sections[i] = s 369 } 370 371 if len(f.Sections) == 0 { 372 return f, nil 373 } 374 375 // Load section header string table. 376 shstrtab, err := f.Sections[shstrndx].Data() 377 if err != nil { 378 return nil, err 379 } 380 for i, s := range f.Sections { 381 var ok bool 382 s.Name, ok = getString(shstrtab, int(names[i])) 383 if !ok { 384 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} 385 } 386 } 387 388 return f, nil 389 } 390 391 // getSymbols returns a slice of Symbols from parsing the symbol table 392 // with the given type, along with the associated string table. 393 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { 394 switch f.Class { 395 case ELFCLASS64: 396 return f.getSymbols64(typ) 397 398 case ELFCLASS32: 399 return f.getSymbols32(typ) 400 } 401 402 return nil, nil, errors.New("not implemented") 403 } 404 405 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { 406 symtabSection := f.SectionByType(typ) 407 if symtabSection == nil { 408 return nil, nil, errors.New("no symbol section") 409 } 410 411 data, err := symtabSection.Data() 412 if err != nil { 413 return nil, nil, errors.New("cannot load symbol section") 414 } 415 symtab := bytes.NewBuffer(data) 416 if symtab.Len()%Sym32Size != 0 { 417 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") 418 } 419 420 strdata, err := f.stringTable(symtabSection.Link) 421 if err != nil { 422 return nil, nil, errors.New("cannot load string table section") 423 } 424 425 // The first entry is all zeros. 426 var skip [Sym32Size]byte 427 symtab.Read(skip[:]) 428 429 symbols := make([]Symbol, symtab.Len()/Sym32Size) 430 431 i := 0 432 var sym Sym32 433 for symtab.Len() > 0 { 434 binary.Read(symtab, f.ByteOrder, &sym) 435 str, _ := getString(strdata, int(sym.Name)) 436 symbols[i].Name = str 437 symbols[i].Info = sym.Info 438 symbols[i].Other = sym.Other 439 symbols[i].Section = SectionIndex(sym.Shndx) 440 symbols[i].Value = uint64(sym.Value) 441 symbols[i].Size = uint64(sym.Size) 442 i++ 443 } 444 445 return symbols, strdata, nil 446 } 447 448 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { 449 symtabSection := f.SectionByType(typ) 450 if symtabSection == nil { 451 return nil, nil, errors.New("no symbol section") 452 } 453 454 data, err := symtabSection.Data() 455 if err != nil { 456 return nil, nil, errors.New("cannot load symbol section") 457 } 458 symtab := bytes.NewBuffer(data) 459 if symtab.Len()%Sym64Size != 0 { 460 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") 461 } 462 463 strdata, err := f.stringTable(symtabSection.Link) 464 if err != nil { 465 return nil, nil, errors.New("cannot load string table section") 466 } 467 468 // The first entry is all zeros. 469 var skip [Sym64Size]byte 470 symtab.Read(skip[:]) 471 472 symbols := make([]Symbol, symtab.Len()/Sym64Size) 473 474 i := 0 475 var sym Sym64 476 for symtab.Len() > 0 { 477 binary.Read(symtab, f.ByteOrder, &sym) 478 str, _ := getString(strdata, int(sym.Name)) 479 symbols[i].Name = str 480 symbols[i].Info = sym.Info 481 symbols[i].Other = sym.Other 482 symbols[i].Section = SectionIndex(sym.Shndx) 483 symbols[i].Value = sym.Value 484 symbols[i].Size = sym.Size 485 i++ 486 } 487 488 return symbols, strdata, nil 489 } 490 491 // getString extracts a string from an ELF string table. 492 func getString(section []byte, start int) (string, bool) { 493 if start < 0 || start >= len(section) { 494 return "", false 495 } 496 497 for end := start; end < len(section); end++ { 498 if section[end] == 0 { 499 return string(section[start:end]), true 500 } 501 } 502 return "", false 503 } 504 505 // Section returns a section with the given name, or nil if no such 506 // section exists. 507 func (f *File) Section(name string) *Section { 508 for _, s := range f.Sections { 509 if s.Name == name { 510 return s 511 } 512 } 513 return nil 514 } 515 516 // applyRelocations applies relocations to dst. rels is a relocations section 517 // in RELA format. 518 func (f *File) applyRelocations(dst []byte, rels []byte) error { 519 if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { 520 return f.applyRelocationsAMD64(dst, rels) 521 } 522 523 return errors.New("not implemented") 524 } 525 526 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { 527 if len(rels)%Sym64Size != 0 { 528 return errors.New("length of relocation section is not a multiple of Sym64Size") 529 } 530 531 symbols, _, err := f.getSymbols(SHT_SYMTAB) 532 if err != nil { 533 return err 534 } 535 536 b := bytes.NewBuffer(rels) 537 var rela Rela64 538 539 for b.Len() > 0 { 540 binary.Read(b, f.ByteOrder, &rela) 541 symNo := rela.Info >> 32 542 t := R_X86_64(rela.Info & 0xffff) 543 544 if symNo == 0 || symNo > uint64(len(symbols)) { 545 continue 546 } 547 sym := &symbols[symNo-1] 548 if SymType(sym.Info&0xf) != STT_SECTION { 549 // We don't handle non-section relocations for now. 550 continue 551 } 552 553 switch t { 554 case R_X86_64_64: 555 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { 556 continue 557 } 558 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) 559 case R_X86_64_32: 560 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { 561 continue 562 } 563 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) 564 } 565 } 566 567 return nil 568 } 569 570 func (f *File) DWARF() (*dwarf.Data, error) { 571 // There are many other DWARF sections, but these 572 // are the required ones, and the debug/dwarf package 573 // does not use the others, so don't bother loading them. 574 var names = [...]string{"abbrev", "info", "str"} 575 var dat [len(names)][]byte 576 for i, name := range names { 577 name = ".debug_" + name 578 s := f.Section(name) 579 if s == nil { 580 continue 581 } 582 b, err := s.Data() 583 if err != nil && uint64(len(b)) < s.Size { 584 return nil, err 585 } 586 dat[i] = b 587 } 588 589 // If there's a relocation table for .debug_info, we have to process it 590 // now otherwise the data in .debug_info is invalid for x86-64 objects. 591 rela := f.Section(".rela.debug_info") 592 if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 { 593 data, err := rela.Data() 594 if err != nil { 595 return nil, err 596 } 597 err = f.applyRelocations(dat[1], data) 598 if err != nil { 599 return nil, err 600 } 601 } 602 603 abbrev, info, str := dat[0], dat[1], dat[2] 604 return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) 605 } 606 607 // Symbols returns the symbol table for f. 608 // 609 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. 610 // After retrieving the symbols as symtab, an externally supplied index x 611 // corresponds to symtab[x-1], not symtab[x]. 612 func (f *File) Symbols() ([]Symbol, error) { 613 sym, _, err := f.getSymbols(SHT_SYMTAB) 614 return sym, err 615 } 616 617 type ImportedSymbol struct { 618 Name string 619 Version string 620 Library string 621 } 622 623 // ImportedSymbols returns the names of all symbols 624 // referred to by the binary f that are expected to be 625 // satisfied by other libraries at dynamic load time. 626 // It does not return weak symbols. 627 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { 628 sym, str, err := f.getSymbols(SHT_DYNSYM) 629 if err != nil { 630 return nil, err 631 } 632 f.gnuVersionInit(str) 633 var all []ImportedSymbol 634 for i, s := range sym { 635 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 636 all = append(all, ImportedSymbol{Name: s.Name}) 637 f.gnuVersion(i, &all[len(all)-1]) 638 } 639 } 640 return all, nil 641 } 642 643 type verneed struct { 644 File string 645 Name string 646 } 647 648 // gnuVersionInit parses the GNU version tables 649 // for use by calls to gnuVersion. 650 func (f *File) gnuVersionInit(str []byte) { 651 // Accumulate verneed information. 652 vn := f.SectionByType(SHT_GNU_VERNEED) 653 if vn == nil { 654 return 655 } 656 d, _ := vn.Data() 657 658 var need []verneed 659 i := 0 660 for { 661 if i+16 > len(d) { 662 break 663 } 664 vers := f.ByteOrder.Uint16(d[i : i+2]) 665 if vers != 1 { 666 break 667 } 668 cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) 669 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) 670 aux := f.ByteOrder.Uint32(d[i+8 : i+12]) 671 next := f.ByteOrder.Uint32(d[i+12 : i+16]) 672 file, _ := getString(str, int(fileoff)) 673 674 var name string 675 j := i + int(aux) 676 for c := 0; c < int(cnt); c++ { 677 if j+16 > len(d) { 678 break 679 } 680 // hash := f.ByteOrder.Uint32(d[j:j+4]) 681 // flags := f.ByteOrder.Uint16(d[j+4:j+6]) 682 other := f.ByteOrder.Uint16(d[j+6 : j+8]) 683 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) 684 next := f.ByteOrder.Uint32(d[j+12 : j+16]) 685 name, _ = getString(str, int(nameoff)) 686 ndx := int(other) 687 if ndx >= len(need) { 688 a := make([]verneed, 2*(ndx+1)) 689 copy(a, need) 690 need = a 691 } 692 693 need[ndx] = verneed{file, name} 694 if next == 0 { 695 break 696 } 697 j += int(next) 698 } 699 700 if next == 0 { 701 break 702 } 703 i += int(next) 704 } 705 706 // Versym parallels symbol table, indexing into verneed. 707 vs := f.SectionByType(SHT_GNU_VERSYM) 708 if vs == nil { 709 return 710 } 711 d, _ = vs.Data() 712 713 f.gnuNeed = need 714 f.gnuVersym = d 715 } 716 717 // gnuVersion adds Library and Version information to sym, 718 // which came from offset i of the symbol table. 719 func (f *File) gnuVersion(i int, sym *ImportedSymbol) { 720 // Each entry is two bytes. 721 i = (i + 1) * 2 722 if i >= len(f.gnuVersym) { 723 return 724 } 725 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) 726 if j < 2 || j >= len(f.gnuNeed) { 727 return 728 } 729 n := &f.gnuNeed[j] 730 sym.Library = n.File 731 sym.Version = n.Name 732 } 733 734 // ImportedLibraries returns the names of all libraries 735 // referred to by the binary f that are expected to be 736 // linked with the binary at dynamic link time. 737 func (f *File) ImportedLibraries() ([]string, error) { 738 return f.DynString(DT_NEEDED) 739 } 740 741 // DynString returns the strings listed for the given tag in the file's dynamic 742 // section. 743 // 744 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or 745 // DT_RUNPATH. 746 func (f *File) DynString(tag DynTag) ([]string, error) { 747 switch tag { 748 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: 749 default: 750 return nil, fmt.Errorf("non-string-valued tag %v", tag) 751 } 752 ds := f.SectionByType(SHT_DYNAMIC) 753 if ds == nil { 754 // not dynamic, so no libraries 755 return nil, nil 756 } 757 d, err := ds.Data() 758 if err != nil { 759 return nil, err 760 } 761 str, err := f.stringTable(ds.Link) 762 if err != nil { 763 return nil, err 764 } 765 var all []string 766 for len(d) > 0 { 767 var t DynTag 768 var v uint64 769 switch f.Class { 770 case ELFCLASS32: 771 t = DynTag(f.ByteOrder.Uint32(d[0:4])) 772 v = uint64(f.ByteOrder.Uint32(d[4:8])) 773 d = d[8:] 774 case ELFCLASS64: 775 t = DynTag(f.ByteOrder.Uint64(d[0:8])) 776 v = f.ByteOrder.Uint64(d[8:16]) 777 d = d[16:] 778 } 779 if t == tag { 780 s, ok := getString(str, int(v)) 781 if ok { 782 all = append(all, s) 783 } 784 } 785 } 786 return all, nil 787 }