os/linux/elf: avoid using ldd for listing dynamic dependencies
This commit is contained in:
parent
c6b98d0b8c
commit
a4e0ccc1f6
@ -1,6 +1,8 @@
|
|||||||
# typed: true
|
# typed: true
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "os/linux/ld"
|
||||||
|
|
||||||
# {Pathname} extension for dealing with ELF files.
|
# {Pathname} extension for dealing with ELF files.
|
||||||
# @see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
|
# @see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
|
||||||
#
|
#
|
||||||
@ -130,19 +132,7 @@ module ELFShim
|
|||||||
@dylib_id, needed = needed_libraries path
|
@dylib_id, needed = needed_libraries path
|
||||||
return if needed.empty?
|
return if needed.empty?
|
||||||
|
|
||||||
ldd = DevelopmentTools.locate "ldd"
|
@dylibs = needed.map { |lib| find_full_lib_path(lib).to_s }
|
||||||
ldd_output = Utils.popen_read(ldd, path.expand_path.to_s).split("\n")
|
|
||||||
return unless $CHILD_STATUS.success?
|
|
||||||
|
|
||||||
ldd_paths = ldd_output.filter_map do |line|
|
|
||||||
match = line.match(/\t.+ => (.+) \(.+\)|\t(.+) => not found/)
|
|
||||||
next unless match
|
|
||||||
|
|
||||||
match.captures.compact.first
|
|
||||||
end
|
|
||||||
@dylibs = ldd_paths.select do |ldd_path|
|
|
||||||
needed.include? File.basename(ldd_path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -157,6 +147,52 @@ module ELFShim
|
|||||||
patcher = path.patchelf_patcher
|
patcher = path.patchelf_patcher
|
||||||
[patcher.soname, patcher.needed]
|
[patcher.soname, patcher.needed]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_full_lib_path(basename)
|
||||||
|
local_paths = (path.patchelf_patcher.runpath || path.patchelf_patcher.rpath)&.split(":")
|
||||||
|
|
||||||
|
# Search for dependencies in the runpath/rpath first
|
||||||
|
local_paths&.each do |local_path|
|
||||||
|
candidate = Pathname(local_path)/basename
|
||||||
|
return candidate if candidate.exist? && candidate.elf?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if DF_1_NODEFLIB is set
|
||||||
|
dt_flags_1 = path.patchelf_patcher.elf.segment_by_type(:dynamic)&.tag_by_type(:flags_1)
|
||||||
|
nodeflib_flag = if dt_flags_1.nil?
|
||||||
|
false
|
||||||
|
else
|
||||||
|
dt_flags_1.value & ELFTools::Constants::DF::DF_1_NODEFLIB != 0
|
||||||
|
end
|
||||||
|
|
||||||
|
linker_library_paths = OS::Linux::Ld.library_paths
|
||||||
|
linker_system_dirs = OS::Linux::Ld.system_dirs
|
||||||
|
|
||||||
|
# If DF_1_NODEFLIB is set, exclude any library paths that are subdirectories
|
||||||
|
# of the system dirs
|
||||||
|
if nodeflib_flag
|
||||||
|
linker_library_paths = linker_library_paths.reject do |lib_path|
|
||||||
|
linker_system_dirs.any? { |system_dir| Utils::Path.child_of? system_dir, lib_path }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If not found, search recursively in the paths listed in ld.so.conf (skipping
|
||||||
|
# paths that are subdirectories of the system dirs if DF_1_NODEFLIB is set)
|
||||||
|
linker_library_paths.each do |linker_library_path|
|
||||||
|
candidate = Pathname(linker_library_path)/basename
|
||||||
|
return candidate if candidate.exist? && candidate.elf?
|
||||||
|
end
|
||||||
|
|
||||||
|
# If not found, search in the system dirs, unless DF_1_NODEFLIB is set
|
||||||
|
unless nodeflib_flag
|
||||||
|
linker_system_dirs.each do |linker_system_dir|
|
||||||
|
candidate = Pathname(linker_system_dir)/basename
|
||||||
|
return candidate if candidate.exist? && candidate.elf?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
basename
|
||||||
|
end
|
||||||
end
|
end
|
||||||
private_constant :Metadata
|
private_constant :Metadata
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user