Class: NativeDebugger

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-debug-ide/attach/native_debugger.rb

Direct Known Subclasses

GDB, LLDB

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(executable, pid, flags, gems_to_include, debugger_loader_path, argv) ⇒ NativeDebugger

Returns a new instance of NativeDebugger.

Parameters:

  • executable

    – path to ruby interpreter

  • pid

    – pid of process you want to debug

  • flags

    – flags you want to specify to your debugger as a string (e.g. “-nx -nh” for gdb to disable .gdbinit)



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 8

def initialize(executable, pid, flags, gems_to_include, debugger_loader_path, argv)
  @pid = pid
  @delimiter = '__OUTPUT_FINISHED__' # for getting response
  @tbreak = '__func_to_set_breakpoint_at'
  @main_thread = nil
  @process_threads = nil
  debase_path = gems_to_include.select {|gem_path| gem_path =~ /debase/}
  if debase_path.size == 0
    raise 'No debase gem found.'
  end
  @path_to_attach = find_attach_lib(debase_path[0])

  @gems_to_include = '["' + gems_to_include * '", "' + '"]'
  @debugger_loader_path = debugger_loader_path
  @argv = argv

  @eval_string = "debase_rb_eval(\"require '#{@debugger_loader_path}'; load_debugger(#{@gems_to_include.gsub("\"", "'")}, #{@argv.gsub("\"", "'")})\")"

  launch_string = "#{self} #{executable} #{flags}"
  @pipe = IO.popen(launch_string, 'r+')
  $stdout.puts "executed '#{launch_string}'"
end

Instance Attribute Details

#main_threadObject (readonly)

Returns the value of attribute main_thread.



3
4
5
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 3

def main_thread
  @main_thread
end

#pidObject (readonly)

Returns the value of attribute pid.



3
4
5
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 3

def pid
  @pid
end

#pipeObject (readonly)

Returns the value of attribute pipe.



3
4
5
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 3

def pipe
  @pipe
end

#process_threadsObject (readonly)

Returns the value of attribute process_threads.



3
4
5
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 3

def process_threads
  @process_threads
end

Instance Method Details

#attach_to_processObject



43
44
45
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 43

def attach_to_process
  execute "attach #{@pid}"
end

#call_start_attachObject



107
108
109
110
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 107

def call_start_attach
  raise 'No main thread found. Did you forget to call `update_threads`?' if @main_thread == nil
  @main_thread.switch
end

#check_already_under_debugObject



76
77
78
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 76

def check_already_under_debug

end

#check_delimiter(line) ⇒ Object



84
85
86
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 84

def check_delimiter(line)

end

#continueObject



96
97
98
99
100
101
102
103
104
105
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 96

def continue
  $stdout.puts 'continuing'
  @pipe.puts 'c'
  loop do
    line = @pipe.readline
    DebugPrinter.print_debug('respond line: ' + line)
    break if line =~ /#{Regexp.escape(@tbreak)}/
  end
  get_response
end

#execute(command) ⇒ Object



47
48
49
50
51
52
53
54
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 47

def execute(command)
  @pipe.puts command
  $stdout.puts "executed `#{command}` command inside #{self}."
  if command == 'q'
    return ''
  end
  get_response
end

#exitObject



125
126
127
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 125

def exit
  @pipe.close
end

#exited?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 121

def exited?
  @pipe.closed?
end

#find_attach_lib(debase_path) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 31

def find_attach_lib(debase_path)
  attach_lib = debase_path + '/attach'
  known_extensions = %w(.so .bundle .dll .dylib)
  known_extensions.each do |ext|
    if File.file?(attach_lib + ext)
      return attach_lib + ext
    end
  end

  raise 'Could not find attach library'
end

#get_responseObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 56

def get_response
  # we need this hack to understand that debugger gave us all output from last executed command
  print_delimiter

  content = ''
  loop do
    line = @pipe.readline
    DebugPrinter.print_debug('respond line: ' + line)
    break if check_delimiter(line)
    next if line =~ /\(lldb\)/ # lldb repeats your input to its output
    content += line
  end

  content
end

#load_debuggerObject



117
118
119
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 117

def load_debugger

end


80
81
82
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 80

def print_delimiter

end

#set_break(str) ⇒ Object



92
93
94
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 92

def set_break(str)

end

#switch_to_threadObject



88
89
90
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 88

def switch_to_thread

end

#to_sObject



129
130
131
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 129

def to_s
  'native_debugger'
end

#update_threadsObject



72
73
74
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 72

def update_threads

end

#wait_line_eventObject



112
113
114
115
# File 'lib/ruby-debug-ide/attach/native_debugger.rb', line 112

def wait_line_event
  call_start_attach
  continue
end