diff --git a/lib/debug.gemspec b/lib/debug.gemspec deleted file mode 100644 index 71f93f7409..0000000000 --- a/lib/debug.gemspec +++ /dev/null @@ -1,22 +0,0 @@ -Gem::Specification.new do |spec| - spec.name = "debug" - spec.version = "0.1.0" - spec.authors = ["Yukihiro Matsumoto"] - spec.email = ["matz@ruby-lang.org"] - - spec.summary = %q{Debugging functionality for Ruby} - spec.description = %q{Debugging functionality for Ruby} - spec.homepage = "https://github.com/ruby/debug" - spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0") - spec.licenses = ["Ruby", "BSD-2-Clause"] - - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = spec.homepage - - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - end - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] -end diff --git a/lib/debug.rb b/lib/debug.rb deleted file mode 100644 index bf53eb80a4..0000000000 --- a/lib/debug.rb +++ /dev/null @@ -1,1106 +0,0 @@ -# frozen_string_literal: true -# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. -# Copyright (C) 2000 Information-technology Promotion Agency, Japan -# Copyright (C) 2000-2003 NAKAMURA, Hiroshi - -require 'continuation' - -require 'tracer' -require 'pp' - -class Tracer # :nodoc: - def Tracer.trace_func(*vars) - Single.trace_func(*vars) - end -end - -SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ # :nodoc: - -## -# This library provides debugging functionality to Ruby. -# -# To add a debugger to your code, start by requiring +debug+ in your -# program: -# -# def say(word) -# require 'debug' -# puts word -# end -# -# This will cause Ruby to interrupt execution and show a prompt when the +say+ -# method is run. -# -# Once you're inside the prompt, you can start debugging your program. -# -# (rdb:1) p word -# "hello" -# -# == Getting help -# -# You can get help at any time by pressing +h+. -# -# (rdb:1) h -# Debugger help v.-0.002b -# Commands -# b[reak] [file:|class:] -# b[reak] [class.] -# set breakpoint to some position -# wat[ch] set watchpoint to some expression -# cat[ch] (|off) set catchpoint to an exception -# b[reak] list breakpoints -# cat[ch] show catchpoint -# del[ete][ nnn] delete some or all breakpoints -# disp[lay] add expression into display expression list -# undisp[lay][ nnn] delete one particular or all display expressions -# c[ont] run until program ends or hit breakpoint -# s[tep][ nnn] step (into methods) one line or till line nnn -# n[ext][ nnn] go over one line or till line nnn -# w[here] display frames -# f[rame] alias for where -# l[ist][ (-|nn-mm)] list program, - lists backwards -# nn-mm lists given lines -# up[ nn] move to higher frame -# down[ nn] move to lower frame -# fin[ish] return to outer frame -# tr[ace] (on|off) set trace mode of current thread -# tr[ace] (on|off) all set trace mode of all threads -# q[uit] exit from debugger -# v[ar] g[lobal] show global variables -# v[ar] l[ocal] show local variables -# v[ar] i[nstance] show instance variables of object -# v[ar] c[onst] show constants of object -# m[ethod] i[nstance] show methods of object -# m[ethod] show instance methods of class or module -# th[read] l[ist] list all threads -# th[read] c[ur[rent]] show current thread -# th[read] [sw[itch]] switch thread context to nnn -# th[read] stop stop thread nnn -# th[read] resume resume thread nnn -# p expression evaluate expression and print its value -# h[elp] print this help -# evaluate -# -# == Usage -# -# The following is a list of common functionalities that the debugger -# provides. -# -# === Navigating through your code -# -# In general, a debugger is used to find bugs in your program, which -# often means pausing execution and inspecting variables at some point -# in time. -# -# Let's look at an example: -# -# def my_method(foo) -# require 'debug' -# foo = get_foo if foo.nil? -# raise if foo.nil? -# end -# -# When you run this program, the debugger will kick in just before the -# +foo+ assignment. -# -# (rdb:1) p foo -# nil -# -# In this example, it'd be interesting to move to the next line and -# inspect the value of +foo+ again. You can do that by pressing +n+: -# -# (rdb:1) n # goes to next line -# (rdb:1) p foo -# nil -# -# You now know that the original value of +foo+ was nil, and that it -# still was nil after calling +get_foo+. -# -# Other useful commands for navigating through your code are: -# -# +c+:: -# Runs the program until it either exists or encounters another breakpoint. -# You usually press +c+ when you are finished debugging your program and -# want to resume its execution. -# +s+:: -# Steps into method definition. In the previous example, +s+ would take you -# inside the method definition of +get_foo+. -# +r+:: -# Restart the program. -# +q+:: -# Quit the program. -# -# === Inspecting variables -# -# You can use the debugger to easily inspect both local and global variables. -# We've seen how to inspect local variables before: -# -# (rdb:1) p my_arg -# 42 -# -# You can also pretty print the result of variables or expressions: -# -# (rdb:1) pp %w{a very long long array containing many words} -# ["a", -# "very", -# "long", -# ... -# ] -# -# You can list all local variables with +v l+: -# -# (rdb:1) v l -# foo => "hello" -# -# Similarly, you can show all global variables with +v g+: -# -# (rdb:1) v g -# all global variables -# -# Finally, you can omit +p+ if you simply want to evaluate a variable or -# expression -# -# (rdb:1) 5**2 -# 25 -# -# === Going beyond basics -# -# Ruby Debug provides more advanced functionalities like switching -# between threads, setting breakpoints and watch expressions, and more. -# The full list of commands is available at any time by pressing +h+. -# -# == Staying out of trouble -# -# Make sure you remove every instance of +require 'debug'+ before -# shipping your code. Failing to do so may result in your program -# hanging unpredictably. -# -# Debug is not available in safe mode. - -class DEBUGGER__ - MUTEX = Thread::Mutex.new # :nodoc: - - class Context # :nodoc: - DEBUG_LAST_CMD = [] - - begin - require 'readline' - def readline(prompt, hist) - Readline::readline(prompt, hist) - end - rescue LoadError - def readline(prompt, hist) - STDOUT.print prompt - STDOUT.flush - line = STDIN.gets - exit unless line - line.chomp! - line - end - USE_READLINE = false - end - - def initialize - if Thread.current == Thread.main - @stop_next = 1 - else - @stop_next = 0 - end - @last_file = nil - @file = nil - @line = nil - @no_step = nil - @frames = [] - @finish_pos = 0 - @trace = false - @catch = "StandardError" - @suspend_next = false - end - - def stop_next(n=1) - @stop_next = n - end - - def set_suspend - @suspend_next = true - end - - def clear_suspend - @suspend_next = false - end - - def suspend_all - DEBUGGER__.suspend - end - - def resume_all - DEBUGGER__.resume - end - - def check_suspend - while MUTEX.synchronize { - if @suspend_next - DEBUGGER__.waiting.push Thread.current - @suspend_next = false - true - end - } - end - end - - def trace? - @trace - end - - def set_trace(arg) - @trace = arg - end - - def stdout - DEBUGGER__.stdout - end - - def break_points - DEBUGGER__.break_points - end - - def display - DEBUGGER__.display - end - - def context(th) - DEBUGGER__.context(th) - end - - def set_trace_all(arg) - DEBUGGER__.set_trace(arg) - end - - def set_last_thread(th) - DEBUGGER__.set_last_thread(th) - end - - def debug_eval(str, binding) - begin - eval(str, binding) - rescue StandardError, ScriptError => e - at = eval("caller(1)", binding) - stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '') - for i in at - stdout.printf "\tfrom %s\n", i - end - throw :debug_error - end - end - - def debug_silent_eval(str, binding) - begin - eval(str, binding) - rescue StandardError, ScriptError - nil - end - end - - def var_list(ary, binding) - ary.sort! - for v in ary - stdout.printf " %s => %s\n", v, eval(v.to_s, binding).inspect - end - end - - def debug_variable_info(input, binding) - case input - when /^\s*g(?:lobal)?\s*$/ - var_list(global_variables, binding) - - when /^\s*l(?:ocal)?\s*$/ - var_list(eval("local_variables", binding), binding) - - when /^\s*i(?:nstance)?\s+/ - obj = debug_eval($', binding) - var_list(obj.instance_variables, obj.instance_eval{binding()}) - - when /^\s*c(?:onst(?:ant)?)?\s+/ - obj = debug_eval($', binding) - unless obj.kind_of? Module - stdout.print "Should be Class/Module: ", $', "\n" - else - var_list(obj.constants, obj.module_eval{binding()}) - end - end - end - - def debug_method_info(input, binding) - case input - when /^i(:?nstance)?\s+/ - obj = debug_eval($', binding) - - len = 0 - for v in obj.methods.sort - len += v.size + 1 - if len > 70 - len = v.size + 1 - stdout.print "\n" - end - stdout.print v, " " - end - stdout.print "\n" - - else - obj = debug_eval(input, binding) - unless obj.kind_of? Module - stdout.print "Should be Class/Module: ", input, "\n" - else - len = 0 - for v in obj.instance_methods(false).sort - len += v.size + 1 - if len > 70 - len = v.size + 1 - stdout.print "\n" - end - stdout.print v, " " - end - stdout.print "\n" - end - end - end - - def thnum - num = DEBUGGER__.instance_eval{@thread_list[Thread.current]} - unless num - DEBUGGER__.make_thread_list - num = DEBUGGER__.instance_eval{@thread_list[Thread.current]} - end - num - end - - def debug_command(file, line, id, binding) - MUTEX.lock - unless defined?($debugger_restart) and $debugger_restart - callcc{|c| $debugger_restart = c} - end - set_last_thread(Thread.current) - frame_pos = 0 - binding_file = file - binding_line = line - previous_line = nil - if ENV['EMACS'] - stdout.printf "\032\032%s:%d:\n", binding_file, binding_line - else - stdout.printf "%s:%d:%s", binding_file, binding_line, - line_at(binding_file, binding_line) - end - @frames[0] = [binding, file, line, id] - display_expressions(binding) - prompt = true - while prompt and input = readline("(rdb:%d) "%thnum(), true) - catch(:debug_error) do - if input == "" - next unless DEBUG_LAST_CMD[0] - input = DEBUG_LAST_CMD[0] - stdout.print input, "\n" - else - DEBUG_LAST_CMD[0] = input - end - - case input - when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/ - if defined?( $2 ) - if $1 == 'on' - set_trace_all true - else - set_trace_all false - end - elsif defined?( $1 ) - if $1 == 'on' - set_trace true - else - set_trace false - end - end - if trace? - stdout.print "Trace on.\n" - else - stdout.print "Trace off.\n" - end - - when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/ - pos = $2 - if $1 - klass = debug_silent_eval($1, binding) - file = File.expand_path($1) - end - if pos =~ /^\d+$/ - pname = pos - pos = pos.to_i - else - pname = pos = pos.intern.id2name - end - break_points.push [true, 0, klass || file, pos] - stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname - - when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/ - pos = $2.intern.id2name - klass = debug_eval($1, binding) - break_points.push [true, 0, klass, pos] - stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos - - when /^\s*wat(?:ch)?\s+(.+)$/ - exp = $1 - break_points.push [true, 1, exp] - stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp - - when /^\s*b(?:reak)?$/ - if break_points.find{|b| b[1] == 0} - n = 1 - stdout.print "Breakpoints:\n" - break_points.each do |b| - if b[0] and b[1] == 0 - stdout.printf " %d %s:%s\n", n, b[2], b[3] - end - n += 1 - end - end - if break_points.find{|b| b[1] == 1} - n = 1 - stdout.print "\n" - stdout.print "Watchpoints:\n" - for b in break_points - if b[0] and b[1] == 1 - stdout.printf " %d %s\n", n, b[2] - end - n += 1 - end - end - if break_points.size == 0 - stdout.print "No breakpoints\n" - else - stdout.print "\n" - end - - when /^\s*del(?:ete)?(?:\s+(\d+))?$/ - pos = $1 - unless pos - input = readline("Clear all breakpoints? (y/n) ", false) - if input == "y" - for b in break_points - b[0] = false - end - end - else - pos = pos.to_i - if break_points[pos-1] - break_points[pos-1][0] = false - else - stdout.printf "Breakpoint %d is not defined\n", pos - end - end - - when /^\s*disp(?:lay)?\s+(.+)$/ - exp = $1 - display.push [true, exp] - stdout.printf "%d: ", display.size - display_expression(exp, binding) - - when /^\s*disp(?:lay)?$/ - display_expressions(binding) - - when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/ - pos = $1 - unless pos - input = readline("Clear all expressions? (y/n) ", false) - if input == "y" - for d in display - d[0] = false - end - end - else - pos = pos.to_i - if display[pos-1] - display[pos-1][0] = false - else - stdout.printf "Display expression %d is not defined\n", pos - end - end - - when /^\s*c(?:ont)?$/ - prompt = false - - when /^\s*s(?:tep)?(?:\s+(\d+))?$/ - if $1 - lev = $1.to_i - else - lev = 1 - end - @stop_next = lev - prompt = false - - when /^\s*n(?:ext)?(?:\s+(\d+))?$/ - if $1 - lev = $1.to_i - else - lev = 1 - end - @stop_next = lev - @no_step = @frames.size - frame_pos - prompt = false - - when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ - display_frames(frame_pos) - - when /^\s*l(?:ist)?(?:\s+(.+))?$/ - if not $1 - b = previous_line ? previous_line + 10 : binding_line - 5 - e = b + 9 - elsif $1 == '-' - b = previous_line ? previous_line - 10 : binding_line - 5 - e = b + 9 - else - b, e = $1.split(/[-,]/) - if e - b = b.to_i - e = e.to_i - else - b = b.to_i - 5 - e = b + 9 - end - end - previous_line = b - display_list(b, e, binding_file, binding_line) - - when /^\s*up(?:\s+(\d+))?$/ - previous_line = nil - if $1 - lev = $1.to_i - else - lev = 1 - end - frame_pos += lev - if frame_pos >= @frames.size - frame_pos = @frames.size - 1 - stdout.print "At toplevel\n" - end - binding, binding_file, binding_line = @frames[frame_pos] - stdout.print format_frame(frame_pos) - - when /^\s*down(?:\s+(\d+))?$/ - previous_line = nil - if $1 - lev = $1.to_i - else - lev = 1 - end - frame_pos -= lev - if frame_pos < 0 - frame_pos = 0 - stdout.print "At stack bottom\n" - end - binding, binding_file, binding_line = @frames[frame_pos] - stdout.print format_frame(frame_pos) - - when /^\s*fin(?:ish)?$/ - if frame_pos == @frames.size - stdout.print "\"finish\" not meaningful in the outermost frame.\n" - else - @finish_pos = @frames.size - frame_pos - frame_pos = 0 - prompt = false - end - - when /^\s*cat(?:ch)?(?:\s+(.+))?$/ - if $1 - excn = $1 - if excn == 'off' - @catch = nil - stdout.print "Clear catchpoint.\n" - else - @catch = excn - stdout.printf "Set catchpoint %s.\n", @catch - end - else - if @catch - stdout.printf "Catchpoint %s.\n", @catch - else - stdout.print "No catchpoint.\n" - end - end - - when /^\s*q(?:uit)?$/ - input = readline("Really quit? (y/n) ", false) - if input == "y" - exit! # exit -> exit!: No graceful way to stop threads... - end - - when /^\s*v(?:ar)?\s+/ - debug_variable_info($', binding) - - when /^\s*m(?:ethod)?\s+/ - debug_method_info($', binding) - - when /^\s*th(?:read)?\s+/ - if DEBUGGER__.debug_thread_info($', binding) == :cont - prompt = false - end - - when /^\s*pp\s+/ - PP.pp(debug_eval($', binding), stdout) - - when /^\s*p\s+/ - stdout.printf "%s\n", debug_eval($', binding).inspect - - when /^\s*r(?:estart)?$/ - $debugger_restart.call - - when /^\s*h(?:elp)?$/ - debug_print_help() - - else - v = debug_eval(input, binding) - stdout.printf "%s\n", v.inspect - end - end - end - MUTEX.unlock - resume_all - end - - def debug_print_help - stdout.print < - b[reak] [class.] - set breakpoint to some position - wat[ch] set watchpoint to some expression - cat[ch] (|off) set catchpoint to an exception - b[reak] list breakpoints - cat[ch] show catchpoint - del[ete][ nnn] delete some or all breakpoints - disp[lay] add expression into display expression list - undisp[lay][ nnn] delete one particular or all display expressions - c[ont] run until program ends or hit breakpoint - s[tep][ nnn] step (into methods) one line or till line nnn - n[ext][ nnn] go over one line or till line nnn - w[here] display frames - f[rame] alias for where - l[ist][ (-|nn-mm)] list program, - lists backwards - nn-mm lists given lines - up[ nn] move to higher frame - down[ nn] move to lower frame - fin[ish] return to outer frame - tr[ace] (on|off) set trace mode of current thread - tr[ace] (on|off) all set trace mode of all threads - q[uit] exit from debugger - v[ar] g[lobal] show global variables - v[ar] l[ocal] show local variables - v[ar] i[nstance] show instance variables of object - v[ar] c[onst] show constants of object - m[ethod] i[nstance] show methods of object - m[ethod] show instance methods of class or module - th[read] l[ist] list all threads - th[read] c[ur[rent]] show current thread - th[read] [sw[itch]] switch thread context to nnn - th[read] stop stop thread nnn - th[read] resume resume thread nnn - pp expression evaluate expression and pretty_print its value - p expression evaluate expression and print its value - r[estart] restart program - h[elp] print this help - evaluate -EOHELP - end - - def display_expressions(binding) - n = 1 - for d in display - if d[0] - stdout.printf "%d: ", n - display_expression(d[1], binding) - end - n += 1 - end - end - - def display_expression(exp, binding) - stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s - end - - def frame_set_pos(file, line) - if @frames[0] - @frames[0][1] = file - @frames[0][2] = line - end - end - - def display_frames(pos) - 0.upto(@frames.size - 1) do |n| - if n == pos - stdout.print "--> " - else - stdout.print " " - end - stdout.print format_frame(n) - end - end - - def format_frame(pos) - _, file, line, id = @frames[pos] - sprintf "#%d %s:%s%s\n", pos + 1, file, line, - (id ? ":in `#{id.id2name}'" : "") - end - - def script_lines(file, line) - unless (lines = SCRIPT_LINES__[file]) and lines != true - Tracer::Single.get_line(file, line) if File.exist?(file) - lines = SCRIPT_LINES__[file] - lines = nil if lines == true - end - lines - end - - def display_list(b, e, file, line) - if lines = script_lines(file, line) - stdout.printf "[%d, %d] in %s\n", b, e, file - b.upto(e) do |n| - if n > 0 && lines[n-1] - if n == line - stdout.printf "=> %d %s\n", n, lines[n-1].chomp - else - stdout.printf " %d %s\n", n, lines[n-1].chomp - end - end - end - else - stdout.printf "No sourcefile available for %s\n", file - end - end - - def line_at(file, line) - lines = script_lines(file, line) - if lines and line = lines[line-1] - return line - end - return "\n" - end - - def debug_funcname(id) - if id.nil? - "toplevel" - else - id.id2name - end - end - - def check_break_points(file, klass, pos, binding, id) - return false if break_points.empty? - n = 1 - for b in break_points - if b[0] # valid - if b[1] == 0 # breakpoint - if (b[2] == file and b[3] == pos) or - (klass and b[2] == klass and b[3] == pos) - stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos - return true - end - elsif b[1] == 1 # watchpoint - if debug_silent_eval(b[2], binding) - stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos - return true - end - end - end - n += 1 - end - return false - end - - def excn_handle(file, line, id, binding) - if $!.class <= SystemExit - set_trace_func nil - exit - end - - if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch }) - stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class - fs = @frames.size - tb = caller(0)[-fs..-1] - if tb - for i in tb - stdout.printf "\tfrom %s\n", i - end - end - suspend_all - debug_command(file, line, id, binding) - end - end - - def trace_func(event, file, line, id, binding, klass) - Tracer.trace_func(event, file, line, id, binding, klass) if trace? - context(Thread.current).check_suspend - @file = file - @line = line - case event - when 'line' - frame_set_pos(file, line) - if !@no_step or @frames.size == @no_step - @stop_next -= 1 - @stop_next = -1 if @stop_next < 0 - elsif @frames.size < @no_step - @stop_next = 0 # break here before leaving... - else - # nothing to do. skipped. - end - if @stop_next == 0 or check_break_points(file, nil, line, binding, id) - @no_step = nil - suspend_all - debug_command(file, line, id, binding) - end - - when 'call' - @frames.unshift [binding, file, line, id] - if check_break_points(file, klass, id.id2name, binding, id) - suspend_all - debug_command(file, line, id, binding) - end - - when 'c-call' - frame_set_pos(file, line) - - when 'class' - @frames.unshift [binding, file, line, id] - - when 'return', 'end' - if @frames.size == @finish_pos - @stop_next = 1 - @finish_pos = 0 - end - @frames.shift - - when 'raise' - excn_handle(file, line, id, binding) - - end - @last_file = file - end - end - - trap("INT") { DEBUGGER__.interrupt } - @last_thread = Thread::main - @max_thread = 1 - @thread_list = {Thread::main => 1} - @break_points = [] - @display = [] - @waiting = [] - @stdout = STDOUT - - class << DEBUGGER__ - # Returns the IO used as stdout. Defaults to STDOUT - def stdout - @stdout - end - - # Sets the IO used as stdout. Defaults to STDOUT - def stdout=(s) - @stdout = s - end - - # Returns the display expression list - # - # See DEBUGGER__ for more usage - def display - @display - end - - # Returns the list of break points where execution will be stopped. - # - # See DEBUGGER__ for more usage - def break_points - @break_points - end - - # Returns the list of waiting threads. - # - # When stepping through the traces of a function, thread gets suspended, to - # be resumed later. - def waiting - @waiting - end - - def set_trace( arg ) - MUTEX.synchronize do - make_thread_list - for th, in @thread_list - context(th).set_trace arg - end - end - arg - end - - def set_last_thread(th) - @last_thread = th - end - - def suspend - MUTEX.synchronize do - make_thread_list - for th, in @thread_list - next if th == Thread.current - context(th).set_suspend - end - end - # Schedule other threads to suspend as soon as possible. - Thread.pass - end - - def resume - MUTEX.synchronize do - make_thread_list - @thread_list.each do |th,| - next if th == Thread.current - context(th).clear_suspend - end - waiting.each do |th| - th.run - end - waiting.clear - end - # Schedule other threads to restart as soon as possible. - Thread.pass - end - - def context(thread=Thread.current) - c = thread[:__debugger_data__] - unless c - thread[:__debugger_data__] = c = Context.new - end - c - end - - def interrupt - context(@last_thread).stop_next - end - - def get_thread(num) - th = @thread_list.key(num) - unless th - @stdout.print "No thread ##{num}\n" - throw :debug_error - end - th - end - - def thread_list(num) - th = get_thread(num) - if th == Thread.current - @stdout.print "+" - else - @stdout.print " " - end - @stdout.printf "%d ", num - @stdout.print th.inspect, "\t" - file = context(th).instance_eval{@file} - if file - @stdout.print file,":",context(th).instance_eval{@line} - end - @stdout.print "\n" - end - - # Prints all threads in @thread_list to @stdout. Returns a sorted array of - # values from the @thread_list hash. - # - # While in the debugger you can list all of - # the threads with: DEBUGGER__.thread_list_all - # - # (rdb:1) DEBUGGER__.thread_list_all - # +1 # debug_me.rb.rb:3 - # 2 # - # 3 # - # [1, 2, 3] - # - # Your current thread is indicated by a + - # - # Additionally you can list all threads with th l - # - # (rdb:1) th l - # +1 # debug_me.rb:3 - # 2 # debug_me.rb:3 - # 3 # debug_me.rb:3 - # - # See DEBUGGER__ for more usage. - - def thread_list_all - for th in @thread_list.values.sort - thread_list(th) - end - end - - def make_thread_list - hash = {} - for th in Thread::list - if @thread_list.key? th - hash[th] = @thread_list[th] - else - @max_thread += 1 - hash[th] = @max_thread - end - end - @thread_list = hash - end - - def debug_thread_info(input, binding) - case input - when /^l(?:ist)?/ - make_thread_list - thread_list_all - - when /^c(?:ur(?:rent)?)?$/ - make_thread_list - thread_list(@thread_list[Thread.current]) - - when /^(?:sw(?:itch)?\s+)?(\d+)/ - make_thread_list - th = get_thread($1.to_i) - if th == Thread.current - @stdout.print "It's the current thread.\n" - else - thread_list(@thread_list[th]) - context(th).stop_next - th.run - return :cont - end - - when /^stop\s+(\d+)/ - make_thread_list - th = get_thread($1.to_i) - if th == Thread.current - @stdout.print "It's the current thread.\n" - elsif th.stop? - @stdout.print "Already stopped.\n" - else - thread_list(@thread_list[th]) - context(th).suspend - end - - when /^resume\s+(\d+)/ - make_thread_list - th = get_thread($1.to_i) - if th == Thread.current - @stdout.print "It's the current thread.\n" - elsif !th.stop? - @stdout.print "Already running." - else - thread_list(@thread_list[th]) - th.run - end - end - end - end - - stdout.printf "Debug.rb\n" - stdout.printf "Emacs support available.\n\n" - RubyVM::InstructionSequence.compile_option = { - trace_instruction: true - } - set_trace_func proc { |event, file, line, id, binding, klass, *rest| - DEBUGGER__.context.trace_func event, file, line, id, binding, klass - } -end