From d91c3d1fe742c19ecf53ec3059fb27e616870ca7 Mon Sep 17 00:00:00 2001 From: equivalence1 Date: Thu, 29 Sep 2016 22:30:51 +0300 Subject: [PATCH 1/5] added debug output if `--debug` key specified. --- bin/gdb_wrapper | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/bin/gdb_wrapper b/bin/gdb_wrapper index 08c37d2..510d30f 100755 --- a/bin/gdb_wrapper +++ b/bin/gdb_wrapper @@ -13,6 +13,30 @@ options = OpenStruct.new( 'gems_to_include' => [] ) +module DebugPrinter + + class << self + attr_accessor :cli_debug + + def print_debug(msg) + if DebugPrinter.cli_debug + delimiter = '=' * 10 + upper_border = "\n#{delimiter}\n" + lower_border = "#{delimiter}\n\n" + + if msg.length > 0 and msg[msg.length - 1] != "\n" + lower_border = "\n" + lower_border + end + + $stdout.puts upper_border + msg + lower_border + end + end + end + +end + +DebugPrinter.cli_debug = ARGV.include? '--debug' + opts = OptionParser.new do |opts| # TODO need some banner opts.banner = </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 @@ -348,6 +381,7 @@ debugger.attach_to_process debugger.set_flags if options.uid + DebugPrinter.print_debug("changing current uid from #{Process.uid} to #{options.uid}") Process::Sys.setuid(options.uid.to_i) end From 9026873991e19167cc7aef428b03eb3e97514b91 Mon Sep 17 00:00:00 2001 From: equivalence1 Date: Thu, 29 Sep 2016 22:50:00 +0300 Subject: [PATCH 2/5] It is essential for lldb connecting to OS X's ruby process to specify function type. Under OS X (due to compilation keys, I guess) lldb does not know type of ruby functions so we need to write them explicitly. --- bin/gdb_wrapper | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/gdb_wrapper b/bin/gdb_wrapper index 510d30f..d530811 100755 --- a/bin/gdb_wrapper +++ b/bin/gdb_wrapper @@ -105,6 +105,8 @@ class NativeDebugger @debugger_loader_path = debugger_loader_path @argv = argv + @eval_string = "rb_eval_string_protect(\"require '#{@debugger_loader_path}'; load_debugger(#{@gems_to_include.gsub("\"", "'")}, #{@argv.gsub("\"", "'")})\", (int *)0)" + launch_string = "#{self} #{executable} #{flags}" @pipe = IO.popen(launch_string, 'r+') $stdout.puts "executed '#{launch_string}'" @@ -177,7 +179,7 @@ class NativeDebugger end def load_debugger - execute "call rb_eval_string_protect(\"require '#{@debugger_loader_path}'; load_debugger(#{@gems_to_include.gsub("\"", "'")}, #{@argv.gsub("\"", "'")})\", (int *)0)" + end def exit @@ -230,10 +232,14 @@ class LLDB < NativeDebugger def call_start_attach super() execute "expr (void *) dlopen(\"#{@path_to_attach}\", 2)" - execute 'call start_attach()' + execute 'expr (int) start_attach()' set_tbreak(@tbreak) end + def load_debugger + execute "expr (VALUE) #{@eval_string}" + end + def to_s 'lldb' end @@ -284,6 +290,10 @@ class GDB < NativeDebugger set_tbreak(@tbreak) end + def load_debugger + execute "call #{@eval_string}" + end + def to_s 'gdb' end From 6ae52eef42c62ea3b2f443abb44dfbe7d314ab1a Mon Sep 17 00:00:00 2001 From: equivalence1 Date: Thu, 29 Sep 2016 23:01:20 +0300 Subject: [PATCH 3/5] Gdb does not understand ruby symbol table under OS X (I guess it does not understand darwin debug format). That make it essential to prefer lldb over gdb (lldb works fine). --- bin/gdb_wrapper | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/gdb_wrapper b/bin/gdb_wrapper index d530811..84d7fe3 100755 --- a/bin/gdb_wrapper +++ b/bin/gdb_wrapper @@ -365,10 +365,10 @@ def command_exists(command) end def choose_debugger(ruby_path, pid, gems_to_include, debugger_loader_path, argv) - if command_exists('gdb') - debugger = GDB.new(ruby_path, pid, '-nh -nx', gems_to_include, debugger_loader_path, argv) - elsif command_exists('lldb') + if command_exists('lldb') debugger = LLDB.new(ruby_path, pid, '--no-lldbinit', gems_to_include, debugger_loader_path, argv) + elsif command_exists('gdb') + 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 From c03250eabf1f7120f1118304afdb9a6eb1b50bff Mon Sep 17 00:00:00 2001 From: equivalence1 Date: Thu, 29 Sep 2016 23:12:53 +0300 Subject: [PATCH 4/5] Attach lib can have different extension than '.so' (e.g. '.bundle' under OS X). So we need to find appropriate one manually. --- bin/gdb_wrapper | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bin/gdb_wrapper b/bin/gdb_wrapper index 84d7fe3..d222965 100755 --- a/bin/gdb_wrapper +++ b/bin/gdb_wrapper @@ -99,7 +99,7 @@ class NativeDebugger if debase_path.size == 0 raise 'No debase gem found.' end - @path_to_attach = debase_path[0] + '/attach.so' + @path_to_attach = find_attach_lib(debase_path[0]) @gems_to_include = '["' + gems_to_include * '", "' + '"]' @debugger_loader_path = debugger_loader_path @@ -112,6 +112,18 @@ class NativeDebugger $stdout.puts "executed '#{launch_string}'" end + def find_attach_lib(debase_path) + attach_lib = debase_path + '/attach' + known_extensions = %w(.so .bundle .dll) + known_extensions.each do |ext| + if File.file?(attach_lib + ext) + return attach_lib + ext + end + end + + raise 'Could not find attach library' + end + def attach_to_process execute "attach #{@pid}" end From f3955ca4f99990707ae8d240f9feda72c58d14cc Mon Sep 17 00:00:00 2001 From: equivalence1 Date: Tue, 4 Oct 2016 14:54:04 +0300 Subject: [PATCH 5/5] fixes for lldb-3.6. `print` does not work there. output works bad after `thread select`. replaced debug output with more representative. --- bin/gdb_wrapper | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/bin/gdb_wrapper b/bin/gdb_wrapper index d222965..4fdf002 100755 --- a/bin/gdb_wrapper +++ b/bin/gdb_wrapper @@ -20,15 +20,7 @@ module DebugPrinter def print_debug(msg) if DebugPrinter.cli_debug - delimiter = '=' * 10 - upper_border = "\n#{delimiter}\n" - lower_border = "#{delimiter}\n\n" - - if msg.length > 0 and msg[msg.length - 1] != "\n" - lower_border = "\n" + lower_border - end - - $stdout.puts upper_border + msg + lower_border + $stderr.puts msg end end end @@ -139,18 +131,17 @@ class NativeDebugger def get_response # we need this hack to understand that debugger gave us all output from last executed command - @pipe.puts "print \"#{@delimiter}\"" + print_delimiter content = '' loop do line = @pipe.readline + break if check_delimiter(line) + DebugPrinter.print_debug('respond line: ' + line) next if line =~ /\(lldb\)/ # lldb repeats your input to its output - break if line =~ /\$\d+\s=\s"#{@delimiter}"/ content += line end - DebugPrinter.print_debug(content) - content end @@ -162,6 +153,14 @@ class NativeDebugger end + def print_delimiter + + end + + def check_delimiter(line) + + end + def switch_to_thread end @@ -220,7 +219,6 @@ class LLDB < NativeDebugger info_threads = (execute 'thread list').split("\n") info_threads.each do |thread_info| next unless thread_info =~ /[\s*]*thread\s#\d+.*/ - $stdout.puts "thread_info: #{thread_info}" is_main = thread_info[0] == '*' thread_num = thread_info.sub(/[\s*]*thread\s#/, '').sub(/:\s.*$/, '').to_i thread = ProcessThread.new(thread_num, is_main, thread_info, self) @@ -248,6 +246,14 @@ class LLDB < NativeDebugger set_tbreak(@tbreak) end + def print_delimiter + @pipe.puts "script print \"#{@delimiter}\"" + end + + def check_delimiter(line) + line =~ /#{@delimiter}$/ + end + def load_debugger execute "expr (VALUE) #{@eval_string}" end @@ -302,6 +308,14 @@ class GDB < NativeDebugger set_tbreak(@tbreak) end + def print_delimiter + @pipe.puts "print \"#{@delimiter}\"" + end + + def check_delimiter(line) + line =~ /\$\d+\s=\s"#{@delimiter}"/ + end + def load_debugger execute "call #{@eval_string}" end