ileitch-hijack 0.1.8 → 0.1.9

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.
@@ -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