@@ -13,11 +13,73 @@ import (
1313)
1414
1515type TSDInfo = support.TSDInfo
16+ type DTVInfo = support.DTVInfo
1617
1718// LibcInfo contains introspection information extracted from the C-library
1819type LibcInfo struct {
1920 // TSDInfo is the TSDInfo extracted for this C-library
2021 TSDInfo TSDInfo
22+ // DTVInfo contains DTV (Dynamic Thread Vector) introspection data for accessing
23+ // TLS variables when TLS descriptors are not available
24+ DTVInfo DTVInfo
25+ }
26+
27+ // IsEqual checks if two LibcInfo instances are equal
28+ func (l LibcInfo ) IsEqual (other LibcInfo ) bool {
29+ return l .TSDInfo == other .TSDInfo && l .DTVInfo == other .DTVInfo
30+ }
31+
32+ // Merge fills in empty fields of the receiver with corresponding values from other.
33+ // Fields already populated in the receiver are not overwritten.
34+ func (l * LibcInfo ) Merge (other LibcInfo ) {
35+ // If other has TSDInfo and this instance does not, take it
36+ if l .TSDInfo == (TSDInfo {}) {
37+ l .TSDInfo = other .TSDInfo
38+ }
39+
40+ // If other has DTVInfo and this instance does not, take it
41+ if l .DTVInfo == (DTVInfo {}) {
42+ l .DTVInfo = other .DTVInfo
43+ }
44+ }
45+
46+ // HasTSDInfo returns true if the LibcInfo contains valid TSD information.
47+ // TSDInfo is considered valid when the Multiplier field is non-zero.
48+ func (l LibcInfo ) HasTSDInfo () bool {
49+ return l .TSDInfo .Multiplier != 0
50+ }
51+
52+ // HasDTVInfo returns true if the LibcInfo contains valid DTV information.
53+ // DTVInfo is considered valid when the Multiplier field is non-zero.
54+ func (l LibcInfo ) HasDTVInfo () bool {
55+ return l .DTVInfo .Multiplier != 0
56+ }
57+
58+ var (
59+ // regex for the libc
60+ libcRegex = regexp .MustCompile (`.*/(ld-musl|ld-linux|libc|libpthread)([-.].*)?\.so` )
61+ )
62+
63+ // IsPotentialLibcDSO determines if the DSO filename potentially contains libc code
64+ func IsPotentialLibcDSO (filename string ) bool {
65+ return libcRegex .MatchString (filename )
66+ }
67+
68+ func ExtractLibcInfo (ef * pfelf.File ) (* LibcInfo , error ) {
69+ tsdinfo , err := extractTSDInfo (ef )
70+ if err != nil {
71+ return nil , err
72+ }
73+
74+ dtvinfo , err := extractDTVInfo (ef )
75+ if err != nil {
76+ return & LibcInfo {}, err
77+ }
78+
79+ return & LibcInfo {
80+ TSDInfo : tsdinfo ,
81+ DTVInfo : dtvinfo ,
82+ }, nil
2183}
2284
2385// This code analyzes the C-library provided POSIX defined function which is used
@@ -65,27 +127,6 @@ type LibcInfo struct {
65127//
66128// Reading the value is basically "return self->specific_1stblock[key].data;"
67129
68- var (
69- // regex for the libc
70- libcRegex = regexp .MustCompile (`.*/(ld-musl|libc|libpthread)([-.].*)?\.so` )
71- )
72-
73- // IsPotentialTSDDSO determines if the DSO filename potentially contains pthread code
74- func IsPotentialTSDDSO (filename string ) bool {
75- return libcRegex .MatchString (filename )
76- }
77-
78- func ExtractLibcInfo (ef * pfelf.File ) (* LibcInfo , error ) {
79- tsdinfo , err := extractTSDInfo (ef )
80- if err != nil {
81- return nil , err
82- }
83-
84- return & LibcInfo {
85- TSDInfo : tsdinfo ,
86- }, nil
87- }
88-
89130// extractTSDInfo extracts the introspection data for pthread thread specific data.
90131func extractTSDInfo (ef * pfelf.File ) (TSDInfo , error ) {
91132 _ , code , err := ef .SymbolData ("__pthread_getspecific" , 2048 )
@@ -113,3 +154,31 @@ func extractTSDInfo(ef *pfelf.File) (TSDInfo, error) {
113154 }
114155 return info , nil
115156}
157+
158+ // extractDTVInfo extracts the introspection data for the DTV to access TLS vars
159+ func extractDTVInfo (ef * pfelf.File ) (DTVInfo , error ) {
160+ var info DTVInfo
161+ _ , code , err := ef .SymbolData ("__tls_get_addr" , 2048 )
162+ if err != nil {
163+ // If the symbol is not exported, this is not a critical error.
164+ // Callers can check HasDTVInfo() to determine if DTV data is available.
165+ return info , nil
166+ }
167+
168+ if len (code ) < 8 {
169+ return info , fmt .Errorf ("__tls_get_addr function size is %d" , len (code ))
170+ }
171+
172+ switch ef .Machine {
173+ case elf .EM_AARCH64 :
174+ info , err = extractDTVInfoARM (code )
175+ case elf .EM_X86_64 :
176+ info , err = extractDTVInfoX86 (code )
177+ default :
178+ return info , fmt .Errorf ("unsupported arch %s" , ef .Machine .String ())
179+ }
180+ if err != nil {
181+ return info , fmt .Errorf ("failed to extract DTV data: %s" , err )
182+ }
183+ return info , nil
184+ }
0 commit comments