11import Base. BinaryPlatforms: detect_libstdcxx_version, detect_cxxstring_abi
22using ObjectFile
3+ using ObjectFile. ELF
34using Binutils_jll: Binutils_jll
45
56csl_warning (lib) = @lock AUDITOR_LOGGING_LOCK @warn (
@@ -195,6 +196,85 @@ function cppfilt(symbol_names::Vector, platform::AbstractPlatform; strip_undersc
195196 return filter! (s -> ! isempty (s), split (String (take! (output)), " \n " ))
196197end
197198
199+ function dynamic_abi_symbols (oh:: ELFHandle )
200+ dyn_sections = findall (Sections (oh), " .dynsym" )
201+ if ! isempty (dyn_sections)
202+ return Symbols (first (dyn_sections))
203+ end
204+ return nothing
205+ end
206+
207+ abi_symbol_names (syms) = symbol_name .(syms)
208+
209+ function lookup_strtab (strtab:: AbstractVector{UInt8} , index:: Integer )
210+ i = Int (index) + 1
211+ j = findnext (== (0x00 ), strtab, i)
212+ j === nothing && return String (strtab[i: end ])
213+ return String (strtab[i: j- 1 ])
214+ end
215+
216+ function abi_symbol_names (syms:: ELFSymbols )
217+ strtab = read (StrTab (syms). section_ref)
218+ return [lookup_strtab (strtab, deref (sym). st_name) for sym in syms]
219+ end
220+
221+ has_cxx11_marker (symbol_name:: AbstractString ) = occursin (" St7__cxx11" , symbol_name) ||
222+ occursin (" B5cxx11" , symbol_name) ||
223+ occursin (" std::__cxx11" , symbol_name) ||
224+ occursin (" [abi:cxx11]" , symbol_name)
225+ has_cxx03_marker (symbol_name:: AbstractString ) = startswith (symbol_name, " _ZNSs" ) || startswith (symbol_name, " _ZNSb" )
226+
227+ function detect_cxxstring_abi (symbol_names:: Vector{<:AbstractString} , platform:: AbstractPlatform )
228+ # Fast paths on mangled names. These avoid invoking c++filt for large C++
229+ # libraries when the ABI evidence is already visible in the raw symbol names.
230+ if any (has_cxx11_marker, symbol_names)
231+ return " cxx11"
232+ end
233+ if any (has_cxx03_marker, symbol_names)
234+ return " cxx03"
235+ end
236+
237+ demangled_names = cppfilt (symbol_names, platform; strip_underscore= Sys. isapple (platform))
238+ if any (occursin (" [abi:cxx11]" , c) || occursin (" std::__cxx11" , c) for c in demangled_names)
239+ return " cxx11"
240+ end
241+ if any (occursin (" std::string" , c) || occursin (" std::basic_string" , c) ||
242+ occursin (" std::list" , c) for c in demangled_names)
243+ return " cxx03"
244+ end
245+ return nothing
246+ end
247+
248+ detect_cxxstring_abi_from_symbols (syms, platform:: AbstractPlatform ) = detect_cxxstring_abi (abi_symbol_names (syms), platform)
249+
250+ function detect_dynamic_cxx11_abi (oh:: ELFHandle )
251+ syms = dynamic_abi_symbols (oh)
252+ syms === nothing && return nothing
253+
254+ strtab = read (StrTab (syms). section_ref)
255+ for sym in syms
256+ symbol_name = lookup_strtab (strtab, deref (sym). st_name)
257+ has_cxx11_marker (symbol_name) && return " cxx11"
258+ end
259+ return nothing
260+ end
261+
262+ function detect_cxxstring_abi_from_symbols (syms:: ELFSymbols , platform:: AbstractPlatform )
263+ strtab = read (StrTab (syms). section_ref)
264+ symbol_names = String[]
265+ found_cxx03 = false
266+ for sym in syms
267+ symbol_name = lookup_strtab (strtab, deref (sym). st_name)
268+ if has_cxx11_marker (symbol_name)
269+ return " cxx11"
270+ end
271+ found_cxx03 |= has_cxx03_marker (symbol_name)
272+ push! (symbol_names, symbol_name)
273+ end
274+ found_cxx03 && return " cxx03"
275+ return detect_cxxstring_abi (symbol_names, platform)
276+ end
277+
198278"""
199279 detect_cxxstring_abi(oh::ObjectHandle, platform::AbstractPlatform)
200280
@@ -210,20 +290,12 @@ function detect_cxxstring_abi(oh::ObjectHandle, platform::AbstractPlatform)
210290 return nothing
211291 end
212292
213- # GCC on macOS prepends an underscore to symbols, strip it.
214- symbol_names = cppfilt (symbol_name .(Symbols (oh)), platform; strip_underscore= Sys. isapple (platform))
215- # Shove the symbol names through c++filt (since we don't want to have to
216- # reimplement the parsing logic in Julia). If anything has `cxx11` tags,
217- # then mark it as such.
218- if any (occursin (" [abi:cxx11]" , c) || occursin (" std::__cxx11" , c) for c in symbol_names)
219- return " cxx11"
220- end
221- # Otherwise, if we still have `std::string`'s or `std::list`'s in there, it's implicitly a
222- # `cxx03` binary, even though we don't have a __cxx03 namespace or something. Mark it.
223- if any (occursin (" std::string" , c) || occursin (" std::basic_string" , c) ||
224- occursin (" std::list" , c) for c in symbol_names)
225- return " cxx03"
293+ if isa (oh, ELFHandle)
294+ cxx_abi = detect_dynamic_cxx11_abi (oh)
295+ cxx_abi === nothing || return cxx_abi
226296 end
297+
298+ return detect_cxxstring_abi_from_symbols (Symbols (oh), platform)
227299 catch e
228300 if isa (e, InterruptException)
229301 rethrow (e)
0 commit comments