Methods
break_points
check_break_points
check_suspend
clear_suspend
context
debug_command
debug_eval
debug_funcname
debug_method_info
debug_print_help
debug_silent_eval
debug_variable_info
display
display_expression
display_expressions
display_frames
display_list
excn_handle
format_frame
frame_set_pos
line_at
new
readline
readline
resume_all
set_last_thread
set_suspend
set_trace
set_trace_all
stdout
stop_next
suspend_all
thnum
trace?
trace_func
var_list
Constants
| DEBUG_LAST_CMD | = | [] |
| USE_READLINE | = | false |
Public Class methods
# File debug.rb, line 83
83: def initialize
84: if Thread.current == Thread.main
85: @stop_next = 1
86: else
87: @stop_next = 0
88: end
89: @last_file = nil
90: @file = nil
91: @line = nil
92: @no_step = nil
93: @frames = []
94: @finish_pos = 0
95: @trace = false
96: @catch = "StandardError"
97: @suspend_next = false
98: end
Public Instance methods
# File debug.rb, line 661
661: def check_break_points(file, klass, pos, binding, id)
662: return false if break_points.empty?
663: n = 1
664: for b in break_points
665: if b[0] # valid
666: if b[1] == 0 # breakpoint
667: if (b[2] == file and b[3] == pos) or
668: (klass and b[2] == klass and b[3] == pos)
669: stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
670: return true
671: end
672: elsif b[1] == 1 # watchpoint
673: if debug_silent_eval(b[2], binding)
674: stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
675: return true
676: end
677: end
678: end
679: n += 1
680: end
681: return false
682: end
# File debug.rb, line 120
120: def check_suspend
121: return if Thread.critical
122: while (Thread.critical = true; @suspend_next)
123: DEBUGGER__.waiting.push Thread.current
124: @suspend_next = false
125: Thread.stop
126: end
127: Thread.critical = false
128: end
# File debug.rb, line 256
256: def debug_command(file, line, id, binding)
257: MUTEX.lock
258: set_last_thread(Thread.current)
259: frame_pos = 0
260: binding_file = file
261: binding_line = line
262: previous_line = nil
263: if ENV['EMACS']
264: stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
265: else
266: stdout.printf "%s:%d:%s", binding_file, binding_line,
267: line_at(binding_file, binding_line)
268: end
269: @frames[0] = [binding, file, line, id]
270: display_expressions(binding)
271: prompt = true
272: while prompt and input = readline("(rdb:%d) "%thnum(), true)
273: catch(:debug_error) do
274: if input == ""
275: next unless DEBUG_LAST_CMD[0]
276: input = DEBUG_LAST_CMD[0]
277: stdout.print input, "\n"
278: else
279: DEBUG_LAST_CMD[0] = input
280: end
281:
282: case input
283: when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
284: if defined?( $2 )
285: if $1 == 'on'
286: set_trace_all true
287: else
288: set_trace_all false
289: end
290: elsif defined?( $1 )
291: if $1 == 'on'
292: set_trace true
293: else
294: set_trace false
295: end
296: end
297: if trace?
298: stdout.print "Trace on.\n"
299: else
300: stdout.print "Trace off.\n"
301: end
302:
303: when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
304: pos = $2
305: if $1
306: klass = debug_silent_eval($1, binding)
307: file = $1
308: end
309: if pos =~ /^\d+$/
310: pname = pos
311: pos = pos.to_i
312: else
313: pname = pos = pos.intern.id2name
314: end
315: break_points.push [true, 0, klass || file, pos]
316: stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
317:
318: when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
319: pos = $2.intern.id2name
320: klass = debug_eval($1, binding)
321: break_points.push [true, 0, klass, pos]
322: stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
323:
324: when /^\s*wat(?:ch)?\s+(.+)$/
325: exp = $1
326: break_points.push [true, 1, exp]
327: stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
328:
329: when /^\s*b(?:reak)?$/
330: if break_points.find{|b| b[1] == 0}
331: n = 1
332: stdout.print "Breakpoints:\n"
333: for b in break_points
334: if b[0] and b[1] == 0
335: stdout.printf " %d %s:%s\n", n, b[2], b[3]
336: end
337: n += 1
338: end
339: end
340: if break_points.find{|b| b[1] == 1}
341: n = 1
342: stdout.print "\n"
343: stdout.print "Watchpoints:\n"
344: for b in break_points
345: if b[0] and b[1] == 1
346: stdout.printf " %d %s\n", n, b[2]
347: end
348: n += 1
349: end
350: end
351: if break_points.size == 0
352: stdout.print "No breakpoints\n"
353: else
354: stdout.print "\n"
355: end
356:
357: when /^\s*del(?:ete)?(?:\s+(\d+))?$/
358: pos = $1
359: unless pos
360: input = readline("Clear all breakpoints? (y/n) ", false)
361: if input == "y"
362: for b in break_points
363: b[0] = false
364: end
365: end
366: else
367: pos = pos.to_i
368: if break_points[pos-1]
369: break_points[pos-1][0] = false
370: else
371: stdout.printf "Breakpoint %d is not defined\n", pos
372: end
373: end
374:
375: when /^\s*disp(?:lay)?\s+(.+)$/
376: exp = $1
377: display.push [true, exp]
378: stdout.printf "%d: ", display.size
379: display_expression(exp, binding)
380:
381: when /^\s*disp(?:lay)?$/
382: display_expressions(binding)
383:
384: when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
385: pos = $1
386: unless pos
387: input = readline("Clear all expressions? (y/n) ", false)
388: if input == "y"
389: for d in display
390: d[0] = false
391: end
392: end
393: else
394: pos = pos.to_i
395: if display[pos-1]
396: display[pos-1][0] = false
397: else
398: stdout.printf "Display expression %d is not defined\n", pos
399: end
400: end
401:
402: when /^\s*c(?:ont)?$/
403: prompt = false
404:
405: when /^\s*s(?:tep)?(?:\s+(\d+))?$/
406: if $1
407: lev = $1.to_i
408: else
409: lev = 1
410: end
411: @stop_next = lev
412: prompt = false
413:
414: when /^\s*n(?:ext)?(?:\s+(\d+))?$/
415: if $1
416: lev = $1.to_i
417: else
418: lev = 1
419: end
420: @stop_next = lev
421: @no_step = @frames.size - frame_pos
422: prompt = false
423:
424: when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
425: display_frames(frame_pos)
426:
427: when /^\s*l(?:ist)?(?:\s+(.+))?$/
428: if not $1
429: b = previous_line ? previous_line + 10 : binding_line - 5
430: e = b + 9
431: elsif $1 == '-'
432: b = previous_line ? previous_line - 10 : binding_line - 5
433: e = b + 9
434: else
435: b, e = $1.split(/[-,]/)
436: if e
437: b = b.to_i
438: e = e.to_i
439: else
440: b = b.to_i - 5
441: e = b + 9
442: end
443: end
444: previous_line = b
445: display_list(b, e, binding_file, binding_line)
446:
447: when /^\s*up(?:\s+(\d+))?$/
448: previous_line = nil
449: if $1
450: lev = $1.to_i
451: else
452: lev = 1
453: end
454: frame_pos += lev
455: if frame_pos >= @frames.size
456: frame_pos = @frames.size - 1
457: stdout.print "At toplevel\n"
458: end
459: binding, binding_file, binding_line = @frames[frame_pos]
460: stdout.print format_frame(frame_pos)
461:
462: when /^\s*down(?:\s+(\d+))?$/
463: previous_line = nil
464: if $1
465: lev = $1.to_i
466: else
467: lev = 1
468: end
469: frame_pos -= lev
470: if frame_pos < 0
471: frame_pos = 0
472: stdout.print "At stack bottom\n"
473: end
474: binding, binding_file, binding_line = @frames[frame_pos]
475: stdout.print format_frame(frame_pos)
476:
477: when /^\s*fin(?:ish)?$/
478: if frame_pos == @frames.size
479: stdout.print "\"finish\" not meaningful in the outermost frame.\n"
480: else
481: @finish_pos = @frames.size - frame_pos
482: frame_pos = 0
483: prompt = false
484: end
485:
486: when /^\s*cat(?:ch)?(?:\s+(.+))?$/
487: if $1
488: excn = $1
489: if excn == 'off'
490: @catch = nil
491: stdout.print "Clear catchpoint.\n"
492: else
493: @catch = excn
494: stdout.printf "Set catchpoint %s.\n", @catch
495: end
496: else
497: if @catch
498: stdout.printf "Catchpoint %s.\n", @catch
499: else
500: stdout.print "No catchpoint.\n"
501: end
502: end
503:
504: when /^\s*q(?:uit)?$/
505: input = readline("Really quit? (y/n) ", false)
506: if input == "y"
507: exit! # exit -> exit!: No graceful way to stop threads...
508: end
509:
510: when /^\s*v(?:ar)?\s+/
511: debug_variable_info($', binding)
512:
513: when /^\s*m(?:ethod)?\s+/
514: debug_method_info($', binding)
515:
516: when /^\s*th(?:read)?\s+/
517: if DEBUGGER__.debug_thread_info($', binding) == :cont
518: prompt = false
519: end
520:
521: when /^\s*pp\s+/
522: PP.pp(debug_eval($', binding), stdout)
523:
524: when /^\s*p\s+/
525: stdout.printf "%s\n", debug_eval($', binding).inspect
526:
527: when /^\s*h(?:elp)?$/
528: debug_print_help()
529:
530: else
531: v = debug_eval(input, binding)
532: stdout.printf "%s\n", v.inspect
533: end
534: end
535: end
536: MUTEX.unlock
537: resume_all
538: end
# File debug.rb, line 162
162: def debug_eval(str, binding)
163: begin
164: val = eval(str, binding)
165: rescue StandardError, ScriptError => e
166: at = eval("caller(1)", binding)
167: stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
168: for i in at
169: stdout.printf "\tfrom %s\n", i
170: end
171: throw :debug_error
172: end
173: end
# File debug.rb, line 653
653: def debug_funcname(id)
654: if id.nil?
655: "toplevel"
656: else
657: id.id2name
658: end
659: end
# File debug.rb, line 212
212: def debug_method_info(input, binding)
213: case input
214: when /^i(:?nstance)?\s+/
215: obj = debug_eval($', binding)
216:
217: len = 0
218: for v in obj.methods.sort
219: len += v.size + 1
220: if len > 70
221: len = v.size + 1
222: stdout.print "\n"
223: end
224: stdout.print v, " "
225: end
226: stdout.print "\n"
227:
228: else
229: obj = debug_eval(input, binding)
230: unless obj.kind_of? Module
231: stdout.print "Should be Class/Module: ", input, "\n"
232: else
233: len = 0
234: for v in obj.instance_methods(false).sort
235: len += v.size + 1
236: if len > 70
237: len = v.size + 1
238: stdout.print "\n"
239: end
240: stdout.print v, " "
241: end
242: stdout.print "\n"
243: end
244: end
245: end
# File debug.rb, line 540
540: def debug_print_help
541: stdout.print "Debugger help v.-0.002b\nCommands\n b[reak] [file|class:]<line|method>\n b[reak] [class.]<line|method>\n set breakpoint to some position\n wat[ch] <expression> set watchpoint to some expression\n cat[ch] <an Exception> set catchpoint to an exception\n b[reak] list breakpoints\n cat[ch] show catchpoint\n del[ete][ nnn] delete some or all breakpoints\n disp[lay] <expression> add expression into display expression list\n undisp[lay][ nnn] delete one particular or all display expressions\n c[ont] run until program ends or hit breakpoint\n s[tep][ nnn] step (into methods) one line or till line nnn\n n[ext][ nnn] go over one line or till line nnn\n w[here] display frames\n f[rame] alias for where\n l[ist][ (-|nn-mm)] list program, - lists backwards\n nn-mm lists given lines\n up[ nn] move to higher frame\n down[ nn] move to lower frame\n fin[ish] return to outer frame\n tr[ace] (on|off) set trace mode of current thread\n tr[ace] (on|off) all set trace mode of all threads\n q[uit] exit from debugger\n v[ar] g[lobal] show global variables\n v[ar] l[ocal] show local variables\n v[ar] i[nstance] <object> show instance variables of object\n v[ar] c[onst] <object> show constants of object\n m[ethod] i[nstance] <obj> show methods of object\n m[ethod] <class|module> show instance methods of class or module\n th[read] l[ist] list all threads\n th[read] c[ur[rent]] show current thread\n th[read] [sw[itch]] <nnn> switch thread context to nnn\n th[read] stop <nnn> stop thread nnn\n th[read] resume <nnn> resume thread nnn\n p expression evaluate expression and print its value\n h[elp] print this help\n <everything else> evaluate\n"
542: end
# File debug.rb, line 175
175: def debug_silent_eval(str, binding)
176: begin
177: eval(str, binding)
178: rescue StandardError, ScriptError
179: nil
180: end
181: end
# File debug.rb, line 190
190: def debug_variable_info(input, binding)
191: case input
192: when /^\s*g(?:lobal)?\s*$/
193: var_list(global_variables, binding)
194:
195: when /^\s*l(?:ocal)?\s*$/
196: var_list(eval("local_variables", binding), binding)
197:
198: when /^\s*i(?:nstance)?\s+/
199: obj = debug_eval($', binding)
200: var_list(obj.instance_variables, obj.instance_eval{binding()})
201:
202: when /^\s*c(?:onst(?:ant)?)?\s+/
203: obj = debug_eval($', binding)
204: unless obj.kind_of? Module
205: stdout.print "Should be Class/Module: ", $', "\n"
206: else
207: var_list(obj.constants, obj.module_eval{binding()})
208: end
209: end
210: end
# File debug.rb, line 596
596: def display_expression(exp, binding)
597: stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
598: end
# File debug.rb, line 585
585: def display_expressions(binding)
586: n = 1
587: for d in display
588: if d[0]
589: stdout.printf "%d: ", n
590: display_expression(d[1], binding)
591: end
592: n += 1
593: end
594: end
# File debug.rb, line 607
607: def display_frames(pos)
608: 0.upto(@frames.size - 1) do |n|
609: if n == pos
610: stdout.print "--> "
611: else
612: stdout.print " "
613: end
614: stdout.print format_frame(n)
615: end
616: end
# File debug.rb, line 624
624: def display_list(b, e, file, line)
625: stdout.printf "[%d, %d] in %s\n", b, e, file
626: if lines = SCRIPT_LINES__[file] and lines != true
627: n = 0
628: b.upto(e) do |n|
629: if n > 0 && lines[n-1]
630: if n == line
631: stdout.printf "=> %d %s\n", n, lines[n-1].chomp
632: else
633: stdout.printf " %d %s\n", n, lines[n-1].chomp
634: end
635: end
636: end
637: else
638: stdout.printf "No sourcefile available for %s\n", file
639: end
640: end
# File debug.rb, line 684
684: def excn_handle(file, line, id, binding)
685: if $!.class <= SystemExit
686: set_trace_func nil
687: exit
688: end
689:
690: if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
691: stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class
692: fs = @frames.size
693: tb = caller(0)[-fs..-1]
694: if tb
695: for i in tb
696: stdout.printf "\tfrom %s\n", i
697: end
698: end
699: suspend_all
700: debug_command(file, line, id, binding)
701: end
702: end
# File debug.rb, line 618
618: def format_frame(pos)
619: bind, file, line, id = @frames[pos]
620: sprintf "#%d %s:%s%s\n", pos + 1, file, line,
621: (id ? ":in `#{id.id2name}'" : "")
622: end
# File debug.rb, line 600
600: def frame_set_pos(file, line)
601: if @frames[0]
602: @frames[0][1] = file
603: @frames[0][2] = line
604: end
605: end
# File debug.rb, line 642
642: def line_at(file, line)
643: lines = SCRIPT_LINES__[file]
644: if lines
645: return "\n" if lines == true
646: line = lines[line-1]
647: return "\n" unless line
648: return line
649: end
650: return "\n"
651: end
# File debug.rb, line 68
68: def readline(prompt, hist)
69: Readline::readline(prompt, hist)
70: end
# File debug.rb, line 72
72: def readline(prompt, hist)
73: STDOUT.print prompt
74: STDOUT.flush
75: line = STDIN.gets
76: exit unless line
77: line.chomp!
78: line
79: end
# File debug.rb, line 247
247: def thnum
248: num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
249: unless num
250: DEBUGGER__.make_thread_list
251: num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
252: end
253: num
254: end
# File debug.rb, line 704
704: def trace_func(event, file, line, id, binding, klass)
705: Tracer.trace_func(event, file, line, id, binding, klass) if trace?
706: context(Thread.current).check_suspend
707: @file = file
708: @line = line
709: case event
710: when 'line'
711: frame_set_pos(file, line)
712: if !@no_step or @frames.size == @no_step
713: @stop_next -= 1
714: @stop_next = -1 if @stop_next < 0
715: elsif @frames.size < @no_step
716: @stop_next = 0 # break here before leaving...
717: else
718: # nothing to do. skipped.
719: end
720: if @stop_next == 0 or check_break_points(file, nil, line, binding, id)
721: @no_step = nil
722: suspend_all
723: debug_command(file, line, id, binding)
724: end
725:
726: when 'call'
727: @frames.unshift [binding, file, line, id]
728: if check_break_points(file, klass, id.id2name, binding, id)
729: suspend_all
730: debug_command(file, line, id, binding)
731: end
732:
733: when 'c-call'
734: frame_set_pos(file, line)
735:
736: when 'class'
737: @frames.unshift [binding, file, line, id]
738:
739: when 'return', 'end'
740: if @frames.size == @finish_pos
741: @stop_next = 1
742: @finish_pos = 0
743: end
744: @frames.shift
745:
746: when 'end'
747: @frames.shift
748:
749: when 'raise'
750: excn_handle(file, line, id, binding)
751:
752: end
753: @last_file = file
754: end