Skip to content

Commit ccac6af

Browse files
committed
Add a test
1 parent 6b908e5 commit ccac6af

4 files changed

Lines changed: 166 additions & 1 deletion

File tree

libpf/pfelf/file_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package pfelf
55

66
import (
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

1921
func 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+
}

libpf/pfelf/testdata/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ kernel-image
55
ubuntu-kernel-image
66
go-binary
77
separate-debug-file
8+
tls-*
9+
!tls-lookup.c

libpf/pfelf/testdata/Makefile

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@ BINARIES=fixed-address \
1010
the_notorious_build_id \
1111
ubuntu-kernel-image \
1212
with-debug-syms \
13-
without-debug-syms
13+
without-debug-syms \
14+
tls-tbss \
15+
tls-aligned-tbss \
16+
tls-tdata \
17+
tls-aligned-tdata \
18+
tls-tbss-tdata \
19+
tls-aligned-tbss-tdata \
20+
tls-tbss-aligned-tdata \
21+
tls-aligned-tbss-aligned-tdata
1422

1523
all: $(BINARIES)
1624

@@ -47,3 +55,32 @@ ubuntu-kernel-image: test.c
4755
go-binary: gotest.go
4856
go build -o go-binary -ldflags "-w -s" gotest.go
4957

58+
# -fcf-protection=none is only necessary to avoid
59+
# emitting 'endbr64' which the Go disassembler can't
60+
# handle.
61+
#
62+
# -Wl,-E makes all the symbols dynamic.
63+
64+
tls-tbss: tls-lookup.c
65+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 $< -o $@
66+
67+
tls-aligned-tbss: tls-lookup.c
68+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 -DTBSS_ALIGN=1 $< -o $@
69+
70+
tls-tdata: tls-lookup.c
71+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TDATA=1 $< -o $@
72+
73+
tls-aligned-tdata: tls-lookup.c
74+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TDATA=1 -DTDATA_ALIGN=1 $< -o $@
75+
76+
tls-tbss-tdata: tls-lookup.c
77+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 -DHAS_TDATA=1 $< -o $@
78+
79+
tls-aligned-tbss-tdata: tls-lookup.c
80+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 -DTBSS_ALIGN=1 -DHAS_TDATA=1 $< -o $@
81+
82+
tls-tbss-aligned-tdata: tls-lookup.c
83+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 -DHAS_TDATA=1 -DTDATA_ALIGN=1 $< -o $@
84+
85+
tls-aligned-tbss-aligned-tdata: tls-lookup.c
86+
$(CC) -Wl,-E -fcf-protection=none -DHAS_TBSS=1 -DTDATA_ALIGN=1 -DHAS_TDATA=1 -DTDATA_ALIGN=1 $< -o $@

libpf/pfelf/testdata/tls-lookup.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifdef HAS_TBSS
2+
#ifdef TBSS_ALIGN
3+
#define ALIGNMENT __attribute__((aligned(32)))
4+
#else
5+
#define ALIGNMENT
6+
#endif
7+
int __thread ALIGNMENT tbss = 0;
8+
9+
int get_tbss()
10+
{
11+
return tbss;
12+
}
13+
#undef ALIGNMENT
14+
#endif
15+
16+
#ifdef HAS_TDATA
17+
#ifdef TDATA_ALIGN
18+
#define ALIGNMENT __attribute__((aligned(32)))
19+
#else
20+
#define ALIGNMENT
21+
#endif
22+
int __thread ALIGNMENT tdata = 42;
23+
24+
int get_tdata()
25+
{
26+
return tdata;
27+
}
28+
29+
#undef ALIGNMENT
30+
#endif
31+
32+
33+
#include <unistd.h>
34+
35+
int main()
36+
{
37+
for (;;)
38+
sleep(1);
39+
}

0 commit comments

Comments
 (0)