blob: 4723d708b395a55b2956778ccca72a3b79dfa47a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# frozen_string_literal: true
if RUBY_ENGINE == 'ruby'
require 'fiddle.so'
else
require 'fiddle/ffi_backend'
end
require 'fiddle/closure'
require 'fiddle/function'
require 'fiddle/version'
module Fiddle
if WINDOWS
# Returns the last win32 +Error+ of the current executing +Thread+ or nil
# if none
def self.win32_last_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
end
end
# Sets the last win32 +Error+ of the current executing +Thread+ to +error+
def self.win32_last_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
end
end
# Returns the last win32 socket +Error+ of the current executing
# +Thread+ or nil if none
def self.win32_last_socket_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
end
end
# Sets the last win32 socket +Error+ of the current executing
# +Thread+ to +error+
def self.win32_last_socket_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
end
end
end
# Returns the last +Error+ of the current executing +Thread+ or nil if none
def self.last_error
if RUBY_ENGINE == 'jruby'
errno = FFI.errno
errno == 0 ? nil : errno
else
Thread.current[:__FIDDLE_LAST_ERROR__]
end
end
# Sets the last +Error+ of the current executing +Thread+ to +error+
def self.last_error= error
if RUBY_ENGINE == 'jruby'
FFI.errno = error || 0
else
Thread.current[:__DL2_LAST_ERROR__] = error
Thread.current[:__FIDDLE_LAST_ERROR__] = error
end
end
# call-seq: dlopen(library) => Fiddle::Handle
#
# Creates a new handler that opens +library+, and returns an instance of
# Fiddle::Handle.
#
# If +nil+ is given for the +library+, Fiddle::Handle::DEFAULT is used, which
# is the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
#
# lib = Fiddle.dlopen(nil)
#
# The default is dependent on OS, and provide a handle for all libraries
# already loaded. For example, in most cases you can use this to access
# +libc+ functions, or ruby functions like +rb_str_new+.
#
# See Fiddle::Handle.new for more.
def dlopen library
begin
Fiddle::Handle.new(library)
rescue DLError => error
case RUBY_PLATFORM
when /linux/
case error.message
when /\A(\/.+?): (?:invalid ELF header|file too short)/
# This may be a linker script:
# https://sourceware.org/binutils/docs/ld.html#Scripts
path = $1
else
raise
end
else
raise
end
File.open(path) do |input|
input.each_line do |line|
case line
when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
# TODO: Should we support multiple files?
first_input = $1
if first_input.start_with?("-l")
first_input = "lib#{first_input[2..-1]}.so"
end
return dlopen(first_input)
end
end
end
# Not found
raise
end
end
module_function :dlopen
# Add constants for backwards compat
RTLD_GLOBAL = Handle::RTLD_GLOBAL # :nodoc:
RTLD_LAZY = Handle::RTLD_LAZY # :nodoc:
RTLD_NOW = Handle::RTLD_NOW # :nodoc:
Fiddle::Types.constants.each do |type|
const_set "TYPE_#{type}", Fiddle::Types.const_get(type)
end
end
|