summaryrefslogtreecommitdiff
path: root/libgo/go/debug/elf/file.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/debug/elf/file.go')
-rw-r--r--libgo/go/debug/elf/file.go161
1 files changed, 143 insertions, 18 deletions
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index 568370b857c..e69317a75fa 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -75,6 +75,15 @@ func (s *Section) Data() ([]byte, os.Error) {
return dat[0:n], err
}
+// stringTable reads and returns the string table given by the
+// specified link value.
+func (f *File) stringTable(link uint32) ([]byte, os.Error) {
+ if link <= 0 || link >= uint32(len(f.Sections)) {
+ return nil, os.ErrorString("section has invalid string table link")
+ }
+ return f.Sections[link].Data()
+}
+
// Open returns a new ReadSeeker reading the ELF section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
@@ -108,9 +117,9 @@ func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-
// A Symbol represents an entry in an ELF symbol table section.
type Symbol struct {
- Name uint32
+ Name string
Info, Other byte
- Section uint32
+ Section SectionIndex
Value, Size uint64
}
@@ -160,6 +169,17 @@ func (f *File) Close() os.Error {
return err
}
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ SectionType) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
// NewFile creates a new File for accessing an ELF binary in an underlying reader.
// The ELF binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, os.Error) {
@@ -293,9 +313,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
}
// Load section header string table.
- s := f.Sections[shstrndx]
- shstrtab := make([]byte, s.Size)
- if _, err := r.ReadAt(shstrtab, int64(s.Offset)); err != nil {
+ shstrtab, err := f.Sections[shstrndx].Data()
+ if err != nil {
return nil, err
}
for i, s := range f.Sections {
@@ -309,25 +328,65 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return f, nil
}
-func (f *File) getSymbols() ([]Symbol, os.Error) {
+// getSymbols returns a slice of Symbols from parsing the symbol table
+// with the given type.
+func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) {
switch f.Class {
case ELFCLASS64:
- return f.getSymbols64()
+ return f.getSymbols64(typ)
+
+ case ELFCLASS32:
+ return f.getSymbols32(typ)
}
return nil, os.ErrorString("not implemented")
}
-// GetSymbols returns a slice of Symbols from parsing the symbol table.
-func (f *File) getSymbols64() ([]Symbol, os.Error) {
- var symtabSection *Section
- for _, section := range f.Sections {
- if section.Type == SHT_SYMTAB {
- symtabSection = section
- break
- }
+func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, os.ErrorString("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, os.ErrorString("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym32Size != 0 {
+ return nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[0:])
+
+ symbols := make([]Symbol, symtab.Len()/Sym32Size)
+
+ i := 0
+ var sym Sym32
+ for symtab.Len() > 0 {
+ binary.Read(symtab, f.ByteOrder, &sym)
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
+ symbols[i].Info = sym.Info
+ symbols[i].Other = sym.Other
+ symbols[i].Section = SectionIndex(sym.Shndx)
+ symbols[i].Value = uint64(sym.Value)
+ symbols[i].Size = uint64(sym.Size)
+ i++
}
+ return symbols, nil
+}
+
+func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
if symtabSection == nil {
return nil, os.ErrorString("no symbol section")
}
@@ -341,6 +400,11 @@ func (f *File) getSymbols64() ([]Symbol, os.Error) {
return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
}
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
// The first entry is all zeros.
var skip [Sym64Size]byte
symtab.Read(skip[0:])
@@ -351,10 +415,11 @@ func (f *File) getSymbols64() ([]Symbol, os.Error) {
var sym Sym64
for symtab.Len() > 0 {
binary.Read(symtab, f.ByteOrder, &sym)
- symbols[i].Name = sym.Name
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
symbols[i].Info = sym.Info
symbols[i].Other = sym.Other
- symbols[i].Section = uint32(sym.Shndx)
+ symbols[i].Section = SectionIndex(sym.Shndx)
symbols[i].Value = sym.Value
symbols[i].Size = sym.Size
i++
@@ -403,7 +468,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
}
- symbols, err := f.getSymbols()
+ symbols, err := f.getSymbols(SHT_SYMTAB)
if err != nil {
return err
}
@@ -478,3 +543,63 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
abbrev, info, str := dat[0], dat[1], dat[2]
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ sym, err := f.getSymbols(SHT_DYNSYM)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for _, s := range sym {
+ if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
+ all = append(all, s.Name)
+ }
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ ds := f.SectionByType(SHT_DYNAMIC)
+ if ds == nil {
+ // not dynamic, so no libraries
+ return nil, nil
+ }
+ d, err := ds.Data()
+ if err != nil {
+ return nil, err
+ }
+ str, err := f.stringTable(ds.Link)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for len(d) > 0 {
+ var tag DynTag
+ var value uint64
+ switch f.Class {
+ case ELFCLASS32:
+ tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
+ value = uint64(f.ByteOrder.Uint32(d[4:8]))
+ d = d[8:]
+ case ELFCLASS64:
+ tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
+ value = f.ByteOrder.Uint64(d[8:16])
+ d = d[16:]
+ }
+ if tag == DT_NEEDED {
+ s, ok := getString(str, int(value))
+ if ok {
+ all = append(all, s)
+ }
+ }
+ }
+
+ return all, nil
+}