Top Level Namespace

Defined Under Namespace

Modules: Debugger, Kernel, Process Classes: GDB, LLDB, NativeDebugger, ProcessThread

Instance Method Summary collapse

Instance Method Details

#attach_and_return_thread(options, pid, debugger_loader_path, argv) ⇒ Object



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
# File 'lib/ruby-debug-ide/attach/util.rb', line 6

def attach_and_return_thread(options, pid, debugger_loader_path, argv)
  Thread.new(argv) do |argv|

    debugger = choose_debugger(options.ruby_path, pid, options.gems_to_include, debugger_loader_path, argv)

    trap('INT') do
      unless debugger.exited?
        $stderr.puts "backtraces for threads:\n\n"
        process_threads = debugger.process_threads
        if process_threads
          process_threads.each do |thread|
            $stderr.puts "#{thread.thread_info}\n#{thread.last_bt}\n\n"
          end
        end
        debugger.exit
      end
      exit!
    end

    debugger.attach_to_process
    debugger.set_flags

    if debugger.check_already_under_debug
      $stderr.puts "Process #{debugger.pid} is already under debug"
      debugger.exit
      exit!
    end

    should_check_threads_state = true

    while should_check_threads_state
      should_check_threads_state = false
      debugger.update_threads.each do |thread|
        thread.switch
        while thread.need_finish_frame
          should_check_threads_state = true
          thread.finish
        end
      end
    end

    debugger.wait_line_event
    debugger.load_debugger
    debugger.exit
  end
end

#choose_debugger(ruby_path, pid, gems_to_include, debugger_loader_path, argv) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ruby-debug-ide/attach/util.rb', line 105

def choose_debugger(ruby_path, pid, gems_to_include, debugger_loader_path, argv)
  if command_exists(LLDB.to_s)
    debugger = LLDB.new(ruby_path, pid, '--no-lldbinit', gems_to_include, debugger_loader_path, argv)
  elsif command_exists(GDB.to_s)
    debugger = GDB.new(ruby_path, pid, '-nh -nx', gems_to_include, debugger_loader_path, argv)
  else
    raise 'Neither gdb nor lldb was found. Aborting.'
  end

  debugger
end

#command_exists(command) ⇒ Object



94
95
96
97
98
99
100
101
102
103
# File 'lib/ruby-debug-ide/attach/util.rb', line 94

def command_exists(command)
  checking_command = "checking command #{command} for existence\n"
  `command -v #{command} >/dev/null 2>&1 || { exit 1; }`
  if $?.exitstatus != 0
    DebugPrinter.print_debug("#{checking_command}command does not exist.")
  else
    DebugPrinter.print_debug("#{checking_command}command does exist.")
  end
  $?.exitstatus == 0
end

#filter_ruby_processes(pids) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/ruby-debug-ide/attach/util.rb', line 76

def filter_ruby_processes(pids)
  pipe = IO.popen(%Q(lsof -c ruby | awk '{print $2 ":" $9}' | grep -E 'bin/ruby([[:digit:]]+\.?)*$'))

  ruby_processes = Set.new

  pipe.readlines.each do |process|
    pid = process.split(/:/).first
    ruby_processes.add(pid.to_i)
  end

  ruby_processes_pids, non_ruby_processes_pids = pids.partition {|pid| ruby_processes.include? pid}

  DebugPrinter.print_debug("The following child processes was added to attach: #{ruby_processes_pids.join(', ')}") unless ruby_processes_pids.empty?
  DebugPrinter.print_debug("The following child are not ruby processes: #{non_ruby_processes_pids.join(', ')}") unless non_ruby_processes_pids.empty?

  ruby_processes_pids
end

#get_child_pids(pid) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ruby-debug-ide/attach/util.rb', line 53

def get_child_pids(pid)
  return [] unless command_exists 'pgrep'

  pids = Array.new

  q = Queue.new
  q.push(pid)

  until q.empty? do
    pid = q.pop

    pipe = IO.popen("pgrep -P #{pid}")

    pipe.readlines.each do |child|
      child_pid = child.strip.to_i
      q.push(child_pid)
      pids << child_pid
    end
  end

  filter_ruby_processes(pids)
end

#load_debugger(gems_to_include, new_argv) ⇒ Object



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/ruby-debug-ide/attach/debugger_loader.rb', line 1

def load_debugger(gems_to_include, new_argv)
  path_to_rdebug = File.expand_path(File.dirname(__FILE__)) + '/../../../bin/rdebug-ide'

  old_argv = ARGV.clone
  ARGV.clear
  new_argv.each do |x|
    ARGV << x
  end

  gems_to_include.each do |gem_path|
    $LOAD_PATH.unshift(gem_path) unless $LOAD_PATH.include?(gem_path)
  end

  load path_to_rdebug
  
  ARGV.clear
  old_argv.each do |x|
    ARGV << x
  end
end