]> Cypherpunks repositories - gostls13.git/commitdiff
debug/elf: add version information to all dynamic symbols
authorAustin Clements <austin@google.com>
Thu, 27 Jun 2019 22:03:15 +0000 (18:03 -0400)
committerAustin Clements <austin@google.com>
Fri, 5 Jul 2019 18:18:26 +0000 (18:18 +0000)
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>
src/debug/elf/file.go
src/debug/elf/symbols_test.go

index f92a2b005253850effcd95248caba3bfddf83760..79ef467145261c117394fd8b294f49c35c378d50 100644 (file)
@@ -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
index 1b79520e3ccb56c39bc61ebb3b8a575293a0498d..42f02312e871dda91417d861480631f5ef2e22e5 100644 (file)
@@ -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": {},