-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
I'm porting @brendangregg's eBPF profiling application profile.py to Golang. I'm attempting to use the debug/elf
package for retrieving debug symbol info but have stumbled upon a limitation.
As a demonstration I've picked a library called libtiffxx.so
as it's relatively small and clearly demontrates the issues I have with the package.
Let's take a look at the .gnu.version*
sections contained in the library:
$ readelf -SW /usr/lib/x86_64-linux-gnu/libtiffxx.so | grep .gnu.version
[ 6] .gnu.version VERSYM 0000000000000882 000882 000036 02 A 4 0 2
[ 7] .gnu.version_d VERDEF 00000000000008b8 0008b8 000038 00 A 5 2 8
[ 8] .gnu.version_r VERNEED 00000000000008f0 0008f0 000090 00 A 5 3 8
There's important debug symbol information contained in the .gnu.version_d
(SHT_GNU_VERDEF) section which is currently not parsed by the package. Let's look at the last four functions in the .dynsym
section.
$ readelf -sW /usr/lib/x86_64-linux-gnu/libtiffxx.so | tail -4
23: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (3)
24: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS LIBTIFFXX_4.0
25: 0000000000001890 169 FUNC GLOBAL DEFAULT 15 _Z14TIFFStreamOpenPKcPSo@@LIBTIFFXX_4.0
26: 0000000000001940 19 FUNC GLOBAL DEFAULT 15 _Z14TIFFStreamOpenPKcPSi@@LIBTIFFXX_4.0
The debug/elf
package can retreive the function name, but what about the @
or @@
, the library name after it or even the number in the brackets? In my proposal and my current implementation I provide a way to access this important debug symbol information.
If we take a look at the dynamic symbol output of these four functions in the current implementation of debug/elf
we have the following output:
Symbol{
Name: "_ZNSt8ios_base4InitD1Ev",
Info: 0x12,
Other: 0x0,
Section: 0x0,
Value: 0x0,
Size: 0x0,
Version: "GLIBCXX_3.4",
Library: "libstdc++.so.6",
},
Symbol{
Name: "LIBTIFFXX_4.0",
Info: 0x11,
Other: 0x0,
Section: 0xFFF1,
Value: 0x0,
Size: 0x0,
},
Symbol{
Name: "_Z14TIFFStreamOpenPKcPSo",
Info: 0x12,
Other: 0x0,
Section: 0xF,
Value: 0x1890,
Size: 0xA9,
},
Symbol{
Name: "_Z14TIFFStreamOpenPKcPSi",
Info: 0x12,
Other: 0x0,
Section: 0xF,
Value: 0x1940,
Size: 0x13,
},
In my new implemenation we get this output:
Symbol{
Name: "_ZNSt8ios_base4InitD1Ev",
Info: 0x12,
Other: 0x0,
Section: 0x0,
Value: 0x0,
Size: 0x0,
Version: "GLIBCXX_3.4",
Library: "libstdc++.so.6",
VerInfo: 0x1,
VerOther: 0x3,
},
Symbol{
Name: "LIBTIFFXX_4.0",
Info: 0x11,
Other: 0x0,
Section: 0xFFF1,
Value: 0x0,
Size: 0x0,
Version: "LIBTIFFXX_4.0",
Library: "",
VerInfo: 0x2,
VerOther: 0x1,
},
Symbol{
Name: "_Z14TIFFStreamOpenPKcPSo",
Info: 0x12,
Other: 0x0,
Section: 0xF,
Value: 0x1890,
Size: 0xA9,
Version: "LIBTIFFXX_4.0",
Library: "",
VerInfo: 0x2,
VerOther: 0x1,
},
Symbol{
Name: "_Z14TIFFStreamOpenPKcPSi",
Info: 0x12,
Other: 0x0,
Section: 0xF,
Value: 0x1940,
Size: 0x13,
Version: "LIBTIFFXX_4.0",
Library: "",
VerInfo: 0x2,
VerOther: 0x1,
},
We now have the Version
entry as is often retrieved from SHT_GNU_VERNEED
but in the last three entries can only be obtained from the SHT_GNU_VERDEF
section. We also have two new Symbol
members called VerInfo
and VerOther
.
So what are these new values and where do they come from? Using binutil's readelf.c
as a reference we can find out where this data is located and how to extract it.
VerInfo
in this case refers to the number in the brackets. In the case of _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (3)
the number 3 comes from VerOther
which is the version number. If it's 1
we don't display it in the brackets. The single @
comes from VerInfo
which can be one of three values:
// Versioned symbol info
const (
SymUndefined byte = 0
SymHidden byte = 1
SymPublic byte = 2
)
If the value is SymHidden
it will be @
and if it's SymPublic
it will be @@
. This is taken from readelf.c
So I have implemented the code to do the necessary parsing of the SHT_GNU_VERDEF
section and am writing this proposal so I can submit my changes to Gerrit for review by the Golang team.
Currently I have made changes to the following files in src/debug/elf
:
- Change
file_test.go
- Change
file.go
- Change
symbols_test.go
- Added
testdata/libtiffxx.so
(should be renamed?)
As I mentioned I use libtiffxx.so
as my testdata ELF binary because it's relatively small (14.4 kB) and it demonstrates the new data from which my new branch can parse.
My changes currently pass all tests except for the API check
##### API check
+pkg debug/elf, const SymHidden = 1
+pkg debug/elf, const SymHidden uint8
+pkg debug/elf, const SymPublic = 2
+pkg debug/elf, const SymPublic uint8
+pkg debug/elf, const SymUndefined = 0
+pkg debug/elf, const SymUndefined uint8
+pkg debug/elf, type ImportedSymbol struct, VerInfo uint8
+pkg debug/elf, type ImportedSymbol struct, VerOther uint8
+pkg debug/elf, type Symbol struct, VerInfo uint8
+pkg debug/elf, type Symbol struct, VerOther uint8
--- FAIL: TestCheck (26.62s)
main_test.go:184: API differences found
Thanks for taking the time to review my proposal.
Metadata
Metadata
Assignees
Type
Projects
Status