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