Commit 7aac3436 authored by Austin Clements's avatar Austin Clements

debug/elf: add version information to all dynamic symbols

Currently, File.ImportedSymbols is the only API that exposes the GNU
symbol version information for dynamic symbols. Unfortunately, it also
filters to specific types of symbols, and only returns symbol names.

The cgo tool is going to need symbol version information for more
symbols. In order to support this and make the API more orthogonal,
this CL adds version information to the Symbol type and updates
File.DynamicSymbols to fill this in. This has the downside of
increasing the size of Symbol, but seems to be the most natural API
for exposing this. I also explored 1) adding a method to get the
version information for the i'th dynamic symbol, but we don't use
symbol indexes anywhere else in the API, and it's not clear if this
index would be 0-based or 1-based, and 2) adding a
DynamicSymbolVersions method that returns a slice of version
information that parallels the DynamicSymbols slice, but that's less
efficient to implement and harder to use.

For #31912.

Change-Id: I69052ac3894f7af2aa9561f7085275130e0cf717
Reviewed-on: https://go-review.googlesource.com/c/go/+/184099
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 9a00e646
...@@ -171,6 +171,11 @@ type Symbol struct { ...@@ -171,6 +171,11 @@ type Symbol struct {
Info, Other byte Info, Other byte
Section SectionIndex Section SectionIndex
Value, Size uint64 Value, Size uint64
// Version and Library are present only for the dynamic symbol
// table.
Version string
Library string
} }
/* /*
...@@ -1228,12 +1233,23 @@ func (f *File) Symbols() ([]Symbol, error) { ...@@ -1228,12 +1233,23 @@ func (f *File) Symbols() ([]Symbol, error) {
// DynamicSymbols returns the dynamic symbol table for f. The symbols // DynamicSymbols returns the dynamic symbol table for f. The symbols
// will be listed in the order they appear in f. // will be listed in the order they appear in f.
// //
// If f has a symbol version table, the returned Symbols will have
// initialized Version and Library fields.
//
// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
// After retrieving the symbols as symtab, an externally supplied index x // After retrieving the symbols as symtab, an externally supplied index x
// corresponds to symtab[x-1], not symtab[x]. // corresponds to symtab[x-1], not symtab[x].
func (f *File) DynamicSymbols() ([]Symbol, error) { func (f *File) DynamicSymbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_DYNSYM) sym, str, err := f.getSymbols(SHT_DYNSYM)
return sym, err if err != nil {
return nil, err
}
if f.gnuVersionInit(str) {
for i := range sym {
sym[i].Library, sym[i].Version = f.gnuVersion(i)
}
}
return sym, nil
} }
type ImportedSymbol struct { type ImportedSymbol struct {
...@@ -1256,7 +1272,8 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { ...@@ -1256,7 +1272,8 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
for i, s := range sym { for i, s := range sym {
if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
all = append(all, ImportedSymbol{Name: s.Name}) all = append(all, ImportedSymbol{Name: s.Name})
f.gnuVersion(i, &all[len(all)-1]) sym := &all[len(all)-1]
sym.Library, sym.Version = f.gnuVersion(i)
} }
} }
return all, nil return all, nil
...@@ -1269,11 +1286,16 @@ type verneed struct { ...@@ -1269,11 +1286,16 @@ type verneed struct {
// gnuVersionInit parses the GNU version tables // gnuVersionInit parses the GNU version tables
// for use by calls to gnuVersion. // for use by calls to gnuVersion.
func (f *File) gnuVersionInit(str []byte) { func (f *File) gnuVersionInit(str []byte) bool {
if f.gnuNeed != nil {
// Already initialized
return true
}
// Accumulate verneed information. // Accumulate verneed information.
vn := f.SectionByType(SHT_GNU_VERNEED) vn := f.SectionByType(SHT_GNU_VERNEED)
if vn == nil { if vn == nil {
return return false
} }
d, _ := vn.Data() d, _ := vn.Data()
...@@ -1328,17 +1350,18 @@ func (f *File) gnuVersionInit(str []byte) { ...@@ -1328,17 +1350,18 @@ func (f *File) gnuVersionInit(str []byte) {
// Versym parallels symbol table, indexing into verneed. // Versym parallels symbol table, indexing into verneed.
vs := f.SectionByType(SHT_GNU_VERSYM) vs := f.SectionByType(SHT_GNU_VERSYM)
if vs == nil { if vs == nil {
return return false
} }
d, _ = vs.Data() d, _ = vs.Data()
f.gnuNeed = need f.gnuNeed = need
f.gnuVersym = d f.gnuVersym = d
return true
} }
// gnuVersion adds Library and Version information to sym, // gnuVersion adds Library and Version information to sym,
// which came from offset i of the symbol table. // which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) { func (f *File) gnuVersion(i int) (library string, version string) {
// Each entry is two bytes. // Each entry is two bytes.
i = (i + 1) * 2 i = (i + 1) * 2
if i >= len(f.gnuVersym) { if i >= len(f.gnuVersym) {
...@@ -1349,8 +1372,7 @@ func (f *File) gnuVersion(i int, sym *ImportedSymbol) { ...@@ -1349,8 +1372,7 @@ func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
return return
} }
n := &f.gnuNeed[j] n := &f.gnuNeed[j]
sym.Library = n.File return n.File, n.Name
sym.Version = n.Name
} }
// ImportedLibraries returns the names of all libraries // ImportedLibraries returns the names of all libraries
......
...@@ -819,6 +819,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ ...@@ -819,6 +819,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{
Section: 0x0, Section: 0x0,
Value: 0x0, Value: 0x0,
Size: 0x18C, Size: 0x18C,
Version: "GLIBC_2.2.5",
Library: "libc.so.6",
}, },
Symbol{ Symbol{
Name: "__libc_start_main", Name: "__libc_start_main",
...@@ -827,6 +829,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ ...@@ -827,6 +829,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{
Section: 0x0, Section: 0x0,
Value: 0x0, Value: 0x0,
Size: 0x1C2, Size: 0x1C2,
Version: "GLIBC_2.2.5",
Library: "libc.so.6",
}, },
}, },
"testdata/go-relocation-test-clang-x86.obj": {}, "testdata/go-relocation-test-clang-x86.obj": {},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment