OSDN Git Service

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