module RunLoop # @!visibility private # # This is experimental. # # Injects dylibs into running executables using lldb. class DylibInjector # @!attribute [r] process_name # The name of the process to inject the dylib into. This should be obtained # by inspecting the Info.plist in the app bundle. # @return [String] The process_name attr_reader :process_name # @!attribute [r] dylib_path # The path to the dylib that is to be injected. # @return [String] The dylib_path attr_reader :dylib_path # Create a new dylib injector. # @param [String] process_name The name of the process to inject the dylib # into. This should be obtained by inspecting the Info.plist in the app # bundle. # @param [String] dylib_path The path the dylib to inject. def initialize(process_name, dylib_path) @process_name = process_name @dylib_path = dylib_path end # Injects a dylib into a a currently running process. def inject_dylib debug_logging = RunLoop::Environment.debug? puts "Starting lldb." if debug_logging stderr_output = nil lldb_status = nil lldb_start_time = Time.now Open3.popen3('sh') do |stdin, stdout, stderr, process_status| stdin.puts 'xcrun lldb --no-lldbinit< merged_options[:retries], # Retriable 2.0 :interval => merged_options[:interval], :base_interval => merged_options[:interval], :on_retry => on_retry}) do #unless inject_dylib_with_timeout merged_options[:timeout] unless inject_dylib_with_timeout merged_options[:timeout] raise RuntimeError, "Could not inject dylib" end end true end private RETRIABLE_OPTIONS = { :retries => 3, :timeout => 10, # Retriable 2.0 replaces :interval with :base_interval :interval => 2, :base_interval => 2 } end end