ileitch-hijack 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,7 +14,7 @@ Hijack uses DRb over a unix socket file, so you need to be on the same machine a
14
14
 
15
15
  == Using ruby-debug
16
16
 
17
- Hijack can be used a means to start ruby-debug in your target process, for example:
17
+ Hijack can be used to start ruby-debug in your target process, for example:
18
18
 
19
19
  $ hijack 61378
20
20
  => Hijacked 61378 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
data/TODO CHANGED
@@ -1,5 +1,2 @@
1
- * Use thread local stdout & stderr capture.
2
- * assigning a variable doesn't work
3
1
  * Improve startup experience
4
- * Require actual remote script if possible so that if it defines any classes we can dump those too.
5
2
  * Add a hijack_exec helper to execute a local .rb on the target
@@ -8,7 +8,6 @@ module Hijack
8
8
  $stdout.write(str)
9
9
  $stdout.flush
10
10
  Payload.inject(@pid)
11
- signal_drb_start
12
11
  connect
13
12
  $stdout.write("\b" * str.size)
14
13
  $stdout.flush
@@ -32,15 +31,11 @@ module Hijack
32
31
  end
33
32
  end
34
33
 
35
- def signal_drb_start
36
- Process.kill('USR2', @pid.to_i)
34
+ def connect
37
35
  loop do
38
36
  break if File.exists?(Hijack.socket_path_for(@pid))
39
37
  sleep 0.01
40
38
  end
41
- end
42
-
43
- def connect
44
39
  @remote = DRbObject.new(nil, Hijack.socket_for(@pid))
45
40
  end
46
41
 
@@ -3,35 +3,63 @@
3
3
  module Hijack
4
4
  class GDB
5
5
  def initialize(pid)
6
+ @pid = pid
6
7
  @verbose = Hijack.options[:gdb_debug]
7
- exec_path = File.join(Config::CONFIG['bindir'], Config::CONFIG['RUBY_INSTALL_NAME'] + Config::CONFIG['EXEEXT'])
8
- @gdb = IO.popen("gdb -q #{exec_path} #{pid} 2>&1", 'r+')
9
- wait
8
+ @exec_path = File.join(Config::CONFIG['bindir'], Config::CONFIG['RUBY_INSTALL_NAME'] + Config::CONFIG['EXEEXT'])
9
+ attach
10
10
  end
11
11
 
12
- def attached_to_ruby_process?
13
- backtrace.any? {|line| line =~ /ruby_run/}
12
+ def ensure_attached_to_ruby_process
13
+ unless backtrace.any? {|line| line =~ /rb_/}
14
+ puts "\n=> #{@pid} doesn't appear to be a Ruby process!"
15
+ detach
16
+ exit 1
17
+ end
14
18
  end
15
19
 
16
- def main_thread_blocked_by_join?
17
- backtrace.any? {|line| line =~ /rb_thread_join/}
20
+ def ensure_main_thread_not_blocked_by_join
21
+ if backtrace.any? {|line| line =~ /rb_thread_join/}
22
+ puts "\n=> Unable to hijack #{@pid} because the main thread is blocked waiting for another thread to join."
23
+ puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
24
+ detach
25
+ exit 1
26
+ end
18
27
  end
19
28
 
20
29
  def eval(cmd)
21
- set_trap_pending
22
- set_breakpoint
23
- continue
24
- clear_breakpoint
25
30
  call("(void)rb_eval_string(#{cmd.strip.gsub(/"/, '\"').inspect})")
26
31
  end
27
32
 
28
33
  def detach
34
+ return unless @gdb
29
35
  exec('detach')
30
36
  exec('quit')
37
+ @backtrace = nil
31
38
  @gdb.close
39
+ @gdb = nil
32
40
  end
33
41
 
34
42
  protected
43
+ def attach
44
+ loop do
45
+ @gdb = IO.popen("gdb -q #{@exec_path} #{@pid} 2>&1", 'r+')
46
+ wait
47
+ if backtrace.first =~ /Previous frame inner to this frame/
48
+ detach
49
+ sleep 0.1
50
+ else
51
+ break
52
+ end
53
+ end
54
+
55
+ ensure_attached_to_ruby_process
56
+ ensure_main_thread_not_blocked_by_join
57
+ set_trap_pending
58
+ set_breakpoint
59
+ continue
60
+ clear_breakpoint
61
+ end
62
+
35
63
  def backtrace
36
64
  @backtrace ||= exec('bt').reverse
37
65
  end
@@ -1,20 +1,15 @@
1
1
  module Hijack
2
2
  class Payload
3
3
  def self.inject(pid)
4
- gdb = GDB.new(pid)
5
- unless gdb.attached_to_ruby_process?
6
- puts "\n=> #{pid} doesn't appear to be a Ruby process!"
7
- gdb.detach
8
- exit 1
9
- end
10
- if gdb.main_thread_blocked_by_join?
11
- puts "\n=> Unable to hijack #{pid} because the main thread is blocked waiting for another thread to join."
12
- puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
13
- gdb.detach
14
- exit 1
4
+ gdb = nil
5
+ trap('SIGINT') do
6
+ puts
7
+ @received_sigint = true
15
8
  end
9
+ gdb = GDB.new(pid)
16
10
  gdb.eval(payload(pid))
17
11
  gdb.detach
12
+ exit if @received_sigint
18
13
  end
19
14
 
20
15
  def self.payload(pid)
@@ -108,8 +103,7 @@ module Hijack
108
103
  end
109
104
  end
110
105
  end
111
- __hijack_context = self
112
- Signal.trap('USR2') { Hijack.start(__hijack_context) }
106
+ Hijack.start(self)
113
107
  RUBY
114
108
  end
115
109
  end
@@ -1,7 +1,7 @@
1
1
  require 'rake/gempackagetask'
2
2
  require 'yaml'
3
3
 
4
- HIJACK_VERSION = '0.1.8'
4
+ HIJACK_VERSION = '0.1.9'
5
5
 
6
6
  task :clean => :clobber_package
7
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ileitch-hijack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Leitch
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-16 21:00:00 -07:00
12
+ date: 2009-09-19 21:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15