@@ -13,6 +13,22 @@ options = OpenStruct.new(
1313 'gems_to_include' => [ ]
1414)
1515
16+ module DebugPrinter
17+
18+ class << self
19+ attr_accessor :cli_debug
20+
21+ def print_debug ( msg )
22+ if DebugPrinter . cli_debug
23+ $stderr. puts msg
24+ end
25+ end
26+ end
27+
28+ end
29+
30+ DebugPrinter . cli_debug = ARGV . include? '--debug'
31+
1632opts = OptionParser . new do |opts |
1733 # TODO need some banner
1834 opts . banner = <<EOB
@@ -75,17 +91,31 @@ class NativeDebugger
7591 if debase_path . size == 0
7692 raise 'No debase gem found.'
7793 end
78- @path_to_attach = debase_path [ 0 ] + '/attach.so'
94+ @path_to_attach = find_attach_lib ( debase_path [ 0 ] )
7995
8096 @gems_to_include = '["' + gems_to_include * '", "' + '"]'
8197 @debugger_loader_path = debugger_loader_path
8298 @argv = argv
8399
100+ @eval_string = "rb_eval_string_protect(\" require '#{ @debugger_loader_path } '; load_debugger(#{ @gems_to_include . gsub ( "\" " , "'" ) } , #{ @argv . gsub ( "\" " , "'" ) } )\" , (int *)0)"
101+
84102 launch_string = "#{ self } #{ executable } #{ flags } "
85103 @pipe = IO . popen ( launch_string , 'r+' )
86104 $stdout. puts "executed '#{ launch_string } '"
87105 end
88106
107+ def find_attach_lib ( debase_path )
108+ attach_lib = debase_path + '/attach'
109+ known_extensions = %w( .so .bundle .dll )
110+ known_extensions . each do |ext |
111+ if File . file? ( attach_lib + ext )
112+ return attach_lib + ext
113+ end
114+ end
115+
116+ raise 'Could not find attach library'
117+ end
118+
89119 def attach_to_process
90120 execute "attach #{ @pid } "
91121 end
@@ -101,15 +131,17 @@ class NativeDebugger
101131
102132 def get_response
103133 # we need this hack to understand that debugger gave us all output from last executed command
104- @pipe . puts "print \" #{ @delimiter } \" "
134+ print_delimiter
105135
106136 content = ''
107137 loop do
108138 line = @pipe . readline
139+ break if check_delimiter ( line )
140+ DebugPrinter . print_debug ( 'respond line: ' + line )
109141 next if line =~ /\( lldb\) / # lldb repeats your input to its output
110- break if line =~ /\$ \d +\s =\s "#{ @delimiter } "/
111142 content += line
112143 end
144+
113145 content
114146 end
115147
@@ -121,6 +153,14 @@ class NativeDebugger
121153
122154 end
123155
156+ def print_delimiter
157+
158+ end
159+
160+ def check_delimiter ( line )
161+
162+ end
163+
124164 def switch_to_thread
125165
126166 end
@@ -150,7 +190,7 @@ class NativeDebugger
150190 end
151191
152192 def load_debugger
153- execute "call rb_eval_string_protect( \" require ' #{ @debugger_loader_path } '; load_debugger( #{ @gems_to_include . gsub ( " \" " , "'" ) } , #{ @argv . gsub ( " \" " , "'" ) } ) \" , (int *)0)"
193+
154194 end
155195
156196 def exit
@@ -179,7 +219,6 @@ class LLDB < NativeDebugger
179219 info_threads = ( execute 'thread list' ) . split ( "\n " )
180220 info_threads . each do |thread_info |
181221 next unless thread_info =~ /[\s *]*thread\s #\d +.*/
182- $stdout. puts "thread_info: #{ thread_info } "
183222 is_main = thread_info [ 0 ] == '*'
184223 thread_num = thread_info . sub ( /[\s *]*thread\s #/ , '' ) . sub ( /:\s .*$/ , '' ) . to_i
185224 thread = ProcessThread . new ( thread_num , is_main , thread_info , self )
@@ -203,10 +242,22 @@ class LLDB < NativeDebugger
203242 def call_start_attach
204243 super ( )
205244 execute "expr (void *) dlopen(\" #{ @path_to_attach } \" , 2)"
206- execute 'call start_attach()'
245+ execute 'expr (int) start_attach()'
207246 set_tbreak ( @tbreak )
208247 end
209248
249+ def print_delimiter
250+ @pipe . puts "script print \" #{ @delimiter } \" "
251+ end
252+
253+ def check_delimiter ( line )
254+ line =~ /#{ @delimiter } $/
255+ end
256+
257+ def load_debugger
258+ execute "expr (VALUE) #{ @eval_string } "
259+ end
260+
210261 def to_s
211262 'lldb'
212263 end
@@ -257,6 +308,18 @@ class GDB < NativeDebugger
257308 set_tbreak ( @tbreak )
258309 end
259310
311+ def print_delimiter
312+ @pipe . puts "print \" #{ @delimiter } \" "
313+ end
314+
315+ def check_delimiter ( line )
316+ line =~ /\$ \d +\s =\s "#{ @delimiter } "/
317+ end
318+
319+ def load_debugger
320+ execute "call #{ @eval_string } "
321+ end
322+
260323 def to_s
261324 'gdb'
262325 end
@@ -317,15 +380,21 @@ class ProcessThread
317380end
318381
319382def command_exists ( command )
383+ checking_command = "checking command #{ command } for existence\n "
320384 `command -v #{ command } >/dev/null 2>&1 || { exit 1; }`
385+ if $?. exitstatus != 0
386+ DebugPrinter . print_debug ( "#{ checking_command } command does not exist." )
387+ else
388+ DebugPrinter . print_debug ( "#{ checking_command } command does exist." )
389+ end
321390 $?. exitstatus == 0
322391end
323392
324393def choose_debugger ( ruby_path , pid , gems_to_include , debugger_loader_path , argv )
325- if command_exists ( 'gdb' )
326- debugger = GDB . new ( ruby_path , pid , '-nh -nx' , gems_to_include , debugger_loader_path , argv )
327- elsif command_exists ( 'lldb' )
394+ if command_exists ( 'lldb' )
328395 debugger = LLDB . new ( ruby_path , pid , '--no-lldbinit' , gems_to_include , debugger_loader_path , argv )
396+ elsif command_exists ( 'gdb' )
397+ debugger = GDB . new ( ruby_path , pid , '-nh -nx' , gems_to_include , debugger_loader_path , argv )
329398 else
330399 raise 'Neither gdb nor lldb was found. Aborting.'
331400 end
@@ -348,6 +417,7 @@ debugger.attach_to_process
348417debugger . set_flags
349418
350419if options . uid
420+ DebugPrinter . print_debug ( "changing current uid from #{ Process . uid } to #{ options . uid } " )
351421 Process ::Sys . setuid ( options . uid . to_i )
352422end
353423
0 commit comments