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