| Class | DEBUGGER__::Context |
| In: |
lib/debug.rb
|
| Parent: | Object |
| DEBUG_LAST_CMD | = | [] |
| USE_READLINE | = | false |
# File lib/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
# File lib/debug.rb, line 667
667: def check_break_points(file, klass, pos, binding, id)
668: return false if break_points.empty?
669: n = 1
670: for b in break_points
671: if b[0] # valid
672: if b[1] == 0 # breakpoint
673: if (b[2] == file and b[3] == pos) or
674: (klass and b[2] == klass and b[3] == pos)
675: stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
676: return true
677: end
678: elsif b[1] == 1 # watchpoint
679: if debug_silent_eval(b[2], binding)
680: stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
681: return true
682: end
683: end
684: end
685: n += 1
686: end
687: return false
688: end
# File lib/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 lib/debug.rb, line 256
256: def debug_command(file, line, id, binding)
257: MUTEX.lock
258: unless defined?($debugger_restart) and $debugger_restart
259: callcc{|c| $debugger_restart = c}
260: end
261: set_last_thread(Thread.current)
262: frame_pos = 0
263: binding_file = file
264: binding_line = line
265: previous_line = nil
266: if ENV['EMACS']
267: stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
268: else
269: stdout.printf "%s:%d:%s", binding_file, binding_line,
270: line_at(binding_file, binding_line)
271: end
272: @frames[0] = [binding, file, line, id]
273: display_expressions(binding)
274: prompt = true
275: while prompt and input = readline("(rdb:%d) "%thnum(), true)
276: catch(:debug_error) do
277: if input == ""
278: next unless DEBUG_LAST_CMD[0]
279: input = DEBUG_LAST_CMD[0]
280: stdout.print input, "\n"
281: else
282: DEBUG_LAST_CMD[0] = input
283: end
284:
285: case input
286: when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
287: if defined?( $2 )
288: if $1 == 'on'
289: set_trace_all true
290: else
291: set_trace_all false
292: end
293: elsif defined?( $1 )
294: if $1 == 'on'
295: set_trace true
296: else
297: set_trace false
298: end
299: end
300: if trace?
301: stdout.print "Trace on.\n"
302: else
303: stdout.print "Trace off.\n"
304: end
305:
306: when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
307: pos = $2
308: if $1
309: klass = debug_silent_eval($1, binding)
310: file = $1
311: end
312: if pos =~ /^\d+$/
313: pname = pos
314: pos = pos.to_i
315: else
316: pname = pos = pos.intern.id2name
317: end
318: break_points.push [true, 0, klass || file, pos]
319: stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
320:
321: when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
322: pos = $2.intern.id2name
323: klass = debug_eval($1, binding)
324: break_points.push [true, 0, klass, pos]
325: stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
326:
327: when /^\s*wat(?:ch)?\s+(.+)$/
328: exp = $1
329: break_points.push [true, 1, exp]
330: stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
331:
332: when /^\s*b(?:reak)?$/
333: if break_points.find{|b| b[1] == 0}
334: n = 1
335: stdout.print "Breakpoints:\n"
336: for b in break_points
337: if b[0] and b[1] == 0
338: stdout.printf " %d %s:%s\n", n, b[2], b[3]
339: end
340: n += 1
341: end
342: end
343: if break_points.find{|b| b[1] == 1}
344: n = 1
345: stdout.print "\n"
346: stdout.print "Watchpoints:\n"
347: for b in break_points
348: if b[0] and b[1] == 1
349: stdout.printf " %d %s\n", n, b[2]
350: end
351: n += 1
352: end
353: end
354: if break_points.size == 0
355: stdout.print "No breakpoints\n"
356: else
357: stdout.print "\n"
358: end
359:
360: when /^\s*del(?:ete)?(?:\s+(\d+))?$/
361: pos = $1
362: unless pos
363: input = readline("Clear all breakpoints? (y/n) ", false)
364: if input == "y"
365: for b in break_points
366: b[0] = false
367: end
368: end
369: else
370: pos = pos.to_i
371: if break_points[pos-1]
372: break_points[pos-1][0] = false
373: else
374: stdout.printf "Breakpoint %d is not defined\n", pos
375: end
376: end
377:
378: when /^\s*disp(?:lay)?\s+(.+)$/
379: exp = $1
380: display.push [true, exp]
381: stdout.printf "%d: ", display.size
382: display_expression(exp, binding)
383:
384: when /^\s*disp(?:lay)?$/
385: display_expressions(binding)
386:
387: when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
388: pos = $1
389: unless pos
390: input = readline("Clear all expressions? (y/n) ", false)
391: if input == "y"
392: for d in display
393: d[0] = false
394: end
395: end
396: else
397: pos = pos.to_i
398: if display[pos-1]
399: display[pos-1][0] = false
400: else
401: stdout.printf "Display expression %d is not defined\n", pos
402: end
403: end
404:
405: when /^\s*c(?:ont)?$/
406: prompt = false
407:
408: when /^\s*s(?:tep)?(?:\s+(\d+))?$/
409: if $1
410: lev = $1.to_i
411: else
412: lev = 1
413: end
414: @stop_next = lev
415: prompt = false
416:
417: when /^\s*n(?:ext)?(?:\s+(\d+))?$/
418: if $1
419: lev = $1.to_i
420: else
421: lev = 1
422: end
423: @stop_next = lev
424: @no_step = @frames.size - frame_pos
425: prompt = false
426:
427: when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
428: display_frames(frame_pos)
429:
430: when /^\s*l(?:ist)?(?:\s+(.+))?$/
431: if not $1
432: b = previous_line ? previous_line + 10 : binding_line - 5
433: e = b + 9
434: elsif $1 == '-'
435: b = previous_line ? previous_line - 10 : binding_line - 5
436: e = b + 9
437: else
438: b, e = $1.split(/[-,]/)
439: if e
440: b = b.to_i
441: e = e.to_i
442: else
443: b = b.to_i - 5
444: e = b + 9
445: end
446: end
447: previous_line = b
448: display_list(b, e, binding_file, binding_line)
449:
450: when /^\s*up(?:\s+(\d+))?$/
451: previous_line = nil
452: if $1
453: lev = $1.to_i
454: else
455: lev = 1
456: end
457: frame_pos += lev
458: if frame_pos >= @frames.size
459: frame_pos = @frames.size - 1
460: stdout.print "At toplevel\n"
461: end
462: binding, binding_file, binding_line = @frames[frame_pos]
463: stdout.print format_frame(frame_pos)
464:
465: when /^\s*down(?:\s+(\d+))?$/
466: previous_line = nil
467: if $1
468: lev = $1.to_i
469: else
470: lev = 1
471: end
472: frame_pos -= lev
473: if frame_pos < 0
474: frame_pos = 0
475: stdout.print "At stack bottom\n"
476: end
477: binding, binding_file, binding_line = @frames[frame_pos]
478: stdout.print format_frame(frame_pos)
479:
480: when /^\s*fin(?:ish)?$/
481: if frame_pos == @frames.size
482: stdout.print "\"finish\" not meaningful in the outermost frame.\n"
483: else
484: @finish_pos = @frames.size - frame_pos
485: frame_pos = 0
486: prompt = false
487: end
488:
489: when /^\s*cat(?:ch)?(?:\s+(.+))?$/
490: if $1
491: excn = $1
492: if excn == 'off'
493: @catch = nil
494: stdout.print "Clear catchpoint.\n"
495: else
496: @catch = excn
497: stdout.printf "Set catchpoint %s.\n", @catch
498: end
499: else
500: if @catch
501: stdout.printf "Catchpoint %s.\n", @catch
502: else
503: stdout.print "No catchpoint.\n"
504: end
505: end
506:
507: when /^\s*q(?:uit)?$/
508: input = readline("Really quit? (y/n) ", false)
509: if input == "y"
510: exit! # exit -> exit!: No graceful way to stop threads...
511: end
512:
513: when /^\s*v(?:ar)?\s+/
514: debug_variable_info($', binding)
515:
516: when /^\s*m(?:ethod)?\s+/
517: debug_method_info($', binding)
518:
519: when /^\s*th(?:read)?\s+/
520: if DEBUGGER__.debug_thread_info($', binding) == :cont
521: prompt = false
522: end
523:
524: when /^\s*pp\s+/
525: PP.pp(debug_eval($', binding), stdout)
526:
527: when /^\s*p\s+/
528: stdout.printf "%s\n", debug_eval($', binding).inspect
529:
530: when /^\s*r(?:estart)?$/
531: $debugger_restart.call
532:
533: when /^\s*h(?:elp)?$/
534: debug_print_help()
535:
536: else
537: v = debug_eval(input, binding)
538: stdout.printf "%s\n", v.inspect
539: end
540: end
541: end
542: MUTEX.unlock
543: resume_all
544: end
# File lib/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 lib/debug.rb, line 659
659: def debug_funcname(id)
660: if id.nil?
661: "toplevel"
662: else
663: id.id2name
664: end
665: end
# File lib/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 lib/debug.rb, line 546
546: def debug_print_help
547: 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] (<exception>|off) 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"
548: end
# File lib/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 lib/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 lib/debug.rb, line 602
602: def display_expression(exp, binding)
603: stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
604: end
# File lib/debug.rb, line 591
591: def display_expressions(binding)
592: n = 1
593: for d in display
594: if d[0]
595: stdout.printf "%d: ", n
596: display_expression(d[1], binding)
597: end
598: n += 1
599: end
600: end
# File lib/debug.rb, line 613
613: def display_frames(pos)
614: 0.upto(@frames.size - 1) do |n|
615: if n == pos
616: stdout.print "--> "
617: else
618: stdout.print " "
619: end
620: stdout.print format_frame(n)
621: end
622: end
# File lib/debug.rb, line 630
630: def display_list(b, e, file, line)
631: stdout.printf "[%d, %d] in %s\n", b, e, file
632: if lines = SCRIPT_LINES__[file] and lines != true
633: n = 0
634: b.upto(e) do |n|
635: if n > 0 && lines[n-1]
636: if n == line
637: stdout.printf "=> %d %s\n", n, lines[n-1].chomp
638: else
639: stdout.printf " %d %s\n", n, lines[n-1].chomp
640: end
641: end
642: end
643: else
644: stdout.printf "No sourcefile available for %s\n", file
645: end
646: end
# File lib/debug.rb, line 690
690: def excn_handle(file, line, id, binding)
691: if $!.class <= SystemExit
692: set_trace_func nil
693: exit
694: end
695:
696: if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
697: stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class
698: fs = @frames.size
699: tb = caller(0)[-fs..-1]
700: if tb
701: for i in tb
702: stdout.printf "\tfrom %s\n", i
703: end
704: end
705: suspend_all
706: debug_command(file, line, id, binding)
707: end
708: end
# File lib/debug.rb, line 624
624: def format_frame(pos)
625: bind, file, line, id = @frames[pos]
626: sprintf "#%d %s:%s%s\n", pos + 1, file, line,
627: (id ? ":in `#{id.id2name}'" : "")
628: end
# File lib/debug.rb, line 606
606: def frame_set_pos(file, line)
607: if @frames[0]
608: @frames[0][1] = file
609: @frames[0][2] = line
610: end
611: end
# File lib/debug.rb, line 648
648: def line_at(file, line)
649: lines = SCRIPT_LINES__[file]
650: if lines
651: return "\n" if lines == true
652: line = lines[line-1]
653: return "\n" unless line
654: return line
655: end
656: return "\n"
657: end
# File lib/debug.rb, line 68
68: def readline(prompt, hist)
69: Readline::readline(prompt, hist)
70: end
# File lib/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 lib/debug.rb, line 158
158: def set_last_thread(th)
159: DEBUGGER__.set_last_thread(th)
160: end
# File lib/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 lib/debug.rb, line 710
710: def trace_func(event, file, line, id, binding, klass)
711: Tracer.trace_func(event, file, line, id, binding, klass) if trace?
712: context(Thread.current).check_suspend
713: @file = file
714: @line = line
715: case event
716: when 'line'
717: frame_set_pos(file, line)
718: if !@no_step or @frames.size == @no_step
719: @stop_next -= 1
720: @stop_next = -1 if @stop_next < 0
721: elsif @frames.size < @no_step
722: @stop_next = 0 # break here before leaving...
723: else
724: # nothing to do. skipped.
725: end
726: if @stop_next == 0 or check_break_points(file, nil, line, binding, id)
727: @no_step = nil
728: suspend_all
729: debug_command(file, line, id, binding)
730: end
731:
732: when 'call'
733: @frames.unshift [binding, file, line, id]
734: if check_break_points(file, klass, id.id2name, binding, id)
735: suspend_all
736: debug_command(file, line, id, binding)
737: end
738:
739: when 'c-call'
740: frame_set_pos(file, line)
741:
742: when 'class'
743: @frames.unshift [binding, file, line, id]
744:
745: when 'return', 'end'
746: if @frames.size == @finish_pos
747: @stop_next = 1
748: @finish_pos = 0
749: end
750: @frames.shift
751:
752: when 'end'
753: @frames.shift
754:
755: when 'raise'
756: excn_handle(file, line, id, binding)
757:
758: end
759: @last_file = file
760: end