diff options
| author | Austin Clements <austin@google.com> | 2019-06-27 18:03:15 -0400 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2019-07-05 18:18:26 +0000 |
| commit | 7aac3436dde7f247e8602f49317c17563def89ab (patch) | |
| tree | 23196349d183f1bb644c1a40dd1c0eb3d5084c0f /src/debug/elf | |
| parent | 9a00e64633ce3636d9ea94660168d96be3416df8 (diff) | |
| download | go-7aac3436dde7f247e8602f49317c17563def89ab.tar.xz | |
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: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/debug/elf')
| -rw-r--r-- | src/debug/elf/file.go | 40 | ||||
| -rw-r--r-- | src/debug/elf/symbols_test.go | 4 |
2 files changed, 35 insertions, 9 deletions
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index f92a2b0052..79ef467145 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -171,6 +171,11 @@ type Symbol struct { Info, Other byte Section SectionIndex 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) { // DynamicSymbols returns the dynamic symbol table for f. The symbols // 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. // After retrieving the symbols as symtab, an externally supplied index x // corresponds to symtab[x-1], not symtab[x]. func (f *File) DynamicSymbols() ([]Symbol, error) { - sym, _, err := f.getSymbols(SHT_DYNSYM) - return sym, err + sym, str, err := f.getSymbols(SHT_DYNSYM) + 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 { @@ -1256,7 +1272,8 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { for i, s := range sym { if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { 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 @@ -1269,11 +1286,16 @@ type verneed struct { // gnuVersionInit parses the GNU version tables // 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. vn := f.SectionByType(SHT_GNU_VERNEED) if vn == nil { - return + return false } d, _ := vn.Data() @@ -1328,17 +1350,18 @@ func (f *File) gnuVersionInit(str []byte) { // Versym parallels symbol table, indexing into verneed. vs := f.SectionByType(SHT_GNU_VERSYM) if vs == nil { - return + return false } d, _ = vs.Data() f.gnuNeed = need f.gnuVersym = d + return true } // 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) { +func (f *File) gnuVersion(i int) (library string, version string) { // Each entry is two bytes. i = (i + 1) * 2 if i >= len(f.gnuVersym) { @@ -1349,8 +1372,7 @@ func (f *File) gnuVersion(i int, sym *ImportedSymbol) { return } n := &f.gnuNeed[j] - sym.Library = n.File - sym.Version = n.Name + return n.File, n.Name } // ImportedLibraries returns the names of all libraries diff --git a/src/debug/elf/symbols_test.go b/src/debug/elf/symbols_test.go index 1b79520e3c..42f02312e8 100644 --- a/src/debug/elf/symbols_test.go +++ b/src/debug/elf/symbols_test.go @@ -819,6 +819,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Section: 0x0, Value: 0x0, Size: 0x18C, + Version: "GLIBC_2.2.5", + Library: "libc.so.6", }, Symbol{ Name: "__libc_start_main", @@ -827,6 +829,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Section: 0x0, Value: 0x0, Size: 0x1C2, + Version: "GLIBC_2.2.5", + Library: "libc.so.6", }, }, "testdata/go-relocation-test-clang-x86.obj": {}, |
