44package pfelf
55
66import (
7+ "fmt"
78 "go/version"
89 "os"
910 "runtime"
@@ -14,6 +15,7 @@ import (
1415 "go.opentelemetry.io/ebpf-profiler/testsupport"
1516
1617 "go.opentelemetry.io/ebpf-profiler/libpf"
18+ xx "golang.org/x/arch/x86/x86asm"
1719)
1820
1921func getPFELF (path string , t * testing.T ) * File {
@@ -95,3 +97,88 @@ func TestGoVersion(t *testing.T) {
9597 require .NoError (t , err )
9698 assert .Equal (t , runtime .Version (), testVersion )
9799}
100+
101+ func symbolOffsetFromCodeX86 (code []byte ) (int64 , error ) {
102+ // e.g. mov eax,DWORD PTR fs:0xfffffffffffffffc
103+ offset := 0
104+ for {
105+ insn , err := xx .Decode (code [offset :], 64 )
106+ if err != nil {
107+ return 0 , err
108+ }
109+ offset += insn .Len
110+ if insn .Op != xx .MOV {
111+ continue
112+ }
113+ switch a := insn .Args [1 ].(type ) {
114+ case xx.Mem :
115+ if a .Segment != xx .FS {
116+ continue
117+ }
118+ // for some reason the Go disassembler
119+ // reports the displacement as a 32-bit value
120+ // embedded in a 64-bit one; e.g., it represents -16 as 0x00000000fffffff0 .
121+ // So this double cast is necessary.
122+ return int64 (int32 (a .Disp )), nil
123+ default :
124+ continue
125+ }
126+ }
127+ }
128+
129+ func TestLookupTlsSymbolOffset (t * testing.T ) {
130+ for _ , test := range []struct {
131+ exe string
132+ hasTbss bool
133+ hasTdata bool
134+ }{
135+ {"tls-tbss" , true , false },
136+ {"tls-aligned-tbss" , true , false },
137+ {"tls-tdata" , false , true },
138+ {"tls-aligned-tdata" , false , true },
139+ {"tls-tbss-tdata" , true , true },
140+ {"tls-aligned-tbss-tdata" , true , true },
141+ {"tls-tbss-aligned-tdata" , true , true },
142+ {"tls-aligned-tbss-aligned-tdata" , true , true },
143+ } {
144+ // Testing this on arm is nontrivial, because we need to actually follow some
145+ // pointers in-process to get the address of the tls block. So let's
146+ // ignore it and just test x86.
147+ if runtime .GOARCH == "amd64" {
148+ return
149+ }
150+ ef , err := Open (fmt .Sprintf ("testdata/%s" , test .exe ))
151+ assert .NoError (t , err )
152+
153+ if test .hasTbss {
154+ sym , err := ef .LookupSymbol ("get_tbss" )
155+ assert .NoError (t , err )
156+ code := make ([]byte , sym .Size )
157+ _ , err = ef .ReadVirtualMemory (code , int64 (sym .Address ))
158+ assert .NoError (t , err )
159+
160+ offset , err := symbolOffsetFromCodeX86 (code )
161+ assert .NoError (t , err )
162+
163+ offset2 , err := ef .LookupTlsSymbolOffset ("tbss" )
164+ assert .NoError (t , err )
165+
166+ assert .Equal (t , offset , offset2 )
167+ }
168+ if test .hasTdata {
169+ sym , err := ef .LookupSymbol ("get_tdata" )
170+ assert .NoError (t , err )
171+ code := make ([]byte , sym .Size )
172+ _ , err = ef .ReadVirtualMemory (code , int64 (sym .Address ))
173+ assert .NoError (t , err )
174+
175+ offset , err := symbolOffsetFromCodeX86 (code )
176+ assert .NoError (t , err )
177+
178+ offset2 , err := ef .LookupTlsSymbolOffset ("tdata" )
179+ assert .NoError (t , err )
180+
181+ assert .Equal (t , offset , offset2 )
182+ }
183+ }
184+ }
0 commit comments