rallhook 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +3 -0
- data/CHANGELOG +82 -0
- data/README +207 -0
- data/Rakefile +49 -0
- data/TODO +8 -0
- data/examples/hook/example1.rb +19 -0
- data/examples/hook/example2.rb +30 -0
- data/examples/hook/example3.rb +24 -0
- data/examples/hook/example4.rb +18 -0
- data/examples/hook/intercept.rb +41 -0
- data/examples/hook/intercept2.rb +49 -0
- data/examples/hook/redirect.rb +55 -0
- data/examples/hook/redirect_inherited.rb +28 -0
- data/examples/hook/shadow.rb +44 -0
- data/examples/instrospection/main.rb +13 -0
- data/examples/instrospection/source1.rb +4 -0
- data/examples/instrospection/source2.rb +4 -0
- data/ext/rallhook_base/distorm.h +401 -0
- data/ext/rallhook_base/extconf.rb +21 -0
- data/ext/rallhook_base/hook.c +165 -0
- data/ext/rallhook_base/hook.h +30 -0
- data/ext/rallhook_base/hook_rb_call.c +88 -0
- data/ext/rallhook_base/hook_rb_call.h +33 -0
- data/ext/rallhook_base/method_node.c +212 -0
- data/ext/rallhook_base/method_node.h +27 -0
- data/ext/rallhook_base/node_defs.h +294 -0
- data/ext/rallhook_base/rallhook.c +396 -0
- data/ext/rallhook_base/rb_call_fake.c +398 -0
- data/ext/rallhook_base/rb_call_fake.h +138 -0
- data/ext/rallhook_base/restrict_def.c +176 -0
- data/ext/rallhook_base/restrict_def.h +37 -0
- data/ext/rallhook_base/ruby_redirect.c +122 -0
- data/ext/rallhook_base/ruby_redirect.h +33 -0
- data/ext/rallhook_base/ruby_symbols.c +43 -0
- data/ext/rallhook_base/ruby_symbols.h +28 -0
- data/ext/rallhook_base/ruby_version.h +21 -0
- data/lib/rallhook/thread_hook.rb +37 -0
- data/lib/rallhook.rb +384 -0
- data/test/basic_proc.rb +45 -0
- data/test/integrity/test_array.rb +42 -0
- data/test/integrity/test_binding.rb +26 -0
- data/test/integrity/test_block.rb +37 -0
- data/test/integrity/test_call.rb +1 -0
- data/test/integrity/test_class_methods.rb +1 -0
- data/test/integrity/test_exception.rb +1 -0
- data/test/integrity/test_super.rb +34 -0
- data/test/introspection/test_call.rb +29 -0
- data/test/introspection/test_class_method.rb +41 -0
- data/test/introspection/test_file.rb +15 -0
- metadata +113 -0
data/AUTHORS
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
0.7.0 Concurrency support, any thread can hook without affect the hook state of the other threads
|
2
|
+
|
3
|
+
Restrictions about overwrite instance methods disabled
|
4
|
+
|
5
|
+
Added class shadows to confine the behaviour added throught methods to hook state
|
6
|
+
|
7
|
+
Implemented UboundMethod#unchecked_bind to bind methods of different classes
|
8
|
+
|
9
|
+
0.6.1 Fixed bug on binding of class methods in Object#specific_method
|
10
|
+
|
11
|
+
0.6.0 Implemented method UboundMethod#body
|
12
|
+
|
13
|
+
Improved compatibility of test cases with ruby1.9 and ruby1.8 behaviour
|
14
|
+
|
15
|
+
Implemented Object#specific_method to lookup methods by klass and method_id
|
16
|
+
|
17
|
+
Delete overload of Object#method
|
18
|
+
|
19
|
+
0.5.0 Security Improved: Restricted define of singleton methods over classes when hook is enabled
|
20
|
+
|
21
|
+
Added special check for Object#binding to avoid change the binding behaviour with method redirection
|
22
|
+
|
23
|
+
Security improved: Added hook of rb_add_method to avoid the overwriting of any method
|
24
|
+
|
25
|
+
Security improved: Fixed leaks of hooking methods by making all methods called over Hook illegal if hook state is enabled
|
26
|
+
|
27
|
+
More helpers to make easier to use. (see MethodHandler class)
|
28
|
+
|
29
|
+
Documented methods and classes to generate useful RDoc
|
30
|
+
|
31
|
+
Internal refactoring to split the logic of rallhook, hooking, method_handle invoke, etc... and the modification of the ruby interpreter with hook calls, etc...
|
32
|
+
|
33
|
+
0.4.1 Fixed bug in the hook module
|
34
|
+
|
35
|
+
0.4.0 Fixed bug in the version numbering
|
36
|
+
|
37
|
+
0.3.1 Added new method of intercept calls
|
38
|
+
|
39
|
+
Changed interface of handlling of methods (see README and examples) to avoid errors in the handling of yield functions in ruby1.8
|
40
|
+
|
41
|
+
New internal method of hook fixe many many bugs
|
42
|
+
|
43
|
+
Fixed fastcall convention calls in i386, hooks and detection of calling convention
|
44
|
+
|
45
|
+
Fixed compatibility issues with ruby1.8 and ruby1.9 in i386
|
46
|
+
|
47
|
+
Rakefile configured to build extensions automatically at gem install
|
48
|
+
|
49
|
+
0.3.0: Compatibility with ruby1.8 on i386 (tested with ruby 1.8.6 patchlevel 111 in ubuntu 8.04)
|
50
|
+
|
51
|
+
Compatibility with ruby1.9 on i386 (tested with ruby 1.9.0 in ubuntu 8.04)
|
52
|
+
|
53
|
+
Compatiblity with ruby1.8 on x86_64 (tested with ruby 1.8.7 patchlevel 72 in ubuntu 9.04)
|
54
|
+
|
55
|
+
Compatibility with ruby1.9 on x86_64 (tested with ruby 1.9.0 r17482 in ubuntu 9.04)
|
56
|
+
|
57
|
+
New method introspection features (see README for examples)
|
58
|
+
|
59
|
+
|
60
|
+
0.2.1: Fixed issue #3: corrupted block arguments in hooking ( http://github.com/tario/rallhook/issues/issue/3 )
|
61
|
+
|
62
|
+
Added testcase to test the issue #3
|
63
|
+
|
64
|
+
Added some automatic tests of integrity of the modified interpreter
|
65
|
+
|
66
|
+
0.2.0: Fixed RAII issues in RallHook::hook method
|
67
|
+
|
68
|
+
Changed version of package to 0.2.0 to avoid "malformed" version number
|
69
|
+
|
70
|
+
0.2.0-rc1: Added "TagContainer trick" to fix the issue #2: undesirable nest at super call with block ( http://github.com/tario/rallhook/issues/issue/2 )
|
71
|
+
|
72
|
+
Added klass parameter to hooked_send, fixing the issue #1: undesirable nest at super call ( http://github.com/tario/rallhook/issues/issue/1 )
|
73
|
+
|
74
|
+
Added classes and methods to read method body info as the file and line where that method was defined
|
75
|
+
obj.method(:foo).body.file
|
76
|
+
obj.method(:foo).body.line
|
77
|
+
|
78
|
+
|
79
|
+
0.1.1: Changed hooking and unhooking mechanism in the call of the handler of hooks
|
80
|
+
to make it internal at rallhooking (calling of hook and unhook from the call method are unnecesary now)
|
81
|
+
|
82
|
+
0.1.0: implemented basic hooking as PoC of rallhook, basic example works fine
|
data/README
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
= rallhook - An ruby absolute method hooker
|
2
|
+
|
3
|
+
This package contains rallhook, a ruby C extension to intercept ruby methods calls at interpreter level in a transparent way from ruby itself.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
=== Prerequisites
|
8
|
+
|
9
|
+
* ruby-cymbol >= 0.1.0 (found at http://github.com/tario/ruby-cymbol)
|
10
|
+
* ruby debug info ( apt-get install libruby1.8-dbg or libruby1.9-dbg on debian based systems)
|
11
|
+
* ruby development package ( apt-get install ruby1.8-dev or ruby1.9-dev on debian based systems)
|
12
|
+
* objdump
|
13
|
+
* distorm ( found at https://code.google.com/p/distorm/ )
|
14
|
+
|
15
|
+
|
16
|
+
=== Gem installation
|
17
|
+
|
18
|
+
* Download the last version of the gem from http://github.com/tario/ruby-cpp/downloads
|
19
|
+
* Install the gem with the following;
|
20
|
+
|
21
|
+
gem install rallhook-X.X.X.gem
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
=== Basic Example
|
26
|
+
|
27
|
+
test.rb:
|
28
|
+
|
29
|
+
require "rubygems"
|
30
|
+
require "rallhook"
|
31
|
+
|
32
|
+
include RallHook
|
33
|
+
|
34
|
+
class MethodHandler < HookHandler
|
35
|
+
|
36
|
+
def handle_method (klass,self_,m, method_id)
|
37
|
+
|
38
|
+
# print to the standar output details about the method called
|
39
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class} \n"
|
40
|
+
nil # do nothing
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
MethodHandler.hook do
|
45
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
46
|
+
|
47
|
+
[1,2,3].each do |x|
|
48
|
+
print x,"\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
standard output:
|
54
|
+
|
55
|
+
method call each:4001 over 123:Array
|
56
|
+
method call print:7697 over main:Object
|
57
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
58
|
+
method call to_s:3137 over 1:Fixnum
|
59
|
+
1method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
60
|
+
|
61
|
+
method call print:7697 over main:Object
|
62
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
63
|
+
method call to_s:3137 over 2:Fixnum
|
64
|
+
2method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
65
|
+
|
66
|
+
method call print:7697 over main:Object
|
67
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
68
|
+
method call to_s:3137 over 3:Fixnum
|
69
|
+
3method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
70
|
+
|
71
|
+
=== Redirecting calls
|
72
|
+
|
73
|
+
require "rubygems"
|
74
|
+
require "rallhook"
|
75
|
+
|
76
|
+
include RallHook
|
77
|
+
|
78
|
+
class MethodHandler < HookHandler
|
79
|
+
include RallHook::Helper
|
80
|
+
|
81
|
+
def handle_method (klass,recv,m,method_id)
|
82
|
+
|
83
|
+
if m == :foo
|
84
|
+
# redirects the calls of method foo to method bar on the same object
|
85
|
+
return redirect_call(klass,recv, :bar)
|
86
|
+
end
|
87
|
+
|
88
|
+
if m == :bar
|
89
|
+
# redirects the calls of method bar to method bar on the method_handler
|
90
|
+
return redirect_call(self.class,self, :bar)
|
91
|
+
end
|
92
|
+
|
93
|
+
nil # do nothing
|
94
|
+
end
|
95
|
+
|
96
|
+
def bar
|
97
|
+
print "bar in MethodHandler\n"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class X
|
102
|
+
def foo
|
103
|
+
print "foo in X\n"
|
104
|
+
end
|
105
|
+
def bar
|
106
|
+
print "bar in X\n"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
print "WITHOUT HOOK:\n"
|
111
|
+
|
112
|
+
x = X.new
|
113
|
+
x.foo
|
114
|
+
x.bar
|
115
|
+
|
116
|
+
print "WITH HOOK:\n"
|
117
|
+
|
118
|
+
MethodHandler.hook do
|
119
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
120
|
+
x = X.new
|
121
|
+
x.foo # redirected to X#bar
|
122
|
+
x.bar # redirected to MethodHandler#bar
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
=== Wrap Calls
|
127
|
+
require "rubygems"
|
128
|
+
require "rallhook"
|
129
|
+
|
130
|
+
include RallHook
|
131
|
+
|
132
|
+
class MethodHandler < HookHandler
|
133
|
+
include RallHook::Helper
|
134
|
+
|
135
|
+
class FooMethodWrapper < MethodWrapper
|
136
|
+
def call(*x)
|
137
|
+
# call with reyield if block_given
|
138
|
+
if block_given?
|
139
|
+
original_call(*x) do |*a|
|
140
|
+
yield(*a)
|
141
|
+
end
|
142
|
+
# add "�bar?"
|
143
|
+
yield("bar?")
|
144
|
+
else
|
145
|
+
original_call(*x)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def handle_method (klass,recv,m,method_id)
|
151
|
+
if m == :each
|
152
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
153
|
+
end
|
154
|
+
nil # do nothing
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
print "calling Array#each without hook\n"
|
159
|
+
[1,2,3,4].each do |x|
|
160
|
+
print x.inspect, " "
|
161
|
+
end
|
162
|
+
print "\n"
|
163
|
+
|
164
|
+
print "calling Array#each WITH hook\n"
|
165
|
+
MethodHandler.hook do
|
166
|
+
|
167
|
+
# 1 2 3 4 "bar?"
|
168
|
+
[1,2,3,4].each do |x|
|
169
|
+
print x.inspect," "
|
170
|
+
end
|
171
|
+
print "\n"
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
=== Method Instrospection new features example
|
177
|
+
|
178
|
+
source1.rb
|
179
|
+
|
180
|
+
class X
|
181
|
+
def foo
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
source2.rb
|
186
|
+
|
187
|
+
class Y < X
|
188
|
+
def foo
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
main.rb
|
193
|
+
|
194
|
+
require "rallhook"
|
195
|
+
require "source1.rb"
|
196
|
+
require "source2.rb"
|
197
|
+
|
198
|
+
x = X.new
|
199
|
+
y = Y.new
|
200
|
+
|
201
|
+
print x.method(:foo).body.file,"\n" # source1.rb
|
202
|
+
print y.method(:foo).body.file,"\n" # source2.rb
|
203
|
+
|
204
|
+
print y.method(X,:foo).body.file,"\n" # source1.rb
|
205
|
+
print y.method(Y,:foo).body.file,"\n" # source2.rb
|
206
|
+
|
207
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'rallhook'
|
9
|
+
s.version = '0.7.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'Allow hooking of all method invocations transparently to control and / or monitor the behavior of a ruby program'
|
14
|
+
s.homepage = "http://github.com/tario/rallhook"
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.add_dependency "ruby-cymbol", ">= 0.1.0"
|
17
|
+
s.extra_rdoc_files = [ 'README' ]
|
18
|
+
s.rdoc_options << '--main' << 'README'
|
19
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
20
|
+
s.files = Dir.glob("{examples,lib,test}/**/*.rb") + Dir.glob("ext/**/*.c") + Dir.glob("ext/**/*.h") + Dir.glob("ext/**/extconf.rb") +
|
21
|
+
[ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Run tests'
|
25
|
+
task :default => [ :test ]
|
26
|
+
|
27
|
+
Rake::TestTask.new('test') do |t|
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = '{test}/**/test_*.rb'
|
30
|
+
t.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Generate RDoc'
|
34
|
+
Rake::RDocTask.new :rdoc do |rd|
|
35
|
+
rd.rdoc_dir = 'doc'
|
36
|
+
rd.rdoc_files.add 'lib', 'ext', 'README'
|
37
|
+
rd.main = 'README'
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Build Gem'
|
41
|
+
Rake::GemPackageTask.new spec do |pkg|
|
42
|
+
pkg.need_tar = true
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Clean up'
|
46
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
47
|
+
|
48
|
+
desc 'Clean up'
|
49
|
+
task :clobber => [ :clean ]
|
data/TODO
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
* Threading support
|
2
|
+
* Tests cases for 1.0.0 interface
|
3
|
+
* More integrity testcases (with use of ruby core methods)
|
4
|
+
* Security testcases (hook bypass checks, security tests)
|
5
|
+
* Win32 compatibility
|
6
|
+
* Delete distorm dependency
|
7
|
+
* Delete libruby debuginfo dependency
|
8
|
+
* Make rallhook functionality transparent (backtraces, exceptions, etc ...)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class HookProc
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
hook_proc = HookProc.new
|
16
|
+
Hook.hook hook_proc do
|
17
|
+
print 2+2,"\n"
|
18
|
+
print [1,2,3].inject{|x,y| x+y},"\n"
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class HookProc
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class X
|
16
|
+
def foo
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Y <X
|
21
|
+
def foo
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
hook_proc = HookProc.new
|
27
|
+
Hook.hook hook_proc do
|
28
|
+
y = Y.new
|
29
|
+
y.foo
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
mhandler = MethodHandler.new
|
16
|
+
|
17
|
+
Hook.hook mhandler do
|
18
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
19
|
+
|
20
|
+
[1,2,3].each do |x|
|
21
|
+
print x,"\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler < RallHook::HookHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
MethodHandler.hook do
|
16
|
+
print 2+2,"\n"
|
17
|
+
print [1,2,3].inject{|x,y| x+y},"\n"
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
class FooMethodWrapper < MethodWrapper
|
10
|
+
def call(a)
|
11
|
+
# replace the a parameter with a+5
|
12
|
+
original_call(a+5)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle_method (klass,recv,m, method_id)
|
17
|
+
|
18
|
+
if m == :foo
|
19
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
nil # do nothing
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class X
|
28
|
+
def foo(a)
|
29
|
+
print "foo in X with a = #{a}\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
x = X.new
|
33
|
+
print "calling X#foo without hook\n"
|
34
|
+
x.foo 4 # "foo in X with a = 4"
|
35
|
+
|
36
|
+
print "calling X#foo WITH hook\n"
|
37
|
+
mhandler = MethodHandler.new
|
38
|
+
Hook.hook mhandler do
|
39
|
+
x.foo 4 # "foo in X with a = 9" :)
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
class FooMethodWrapper < MethodWrapper
|
10
|
+
def call(*x)
|
11
|
+
# call with reyield if block_given
|
12
|
+
if block_given?
|
13
|
+
original_call(*x) do |*a|
|
14
|
+
yield(*a)
|
15
|
+
end
|
16
|
+
# add "�bar?"
|
17
|
+
yield("bar?")
|
18
|
+
else
|
19
|
+
original_call(*x)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_method (klass,recv,m,method_id)
|
25
|
+
if m == :each
|
26
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
27
|
+
end
|
28
|
+
nil # do nothing
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
print "calling Array#each without hook\n"
|
33
|
+
[1,2,3,4].each do |x|
|
34
|
+
print x.inspect, " "
|
35
|
+
end
|
36
|
+
print "\n"
|
37
|
+
|
38
|
+
print "calling Array#each WITH hook\n"
|
39
|
+
mhandler = MethodHandler.new
|
40
|
+
Hook.hook mhandler do
|
41
|
+
|
42
|
+
# 1 2 3 4 "bar?"
|
43
|
+
[1,2,3,4].each do |x|
|
44
|
+
print x.inspect," "
|
45
|
+
end
|
46
|
+
print "\n"
|
47
|
+
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
def handle_method (klass,recv,m,method_id)
|
10
|
+
|
11
|
+
if m == :foo
|
12
|
+
# redirects the calls of method foo to method bar on the same object
|
13
|
+
return redirect_call(klass,recv, :bar)
|
14
|
+
end
|
15
|
+
|
16
|
+
if m == :bar
|
17
|
+
# redirects the calls of method bar to method bar on the method_handler
|
18
|
+
return redirect_call(self.class,self, :bar)
|
19
|
+
end
|
20
|
+
|
21
|
+
nil # do nothing
|
22
|
+
end
|
23
|
+
|
24
|
+
def bar
|
25
|
+
print "bar in MethodHandler\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class X
|
30
|
+
def foo
|
31
|
+
print "foo in X\n"
|
32
|
+
end
|
33
|
+
def bar
|
34
|
+
print "bar in X\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
mhandler = MethodHandler.new
|
39
|
+
|
40
|
+
print "WITHOUT HOOK:\n"
|
41
|
+
|
42
|
+
x = X.new
|
43
|
+
x.foo
|
44
|
+
x.bar
|
45
|
+
|
46
|
+
print "WITH HOOK:\n"
|
47
|
+
|
48
|
+
Hook.hook mhandler do
|
49
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
50
|
+
x = X.new
|
51
|
+
x.foo # redirected to X#bar
|
52
|
+
x.bar # redirected to MethodHandler#bar
|
53
|
+
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
def handle_method (klass,recv,m,method_id)
|
10
|
+
|
11
|
+
print "called method #{m} over #{recv}\n"
|
12
|
+
|
13
|
+
if m == :inherited
|
14
|
+
return redirect_call(klass,recv,:ssss)
|
15
|
+
end
|
16
|
+
|
17
|
+
nil # do nothing
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
mhandler = MethodHandler.new
|
22
|
+
Hook.hook mhandler do
|
23
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
24
|
+
class N
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler < RallHook::HookHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
# print to the standard output details about the method called
|
9
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
10
|
+
nil # do nothing
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class X
|
15
|
+
def foo
|
16
|
+
print "outside of hook foo\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
x = X.new
|
21
|
+
|
22
|
+
x.foo
|
23
|
+
|
24
|
+
MethodHandler.hook do
|
25
|
+
class X
|
26
|
+
def foo
|
27
|
+
print "inside of hook foo\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
def bar
|
31
|
+
print "inside of hook bar\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
x.foo
|
36
|
+
x.bar
|
37
|
+
end
|
38
|
+
|
39
|
+
x.foo
|
40
|
+
begin
|
41
|
+
x.bar # NoMethodError
|
42
|
+
rescue NoMethodError
|
43
|
+
print "there is no method bar in X outside the hook\n"
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
require "source1.rb"
|
4
|
+
require "source2.rb"
|
5
|
+
|
6
|
+
x = X.new
|
7
|
+
y = Y.new
|
8
|
+
|
9
|
+
print "definition of method :foo in #{x}: ", x.method(:foo).body.file,"\n" # source1.rb
|
10
|
+
print "definition of method :foo in #{y}: ", y.method(:foo).body.file,"\n" # source2.rb
|
11
|
+
|
12
|
+
print "definition of method :foo of class X in object #{y}: ", y.method(X,:foo).body.file,"\n" # source1.rb
|
13
|
+
print "definition of method :foo of class Y in object #{y}: ", y.method(Y,:foo).body.file,"\n" # source1.rb
|