diff options
Diffstat (limited to 'lib/debug.rb')
-rw-r--r-- | lib/debug.rb | 636 |
1 files changed, 318 insertions, 318 deletions
diff --git a/lib/debug.rb b/lib/debug.rb index 48b28217a2..4fb9d509e7 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -82,12 +82,12 @@ class DEBUGGER__ def check_suspend while MUTEX.synchronize { - if @suspend_next - DEBUGGER__.waiting.push Thread.current - @suspend_next = false - true - end - } + if @suspend_next + DEBUGGER__.waiting.push Thread.current + @suspend_next = false + true + end + } end end @@ -261,11 +261,11 @@ class DEBUGGER__ set_trace false end end - if trace? - stdout.print "Trace on.\n" - else - stdout.print "Trace off.\n" - end + if trace? + stdout.print "Trace on.\n" + else + stdout.print "Trace off.\n" + end when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/ pos = $2 @@ -304,22 +304,22 @@ class DEBUGGER__ 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] + 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 - n += 1 end - end - if break_points.size == 0 - stdout.print "No breakpoints\n" - else - stdout.print "\n" - end + if break_points.size == 0 + stdout.print "No breakpoints\n" + else + stdout.print "\n" + end when /^\s*del(?:ete)?(?:\s+(\d+))?$/ pos = $1 @@ -375,8 +375,8 @@ class DEBUGGER__ else lev = 1 end - @stop_next = lev - prompt = false + @stop_next = lev + prompt = false when /^\s*n(?:ext)?(?:\s+(\d+))?$/ if $1 @@ -384,9 +384,9 @@ class DEBUGGER__ else lev = 1 end - @stop_next = lev - @no_step = @frames.size - frame_pos - prompt = false + @stop_next = lev + @no_step = @frames.size - frame_pos + prompt = false when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ display_frames(frame_pos) @@ -408,8 +408,8 @@ class DEBUGGER__ e = b + 9 end end - previous_line = b - display_list(b, e, binding_file, binding_line) + previous_line = b + display_list(b, e, binding_file, binding_line) when /^\s*up(?:\s+(\d+))?$/ previous_line = nil @@ -549,359 +549,359 @@ Commands h[elp] print this help <everything else> evaluate EOHELP - end + end - def display_expressions(binding) - n = 1 - for d in display - if d[0] - stdout.printf "%d: ", n - display_expression(d[1], binding) + 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 - 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 + def display_expression(exp, binding) + stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s end - end - def display_frames(pos) - 0.upto(@frames.size - 1) do |n| - if n == pos - stdout.print "--> " - else - stdout.print " " + def frame_set_pos(file, line) + if @frames[0] + @frames[0][1] = file + @frames[0][2] = line 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 display_list(b, e, file, line) - stdout.printf "[%d, %d] in %s\n", b, e, file - if lines = SCRIPT_LINES__[file] and lines != true - 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 + 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 - else - stdout.printf "No sourcefile available for %s\n", file end - end - def line_at(file, line) - lines = SCRIPT_LINES__[file] - if lines - return "\n" if lines == true - line = lines[line-1] - return "\n" unless line - return line + def format_frame(pos) + _, file, line, id = @frames[pos] + sprintf "#%d %s:%s%s\n", pos + 1, file, line, + (id ? ":in `#{id.id2name}'" : "") end - return "\n" - end - def debug_funcname(id) - if id.nil? - "toplevel" - else - id.id2name + def display_list(b, e, file, line) + stdout.printf "[%d, %d] in %s\n", b, e, file + if lines = SCRIPT_LINES__[file] and lines != true + 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 - 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 + def line_at(file, line) + lines = SCRIPT_LINES__[file] + if lines + return "\n" if lines == true + line = lines[line-1] + return "\n" unless line + return line end - n += 1 + return "\n" end - return false - end - def excn_handle(file, line, id, binding) - if $!.class <= SystemExit - set_trace_func nil - exit + def debug_funcname(id) + if id.nil? + "toplevel" + else + id.id2name + end 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 + 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 - suspend_all - debug_command(file, line, id, binding) + return false 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) + def excn_handle(file, line, id, binding) + if $!.class <= SystemExit + set_trace_func nil + exit 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) + 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 - when 'c-call' - frame_set_pos(file, line) + 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 'class' - @frames.unshift [binding, file, line, id] + 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 'return', 'end' - if @frames.size == @finish_pos - @stop_next = 1 - @finish_pos = 0 - end - @frames.shift + when 'c-call' + frame_set_pos(file, line) - when 'raise' - excn_handle(file, line, id, binding) + when 'class' + @frames.unshift [binding, file, line, id] - end - @last_file = file - end -end + when 'return', 'end' + if @frames.size == @finish_pos + @stop_next = 1 + @finish_pos = 0 + end + @frames.shift -trap("INT") { DEBUGGER__.interrupt } -@last_thread = Thread::main -@max_thread = 1 -@thread_list = {Thread::main => 1} -@break_points = [] -@display = [] -@waiting = [] -@stdout = STDOUT - -class << DEBUGGER__ - def stdout - @stdout - end + when 'raise' + excn_handle(file, line, id, binding) - def stdout=(s) - @stdout = s + end + @last_file = file + end end - def display - @display - end + trap("INT") { DEBUGGER__.interrupt } + @last_thread = Thread::main + @max_thread = 1 + @thread_list = {Thread::main => 1} + @break_points = [] + @display = [] + @waiting = [] + @stdout = STDOUT - def break_points - @break_points - end + class << DEBUGGER__ + def stdout + @stdout + end - def waiting - @waiting - end + def stdout=(s) + @stdout = s + end - def set_trace( arg ) - MUTEX.synchronize do - make_thread_list - for th, in @thread_list - context(th).set_trace arg - end + def display + @display end - arg - end - def set_last_thread(th) - @last_thread = th - end + def break_points + @break_points + end - def suspend - MUTEX.synchronize do - make_thread_list - for th, in @thread_list - next if th == Thread.current - context(th).set_suspend - end + def waiting + @waiting 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 + def set_trace( arg ) + MUTEX.synchronize do + make_thread_list + for th, in @thread_list + context(th).set_trace arg + end end - waiting.clear + arg 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 + def set_last_thread(th) + @last_thread = th 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 + 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 - th - end - def thread_list(num) - th = get_thread(num) - if th == Thread.current - @stdout.print "+" - else - @stdout.print " " + 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 - @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} + + def context(thread=Thread.current) + c = thread[:__debugger_data__] + unless c + thread[:__debugger_data__] = c = Context.new + end + c end - @stdout.print "\n" - end - def thread_list_all - for th in @thread_list.values.sort - thread_list(th) + def interrupt + context(@last_thread).stop_next 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 + def get_thread(num) + th = @thread_list.key(num) + unless th + @stdout.print "No thread ##{num}\n" + throw :debug_error end + th 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) + def thread_list(num) + th = get_thread(num) if th == Thread.current - @stdout.print "It's the current thread.\n" + @stdout.print "+" else - thread_list(@thread_list[th]) - context(th).stop_next - th.run - return :cont + @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 - 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 + def thread_list_all + for th in @thread_list.values.sort + thread_list(th) end + 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 + 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 -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 -} + 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 |