11// Copyright The OpenTelemetry Authors
22// SPDX-License-Identifier: Apache-2.0
33
4- package tpbase // import "go.opentelemetry.io/ebpf-profiler/tpbase "
4+ package libc // import "go.opentelemetry.io/ebpf-profiler/libc "
55
66import (
77 "debug/elf"
88 "fmt"
99 "regexp"
1010
11+ "go.opentelemetry.io/ebpf-profiler/internal/log"
12+
1113 "go.opentelemetry.io/ebpf-profiler/libpf/pfelf"
1214)
1315
16+ type LibcInfo struct {
17+ DTVInfo * DTVInfo
18+ TSDInfo * TSDInfo
19+ }
20+
21+ type DTVInfo struct {
22+ Offset int64 // Offset of DTV from FS base (or from thread pointer)
23+ EntryWidth uint32 // Width of each DTV entry in bytes
24+ Indirect uint8 // 0 if DTV is at FS+offset, 1 if at [FS+0]+offset
25+ }
26+
1427// TSDInfo contains information to access C-library's Thread Specific Data from eBPF
1528type TSDInfo struct {
1629 // Offset is the pointer difference from "tpbase" pointer to the C-library
@@ -84,8 +97,25 @@ func IsPotentialTSDDSO(filename string) bool {
8497 return libcRegex .MatchString (filename )
8598}
8699
100+ func ExtractLibcInfo (ef * pfelf.File ) (* LibcInfo , error ) {
101+ tsdinfo , err := extractTSDInfo (ef )
102+ if err != nil {
103+ return nil , err
104+ }
105+
106+ dtvinfo , err := extractDTVInfo (ef )
107+ if err != nil {
108+ return nil , err
109+ }
110+
111+ return & LibcInfo {
112+ TSDInfo : tsdinfo ,
113+ DTVInfo : dtvinfo ,
114+ }, nil
115+ }
116+
87117// ExtractTSDInfo extracts the introspection data for pthread thread specific data.
88- func ExtractTSDInfo (ef * pfelf.File ) (* TSDInfo , error ) {
118+ func extractTSDInfo (ef * pfelf.File ) (* TSDInfo , error ) {
89119 _ , code , err := ef .SymbolData ("__pthread_getspecific" , 2048 )
90120 if err != nil {
91121 _ , code , err = ef .SymbolData ("pthread_getspecific" , 2048 )
@@ -111,3 +141,33 @@ func ExtractTSDInfo(ef *pfelf.File) (*TSDInfo, error) {
111141 }
112142 return & info , nil
113143}
144+
145+ // extractDTVInfo extracts the introspection data for the DTV to access TLS vars
146+ func extractDTVInfo (ef * pfelf.File ) (* DTVInfo , error ) {
147+ var info DTVInfo
148+ _ , code , err := ef .SymbolData ("__tls_get_addr" , 2048 )
149+ if err != nil {
150+ // Only error out reading DTV if we have the symbol, but fail to parse it
151+ // if the symbol is not exported, failing to read it is not a critical error
152+ // and empty DTV introspection data is returned
153+ log .Warnf ("unable to read '__tls_get_addr': %s, libc DTV introspection data is unavailable" , err )
154+ return & info , nil
155+ }
156+
157+ if len (code ) < 8 {
158+ return nil , fmt .Errorf ("__tls_get_addr function size is %d" , len (code ))
159+ }
160+
161+ switch ef .Machine {
162+ case elf .EM_AARCH64 :
163+ info , err = extractDTVInfoARM (code )
164+ case elf .EM_X86_64 :
165+ info , err = extractDTVInfoX86 (code )
166+ default :
167+ return & info , fmt .Errorf ("unsupported arch %s" , ef .Machine .String ())
168+ }
169+ if err != nil {
170+ return & info , fmt .Errorf ("failed to extract DTV data: %s" , err )
171+ }
172+ return & info , nil
173+ }
0 commit comments