eb3d72f7126d766d2c26e916df468ee28df56375
[platform/upstream/gcc48.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         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         symbols := make([]Symbol, symtab.Len()/Sym32Size)
426
427         i := 0
428         var sym Sym32
429         for symtab.Len() > 0 {
430                 binary.Read(symtab, f.ByteOrder, &sym)
431                 str, _ := getString(strdata, int(sym.Name))
432                 symbols[i].Name = str
433                 symbols[i].Info = sym.Info
434                 symbols[i].Other = sym.Other
435                 symbols[i].Section = SectionIndex(sym.Shndx)
436                 symbols[i].Value = uint64(sym.Value)
437                 symbols[i].Size = uint64(sym.Size)
438                 i++
439         }
440
441         return symbols, strdata, nil
442 }
443
444 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
445         symtabSection := f.SectionByType(typ)
446         if symtabSection == nil {
447                 return nil, nil, errors.New("no symbol section")
448         }
449
450         data, err := symtabSection.Data()
451         if err != nil {
452                 return nil, nil, errors.New("cannot load symbol section")
453         }
454         symtab := bytes.NewBuffer(data)
455         if symtab.Len()%Sym64Size != 0 {
456                 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
457         }
458
459         strdata, err := f.stringTable(symtabSection.Link)
460         if err != nil {
461                 return nil, nil, errors.New("cannot load string table section")
462         }
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.
709         i = i * 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         return f.DynString(DT_NEEDED)
727 }
728
729 // DynString returns the strings listed for the given tag in the file's dynamic
730 // section.
731 //
732 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
733 // DT_RUNPATH.
734 func (f *File) DynString(tag DynTag) ([]string, error) {
735         switch tag {
736         case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
737         default:
738                 return nil, fmt.Errorf("non-string-valued tag %v", tag)
739         }
740         ds := f.SectionByType(SHT_DYNAMIC)
741         if ds == nil {
742                 // not dynamic, so no libraries
743                 return nil, nil
744         }
745         d, err := ds.Data()
746         if err != nil {
747                 return nil, err
748         }
749         str, err := f.stringTable(ds.Link)
750         if err != nil {
751                 return nil, err
752         }
753         var all []string
754         for len(d) > 0 {
755                 var t DynTag
756                 var v uint64
757                 switch f.Class {
758                 case ELFCLASS32:
759                         t = DynTag(f.ByteOrder.Uint32(d[0:4]))
760                         v = uint64(f.ByteOrder.Uint32(d[4:8]))
761                         d = d[8:]
762                 case ELFCLASS64:
763                         t = DynTag(f.ByteOrder.Uint64(d[0:8]))
764                         v = f.ByteOrder.Uint64(d[8:16])
765                         d = d[16:]
766                 }
767                 if t == tag {
768                         s, ok := getString(str, int(v))
769                         if ok {
770                                 all = append(all, s)
771                         }
772                 }
773         }
774         return all, nil
775 }