diff options
Diffstat (limited to 'src/pkg/debug/elf/file.go')
-rw-r--r-- | src/pkg/debug/elf/file.go | 149 |
1 files changed, 125 insertions, 24 deletions
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go index 6fdcda6d4..9ae8b413d 100644 --- a/src/pkg/debug/elf/file.go +++ b/src/pkg/debug/elf/file.go @@ -35,9 +35,11 @@ type FileHeader struct { // A File represents an open ELF file. type File struct { FileHeader - Sections []*Section - Progs []*Prog - closer io.Closer + Sections []*Section + Progs []*Prog + closer io.Closer + gnuNeed []verneed + gnuVersym []byte } // A SectionHeader represents a single ELF section header. @@ -329,8 +331,8 @@ func NewFile(r io.ReaderAt) (*File, 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) { +// with the given type, along with the associated string table. +func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) { switch f.Class { case ELFCLASS64: return f.getSymbols64(typ) @@ -339,27 +341,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) { return f.getSymbols32(typ) } - return nil, os.ErrorString("not implemented") + return nil, nil, os.ErrorString("not implemented") } -func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) { +func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, os.ErrorString("no symbol section") + return nil, nil, os.ErrorString("no symbol section") } data, err := symtabSection.Data() if err != nil { - return nil, os.ErrorString("cannot load symbol section") + return nil, 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") + return nil, 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") + return nil, nil, os.ErrorString("cannot load string table section") } // The first entry is all zeros. @@ -382,27 +384,27 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) { i++ } - return symbols, nil + return symbols, strdata, nil } -func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) { +func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, os.ErrorString("no symbol section") + return nil, nil, os.ErrorString("no symbol section") } data, err := symtabSection.Data() if err != nil { - return nil, os.ErrorString("cannot load symbol section") + return nil, nil, os.ErrorString("cannot load symbol section") } symtab := bytes.NewBuffer(data) if symtab.Len()%Sym64Size != 0 { - return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size") + return nil, 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") + return nil, nil, os.ErrorString("cannot load string table section") } // The first entry is all zeros. @@ -425,7 +427,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) { i++ } - return symbols, nil + return symbols, strdata, nil } // getString extracts a string from an ELF string table. @@ -468,7 +470,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(SHT_SYMTAB) + symbols, _, err := f.getSymbols(SHT_SYMTAB) if err != nil { return err } @@ -544,24 +546,123 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) } +type ImportedSymbol struct { + Name string + Version string + Library string +} + // 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) +func (f *File) ImportedSymbols() ([]ImportedSymbol, os.Error) { + sym, str, err := f.getSymbols(SHT_DYNSYM) if err != nil { return nil, err } - var all []string - for _, s := range sym { + f.gnuVersionInit(str) + var all []ImportedSymbol + for i, s := range sym { if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { - all = append(all, s.Name) + all = append(all, ImportedSymbol{Name: s.Name}) + f.gnuVersion(i, &all[len(all)-1]) } } return all, nil } +type verneed struct { + File string + Name string +} + +// gnuVersionInit parses the GNU version tables +// for use by calls to gnuVersion. +func (f *File) gnuVersionInit(str []byte) { + // Accumulate verneed information. + vn := f.SectionByType(SHT_GNU_VERNEED) + if vn == nil { + return + } + d, _ := vn.Data() + + var need []verneed + i := 0 + for { + if i+16 > len(d) { + break + } + vers := f.ByteOrder.Uint16(d[i : i+2]) + if vers != 1 { + break + } + cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) + fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) + aux := f.ByteOrder.Uint32(d[i+8 : i+12]) + next := f.ByteOrder.Uint32(d[i+12 : i+16]) + file, _ := getString(str, int(fileoff)) + + var name string + j := i + int(aux) + for c := 0; c < int(cnt); c++ { + if j+16 > len(d) { + break + } + // hash := f.ByteOrder.Uint32(d[j:j+4]) + // flags := f.ByteOrder.Uint16(d[j+4:j+6]) + other := f.ByteOrder.Uint16(d[j+6 : j+8]) + nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) + next := f.ByteOrder.Uint32(d[j+12 : j+16]) + name, _ = getString(str, int(nameoff)) + ndx := int(other) + if ndx >= len(need) { + a := make([]verneed, 2*(ndx+1)) + copy(a, need) + need = a + } + + need[ndx] = verneed{file, name} + if next == 0 { + break + } + j += int(next) + } + + if next == 0 { + break + } + i += int(next) + } + + // Versym parallels symbol table, indexing into verneed. + vs := f.SectionByType(SHT_GNU_VERSYM) + if vs == nil { + return + } + d, _ = vs.Data() + + f.gnuNeed = need + f.gnuVersym = d +} + +// gnuVersion adds Library and Version information to sym, +// which came from offset i of the symbol table. +func (f *File) gnuVersion(i int, sym *ImportedSymbol) { + // Each entry is two bytes; skip undef entry at beginning. + i = (i + 1) * 2 + if i >= len(f.gnuVersym) { + return + } + j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) + if j < 2 || j >= len(f.gnuNeed) { + return + } + n := &f.gnuNeed[j] + sym.Library = n.File + sym.Version = n.Name +} + // 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. |