trepanning 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/ChangeLog +354 -0
  2. data/NEWS +21 -0
  3. data/Rakefile +27 -20
  4. data/app/cmd_parse.kpeg +20 -4
  5. data/app/cmd_parse.rb +11 -10
  6. data/app/cmd_parser.rb +119 -55
  7. data/app/complete.rb +1 -0
  8. data/app/core.rb +3 -3
  9. data/app/disassemble.rb +13 -3
  10. data/app/file.rb +2 -1
  11. data/app/frame.rb +3 -1
  12. data/app/mock.rb +3 -0
  13. data/app/options.rb +48 -31
  14. data/app/util.rb +50 -0
  15. data/interface/base_intf.rb +4 -0
  16. data/interface/client.rb +4 -0
  17. data/interface/script.rb +1 -1
  18. data/interface/server.rb +4 -0
  19. data/interface/user.rb +5 -0
  20. data/io/input.rb +3 -2
  21. data/io/null_output.rb +7 -1
  22. data/processor/breakpoint.rb +3 -2
  23. data/processor/command/base/subcmd.rb +1 -1
  24. data/processor/command/base/submgr.rb +4 -1
  25. data/processor/command/base/subsubcmd.rb +2 -2
  26. data/processor/command/base/subsubmgr.rb +1 -1
  27. data/processor/command/break.rb +7 -3
  28. data/processor/command/complete.rb +1 -0
  29. data/processor/command/continue.rb +1 -1
  30. data/processor/command/disassemble.rb +1 -1
  31. data/processor/command/edit.rb +35 -14
  32. data/processor/command/enable.rb +5 -3
  33. data/processor/command/eval.rb +35 -14
  34. data/processor/command/exit.rb +2 -0
  35. data/processor/command/help.rb +0 -9
  36. data/processor/command/help/command.txt +37 -27
  37. data/processor/command/help/examples.txt +16 -0
  38. data/processor/command/help/suffixes.txt +17 -0
  39. data/processor/command/info.rb +1 -1
  40. data/processor/command/info_subcmd/args.rb +7 -13
  41. data/processor/command/info_subcmd/breakpoints.rb +8 -2
  42. data/processor/command/info_subcmd/frame.rb +2 -0
  43. data/processor/command/info_subcmd/globals.rb +63 -0
  44. data/processor/command/info_subcmd/iseq.rb +3 -1
  45. data/processor/command/info_subcmd/locals.rb +16 -15
  46. data/processor/command/{show_subcmd → info_subcmd}/macro.rb +7 -7
  47. data/processor/command/info_subcmd/program.rb +2 -0
  48. data/processor/command/info_subcmd/registers.rb +5 -1
  49. data/processor/command/info_subcmd/registers_subcmd/dfp.rb +2 -3
  50. data/processor/command/info_subcmd/registers_subcmd/helper.rb +8 -9
  51. data/processor/command/info_subcmd/registers_subcmd/lfp.rb +10 -5
  52. data/processor/command/info_subcmd/registers_subcmd/pc.rb +9 -4
  53. data/processor/command/info_subcmd/registers_subcmd/sp.rb +4 -5
  54. data/processor/command/info_subcmd/ruby.rb +3 -1
  55. data/processor/command/info_subcmd/source.rb +78 -0
  56. data/processor/command/info_subcmd/stack.rb +23 -0
  57. data/processor/command/kill.rb +4 -6
  58. data/processor/command/list.rb +118 -120
  59. data/processor/command/macro.rb +1 -1
  60. data/processor/command/parsetree.rb +56 -0
  61. data/processor/command/pp.rb +40 -0
  62. data/processor/command/pr.rb +1 -2
  63. data/processor/command/quit.rb +2 -1
  64. data/processor/command/set_subcmd/abbrev.rb +24 -0
  65. data/processor/command/set_subcmd/auto_subcmd/eval.rb +1 -2
  66. data/processor/command/set_subcmd/auto_subcmd/irb.rb +2 -3
  67. data/processor/command/set_subcmd/auto_subcmd/list.rb +2 -3
  68. data/processor/command/set_subcmd/highlight.rb +8 -2
  69. data/processor/command/set_subcmd/reload.rb +41 -0
  70. data/processor/command/set_subcmd/timer.rb +8 -18
  71. data/processor/command/set_subcmd/trace.rb +2 -2
  72. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +2 -2
  73. data/processor/command/set_subcmd/trace_subcmd/print.rb +3 -3
  74. data/processor/command/{irb.rb → shell.rb} +9 -6
  75. data/processor/command/show_subcmd/abbrev.rb +19 -0
  76. data/processor/command/show_subcmd/directories.rb +21 -0
  77. data/processor/command/show_subcmd/hidelevel.rb +1 -1
  78. data/processor/command/show_subcmd/highlight.rb +2 -1
  79. data/processor/command/show_subcmd/reload.rb +17 -0
  80. data/processor/command/show_subcmd/timer.rb +17 -0
  81. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +1 -1
  82. data/processor/command/source.rb +15 -14
  83. data/processor/command/tbreak.rb +20 -0
  84. data/processor/command/watchg.rb +114 -0
  85. data/processor/default.rb +43 -41
  86. data/processor/display.rb +3 -2
  87. data/processor/eval.rb +5 -3
  88. data/processor/eventbuf.rb +3 -2
  89. data/processor/frame.rb +12 -3
  90. data/processor/hook.rb +3 -2
  91. data/processor/load_cmds.rb +186 -179
  92. data/processor/location.rb +154 -159
  93. data/processor/main.rb +44 -16
  94. data/processor/mock.rb +0 -11
  95. data/processor/msg.rb +3 -1
  96. data/processor/running.rb +3 -2
  97. data/processor/validate.rb +25 -4
  98. data/processor/virtual.rb +32 -0
  99. data/test/data/debugger-stop.right +1 -0
  100. data/test/data/fname-with-blank.right +1 -0
  101. data/test/example/gcd.rb +1 -0
  102. data/test/functional/{test-trace-var.rb → test-watchg.rb} +15 -4
  103. data/test/unit/cmd-helper.rb +0 -3
  104. data/test/unit/test-app-cmd_parser.rb +2 -2
  105. data/test/unit/test-app-file.rb +1 -0
  106. data/test/unit/test-app-frame.rb +1 -1
  107. data/test/unit/test-app-util.rb +21 -0
  108. data/test/unit/test-base-cmd.rb +4 -6
  109. data/test/unit/test-base-subcmd.rb +1 -4
  110. data/test/unit/test-base-submgr.rb +1 -2
  111. data/test/unit/test-base-subsubcmd.rb +0 -4
  112. data/test/unit/test-cmd-edit.rb +33 -0
  113. data/test/unit/test-cmd-parse_list_cmd.rb +33 -0
  114. data/test/unit/test-completion.rb +1 -1
  115. data/test/unit/test-proc-frame.rb +4 -1
  116. data/test/unit/test-proc-load_cmds.rb +2 -1
  117. data/test/unit/test-proc-location.rb +9 -26
  118. data/test/unit/test-proc-main.rb +1 -4
  119. data/test/unit/test-proc-validate.rb +28 -18
  120. data/test/unit/test-subcmd-help.rb +0 -4
  121. data/trepanning.gemspec +1 -1
  122. metadata +27 -10
  123. data/processor/command/set_subcmd/trace_subcmd/var.rb +0 -57
@@ -3,7 +3,7 @@
3
3
  require_relative '../base/subcmd'
4
4
  require_relative '../../../app/complete'
5
5
 
6
- class Trepan::Subcommand::ShowMacro < Trepan::Subcommand
6
+ class Trepan::Subcommand::InfoMacro < Trepan::Subcommand
7
7
  unless defined?(HELP)
8
8
  Trepanning::Subcommand.set_name_prefix(__FILE__, self)
9
9
  HELP = <<-HELP
@@ -18,8 +18,8 @@ In the second form, all macro names and their definitions are show.
18
18
 
19
19
  In the last form the only definitions of the given macro names is shown.
20
20
  HELP
21
- SHORT_HELP = "Show defined macros"
22
- MIN_ABBREV = 'ma'.size
21
+ SHORT_HELP = "Info defined macros"
22
+ MIN_ABBREV = 'mac'.size
23
23
  end
24
24
 
25
25
  def complete(prefix)
@@ -40,11 +40,11 @@ In the last form the only definitions of the given macro names is shown.
40
40
  string = @proc.macros[macro_name][1]
41
41
  msg " #{@proc.ruby_format(string)}", {:unlimited => true}
42
42
  else
43
- errmsg "%s is not a defined macro" % macro_name
43
+ errmsg '%s is not a defined macro' % macro_name
44
44
  end
45
45
  end
46
46
  elsif @proc.macros.empty?
47
- msg "No macros defined."
47
+ msg 'No macros defined.'
48
48
  else
49
49
  msg columnize_commands(@proc.macros.keys.sort)
50
50
  end
@@ -54,8 +54,8 @@ end
54
54
 
55
55
  if __FILE__ == $0
56
56
  # Demo it.
57
- $0 = __FILE__ + 'notagain' # So we don't run this agin
57
+ $0 = __FILE__ + 'notagain' # So we don't run this again
58
58
  require_relative '../../mock'
59
- cmd = MockDebugger::sub_setup(Trepan::Subcommand::ShowMacro)
59
+ cmd = MockDebugger::sub_setup(Trepan::Subcommand::InfoMacro)
60
60
  cmd.run(cmd.prefix + %w(u foo))
61
61
  end
@@ -6,6 +6,8 @@ class Trepan::Subcommand::InfoProgram < Trepan::Subcommand
6
6
  unless defined?(HELP)
7
7
  Trepanning::Subcommand.set_name_prefix(__FILE__, self)
8
8
  HELP = 'Information about debugged program and its environment'
9
+ MIN_ARGS = 0
10
+ MAX_ARGS = 0
9
11
  MIN_ABBREV = 'pr'.size
10
12
  NEED_STACK = true
11
13
  end
@@ -46,7 +46,11 @@ info reg lfp # show lfp(0)
46
46
  key_name = PREFIX.join('') + subcmd_name
47
47
  remain_args = args[3..-1]
48
48
  if all_regs.member?(key_name)
49
- @subcmds.subcmds[key_name].run(remain_args)
49
+ subcmd = @subcmds.subcmds[key_name]
50
+ if @proc.ok_for_running(subcmd, subcmd.class.const_get('CMD'),
51
+ remain_args.size)
52
+ @subcmds.subcmds[key_name].run(remain_args)
53
+ end
50
54
  elsif unavailable_regs.member?(key_name)
51
55
  msg("info registers: %s can not be displayed for frame type %s." %
52
56
  [subcmd_name, @proc.frame.type])
@@ -5,16 +5,15 @@ require_relative 'helper'
5
5
 
6
6
  class Trepan::Subcommand::InfoRegistersDfp < Trepan::SubSubcommand
7
7
  unless defined?(HELP)
8
+ Trepanning::SubSubcommand.set_name_prefix(__FILE__, self)
8
9
  HELP = 'Show the value of the VM dynamic frame pointer (DFP)'
9
10
  MIN_ABBREV = 'df'.size
10
- NAME = File.basename(__FILE__, '.rb')
11
11
  NEED_STACK = true
12
- PREFIX = %W(info registers #{NAME})
13
12
  end
14
13
 
15
14
  include Registers
16
15
  def run(args)
17
- register_array_index(PREFIX[-1], args)
16
+ register_array_index(PREFIX[-1], args[0])
18
17
  end
19
18
  end
20
19
 
@@ -1,18 +1,17 @@
1
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
2
  module Registers
3
- def register_array_index(name, args, max_value=nil)
4
- if args.size == 0
3
+ def register_array_index(name, arg, max_value=nil)
4
+ if !arg or arg.empty?
5
5
  # Form is: "info xx" which means "info xx 0"
6
6
  lookup_pos = position = 0
7
7
  else
8
- position_str = args[0]
9
8
  opts = {
10
9
  :msg_on_error =>
11
- "The 'info registers %s' command argument must eval to an integer. Got: %s" % [name, position_str],
12
- # :min_value => 0,
13
- :max_value => max_value
10
+ "The 'info registers %s' command argument must eval to an integer. Got: %s" % [name, arg],
11
+ :min_value => -10,
12
+ :max_value => max_value + 10
14
13
  }
15
- position = @proc.get_an_int(position_str, opts)
14
+ position = @proc.get_an_int(arg, opts)
16
15
  return nil unless position
17
16
  end
18
17
  lookup_pos =
@@ -28,7 +27,7 @@ module Registers
28
27
  # to do, possibly in the Ruby 1.9 interpeter, we'll handle
29
28
  # this here. It is also conceivable to handle this in
30
29
  # thread_frame's sp handling.
31
- position + 2
30
+ position + 3
32
31
  else
33
32
  position
34
33
  end
@@ -1,21 +1,26 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
3
  require_relative '../../base/subsubcmd'
4
4
  require_relative 'helper'
5
5
 
6
6
  class Trepan::Subcommand::InfoRegistersLfp < Trepan::SubSubcommand
7
7
  unless defined?(HELP)
8
- HELP = 'Show the value of the VM local frame pointer (LFP).
8
+ Trepanning::SubSubcommand.set_name_prefix(__FILE__, self)
9
+ HELP = <<EOH
10
+ #{CMD} NUMBER
9
11
 
12
+ Show the value of the VM local frame pointer (LFP).
10
13
  When a local variable is defined for the first time, this stack
11
14
  is pushed and the value for local variable is assigned to this stack entry.
12
15
 
13
16
  See also "info register sp".'
17
+ EOH
14
18
 
15
19
  MIN_ABBREV = 'lf'.size
16
- NAME = File.basename(__FILE__, '.rb')
20
+ MIN_ARGS = 1
21
+ MAX_ARGS = 1
17
22
  NEED_STACK = true
18
- PREFIX = %w(info registers lfp)
23
+ SHORT_HELP = "Show the value of the VM local frame pointer (LFP)."
19
24
  end
20
25
 
21
26
  include Registers
@@ -25,7 +30,7 @@ See also "info register sp".'
25
30
  msg "local_name not available for C function"
26
31
  else
27
32
  iseq = frame.iseq
28
- index = register_array_index(PREFIX[-1], args, iseq.local_size-1)
33
+ index = register_array_index(PREFIX[-1], args[0], iseq.local_size-1)
29
34
  msg("local_name(%d)=%s" % [index, iseq.local_name(index)]) if index
30
35
  end
31
36
  end
@@ -1,19 +1,24 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
3
  require_relative '../../base/subsubcmd'
4
4
 
5
5
  class Trepan::SubSubcommand::InfoRegistersPc < Trepan::SubSubcommand
6
6
  unless defined?(HELP)
7
- HELP = 'Show the value of the VM program counter (PC).
7
+ Trepanning::SubSubcommand.set_name_prefix(__FILE__, self)
8
+ HELP = <<EOH
9
+ #{CMD}
8
10
 
11
+ Show the value of the VM program counter (PC).
9
12
  The VM program is an offset into the instruction sequence for the next
10
13
  VM instruction in the sequence to be executed.
11
14
 
12
15
  See also "info disassemble" and "info registers".'
16
+ EOH
13
17
  MIN_ABBREV = 'pc'.size
14
- NAME = File.basename(__FILE__, '.rb')
15
18
  NEED_STACK = true
16
- PREFIX = %W(info registers #{NAME})
19
+ MIN_ARGS = 0
20
+ MAX_ARGS = 0
21
+ SHORT_HELP = 'Show the value of the VM program counter (PC).'
17
22
  end
18
23
 
19
24
  def run(args)
@@ -1,14 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
3
  require_relative '../../base/subsubcmd'
4
4
  require_relative 'helper'
5
5
 
6
6
  class Trepan::Subcommand::InfoRegistersSp < Trepan::SubSubcommand
7
7
  unless defined?(HELP)
8
- NAME = File.basename(__FILE__, '.rb')
8
+ Trepanning::SubSubcommand.set_name_prefix(__FILE__, self)
9
9
  HELP = <<EOH
10
- usage:
11
- info register #{NAME} [NUMBER NUMBER ...|size]
10
+ #{CMD} [NUMBER NUMBER ...|size]
12
11
 
13
12
  With no arguments, all SP values for the current frame of the debugged
14
13
  program are shown. If a number is given, then the entry at that
@@ -26,7 +25,7 @@ EOH
26
25
 
27
26
  MIN_ABBREV = 'sp'.size
28
27
  NEED_STACK = true
29
- PREFIX = %W(info registers #{NAME})
28
+ SHORT_HELP = "Show value(s) of the VM stack pointer (SP)."
30
29
  end
31
30
 
32
31
  include Registers
@@ -15,8 +15,10 @@ See also constants: RUBY_DESCRIPTION, RUBY_VERSION, and RUBY_RELEASE_DATE."
15
15
  EOH
16
16
  MIN_ABBREV = 'ru'.size
17
17
  NEED_STACK = false
18
+ MIN_ARGS = 0
19
+ MAX_ARGS = 0
18
20
  SHORT_HELP = 'Ruby version information'
19
- end
21
+ end
20
22
 
21
23
  # def parse_options(args) # :nodoc
22
24
  # options = {}
@@ -0,0 +1,78 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require 'pp'
4
+ require 'linecache'
5
+ require 'columnize'
6
+ require_relative '../base/subcmd'
7
+ require_relative '../../../app/file'
8
+ require_relative '../../../app/complete'
9
+
10
+ class Trepan::Subcommand::InfoSource < Trepan::Subcommand
11
+ unless defined?(HELP)
12
+ Trepanning::Subcommand.set_name_prefix(__FILE__, self)
13
+ DEFAULT_FILE_ARGS = %w(size mtime sha1)
14
+
15
+ HELP = <<-EOH
16
+ #{CMD}
17
+
18
+ Show information about the current source file.
19
+ EOH
20
+ MAX_ARGS = 0
21
+ MIN_ABBREV = 'so'.size # Note we have "info frame"
22
+ NEED_STACK = true
23
+ end
24
+
25
+ # completion %w(all brkpts iseq sha1 size stat)
26
+
27
+ include Trepanning
28
+
29
+ # Get file information
30
+ def run(args)
31
+ if not @proc.frame
32
+ errmsg('No frame - no default file.')
33
+ return false
34
+ end
35
+ frame_file = @proc.frame.source_container[1]
36
+ filename = LineCache::map_file(frame_file) || File.expand_path(frame_file)
37
+ canonic_name = @proc.canonic_file(filename)
38
+ canonic_name = LineCache::map_file(canonic_name) || canonic_name
39
+ m = filename
40
+ if LineCache::cached?(canonic_name)
41
+ m += ' is cached in debugger'
42
+ if canonic_name != filename
43
+ m += (' as:\n ' + canonic_name)
44
+ end
45
+ m += '.'
46
+ msg(m)
47
+ end
48
+ max_line = LineCache::size(canonic_name)
49
+ msg 'File has %d lines.' % max_line if max_line
50
+ msg('SHA1 is %s.' % LineCache::sha1(canonic_name))
51
+ msg('Possible breakpoint line numbers:')
52
+ lines = LineCache.trace_line_numbers(canonic_name)
53
+ fmt_lines = columnize_numbers(lines)
54
+ msg(fmt_lines)
55
+ if SCRIPT_ISEQS__.member?(canonic_name)
56
+ msg("File contains instruction sequences:")
57
+ SCRIPT_ISEQS__[canonic_name].each do |iseq|
58
+ msg("\t%s %s" % [iseq, iseq.name.inspect])
59
+ end
60
+ else
61
+ msg("Instruction sequences not recorded; there may be some, though.")
62
+ end
63
+ msg("Stat info:\n\t%s" % LineCache::stat(canonic_name).pretty_inspect)
64
+ end
65
+ end
66
+
67
+ if __FILE__ == $0
68
+ if !(ARGV.size == 1 && ARGV[0] == 'noload')
69
+ ISEQS__ = {}
70
+ SCRIPT_ISEQS__ = {}
71
+ ARGV[0..-1] = ['noload']
72
+ load(__FILE__)
73
+ else
74
+ require_relative '../../mock'
75
+ cmd = MockDebugger::sub_setup(Trepan::Subcommand::InfoSource, false)
76
+ cmd.run(cmd.prefix)
77
+ end
78
+ end
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative '../base/subcmd'
4
+
5
+ class Trepan::Subcommand::InfoStack < Trepan::Subcommand
6
+ unless defined?(HELP)
7
+ Trepanning::Subcommand.set_name_prefix(__FILE__, self)
8
+ HELP = 'Same thing as "backtrace"'
9
+ MIN_ABBREV = 'st'.size
10
+ NEED_STACK = true
11
+ end
12
+
13
+ def run(args)
14
+ @proc.commands['backtrace'].run(['backtrace'] + args[2..-1])
15
+ end
16
+ end
17
+
18
+ if __FILE__ == $0
19
+ # Demo it.
20
+ require_relative '../../mock'
21
+ cmd = MockDebugger::sub_setup(Trepan::Subcommand::InfoStack, false)
22
+ cmd.run(cmd.prefix)
23
+ end
@@ -50,18 +50,16 @@ Examples:
50
50
  errmsg("Signal name '#{sig}' is not a signal I know about.\n")
51
51
  return false
52
52
  end
53
- if 'KILL' == sig || Signal['KILL'] == sig
54
- @proc.intf.finalize
55
- end
56
53
  else
57
- if not (unconditional || confirm('Really quit?', false))
54
+ if unconditional || confirm('Really quit?', false)
55
+ sig = 'KILL'
56
+ else
58
57
  msg('Kill not confirmed.')
59
58
  return
60
- else
61
- sig = 'KILL'
62
59
  end
63
60
  end
64
61
  begin
62
+ @proc.intf.finalize if 'KILL' == sig || Signal['KILL'] == sig
65
63
  Process.kill(sig, Process.pid)
66
64
  rescue Errno::ESRCH
67
65
  errmsg "Unable to send kill #{sig} to process #{Process.pid}"
@@ -2,6 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
  require 'linecache'
4
4
  require_relative 'base/cmd'
5
+ require_relative '../../app/cmd_parse'
5
6
 
6
7
  class Trepan::Command::ListCommand < Trepan::Command
7
8
  unless defined?(HELP)
@@ -49,11 +50,11 @@ just something that evaluates to a positive integer.
49
50
  Some examples:
50
51
 
51
52
  #{NAME} 5 # List centered around line 5
52
- #{NAME} 4+1 # Same as above.
53
+ #{NAME} @5 # List lines centered around bytecode offset 5.
53
54
  #{NAME} 5> # List starting at line 5
54
55
  #{NAME} foo.rb:5 # List centered around line 5 of foo.rb
55
56
  #{NAME} foo.rb 5 # Same as above.
56
- #{NAME} foo.rb:5> # List starting around line 5 of foo.rb
57
+ #{NAME}> foo.rb:5 # List starting around line 5 of foo.rb
57
58
  #{NAME} foo.rb 5 6 # list lines 5 and 6 of foo.rb
58
59
  #{NAME} foo.rb 5 2 # Same as above, since 2 < 5.
59
60
  #{NAME} foo.rb:5 2 # Same as above
@@ -63,7 +64,7 @@ Some examples:
63
64
  # if . > 3. Otherwise we list from . to 3.
64
65
  #{NAME} - # List lines previous to those just shown
65
66
 
66
- The output of the #{NAME} command give a line number, and some status
67
+ The output of the #{NAME} command gives a line number, and some status
67
68
  information about the line and the text of the line. Here is some
68
69
  hypothetical #{NAME} output modeled roughly around line 251 of one
69
70
  version of this code:
@@ -86,25 +87,19 @@ disabled.
86
87
  SHORT_HELP = 'List source code'
87
88
  end
88
89
 
90
+ include Trepan::CmdParser
91
+
89
92
  # If last is less than first, assume last is a count rather than an
90
93
  # end line number.
91
94
  def adjust_last(first, last)
92
95
  last < first ? first + last - 1 : last
93
96
  end
94
97
 
95
- # What a f*cking mess. Necessitated I suppose because we want to
96
- # allow somewhat flexible parsing with either module names, files or none
97
- # and optional line counts or end-line numbers.
98
-
99
- # Parses arguments for the "list" command and returns the tuple:
100
- # filename, start, last
101
- # or sets these to nil if there was some problem.
102
- def parse_list_cmd(args, listsize, center_correction)
103
-
98
+ def frame_filename
104
99
  frame = @proc.frame
105
100
 
106
101
  container = @proc.frame_container(frame, false)
107
-
102
+
108
103
  # FIXME: put into a helper routine
109
104
  # See also duplicate code in print_location
110
105
  if container[0] != 'file'
@@ -115,84 +110,74 @@ disabled.
115
110
  end
116
111
  container = try_container if try_container[0] == 'file'
117
112
  end
118
-
119
- filename = container[1]
120
-
121
- last = nil
122
- if args.empty? and not frame
123
- errmsg("No Ruby program loaded.")
124
- return nil, nil, nil
125
- end
126
113
 
127
- if args.size > 0
128
- if args[0] == '-'
129
- return no_frame_msg unless @proc.line_no
130
- first = [1, @proc.line_no - 2*listsize - 1].max
131
- elsif args[0] == '.'
132
- return no_frame_msg unless @proc.line_no
133
- if args.size == 2
134
- opts = {
135
- :msg_on_error =>
136
- "#{NAME} command last or count parameter expected, " +
137
- 'got: %s.' % args[2]
138
- }
139
- second = @proc.get_an_int(args[1], opts)
140
- return nil, nil, nil unless second
141
- first = @proc.frame_line
142
- last = adjust_last(first, second)
143
- else
144
- first = [1, @proc.frame_line - center_correction].max
145
- end
114
+ return container[1]
115
+ end
146
116
 
147
- else
148
- modfunc, container, first = @proc.parse_position(args[0])
149
- if first == nil and container == nil
150
- # error should have been shown previously
151
- return nil, nil, nil
152
- end
153
- if args.size == 1
154
- first = 1 if !first and modfunc
155
- first = [1, first - center_correction].max
156
- elsif args.size == 2 or (args.size == 3 and modfunc)
157
- opts = {
158
- :msg_on_error =>
159
- "#{NAME} command starting line expected, got %s." % args[-1]
160
- }
161
- last = @proc.get_an_int(args[1], opts)
162
- return nil, nil, nil unless last
163
- if modfunc
164
- if first
165
- first = last
166
- if args.size == 3 and modfunc
167
- opts[:msg_on_error] =
168
- ("#{NAME} command last or count parameter expected, " +
169
- 'got: %s.' % args[2])
170
- last = @proc.get_an_int(args[2], opts)
171
- return nil, nil, nil unless last
172
- end
173
- end
117
+
118
+ # What a f*cking mess. Necessitated I suppose because we want to
119
+ # allow somewhat flexible parsing with either module names, files or none
120
+ # and optional line counts or end-line numbers.
121
+
122
+ # Parses arguments for the "list" command and returns the tuple:
123
+ # filename, start, last
124
+ # or sets these to nil if there was some problem.
125
+ def parse_list_cmd(arg_str, listsize, center_correction)
126
+
127
+ iseq = nil
128
+ if arg_str.empty?
129
+ filename = frame_filename
130
+ first = [1, @proc.frame_line - center_correction].max
131
+ else
132
+ list_cmd_parse = parse_list(arg_str,
133
+ :file_exists_proc => @proc.file_exists_proc)
134
+ last = list_cmd_parse.num
135
+ position = list_cmd_parse.position
136
+
137
+ if position.is_a?(String)
138
+ if position == '-'
139
+ return no_frame_msg unless @proc.line_no
140
+ first = [1, @proc.line_no - 2*listsize - 1].max
141
+ elsif position == '.'
142
+ return no_frame_msg unless @proc.line_no
143
+ if (second = list_cmd_parse.num)
144
+ first = @proc.frame_line
145
+ last = adjust_last(first, second)
146
+ else
147
+ first = [1, @proc.frame_line - center_correction].max
148
+ last = first + listsize - 1
174
149
  end
175
- last = adjust_last(first, last)
176
- elsif not modfunc
177
- errmsg('At most 2 parameters allowed when no module' +
178
- ' name is found/given. Saw: %d parameters' % args.size)
179
- return nil, nil, nil
150
+ end
151
+ filename = frame_filename
152
+ else
153
+ meth, filename, offset, offset_type = @proc.parse_position(position)
154
+ iseq = meth.iseq if meth
155
+ return unless filename
156
+ if offset_type == :line
157
+ first = offset
158
+ elsif meth
159
+ iseq, first, vm_offset =
160
+ @proc.position_to_line_and_offset(meth.iseq, filename,
161
+ position, offset_type)
162
+ return [nil] * 3 unless first
163
+ elsif !offset
164
+ # Have just a filename. Go with line 1
165
+ first = 1
180
166
  else
181
- errmsg(('At most 3 parameters allowed when a module' +
182
- ' name is given. Saw: %d parameters') % args.size)
183
- return nil, nil, nil
167
+ errmsg "Dunno what to do here"
168
+ return [nil] * 3
184
169
  end
185
170
  end
186
- elsif !@proc.line_no and @proc.frame
187
- first = [1, @proc.frame_line - center_correction].max
171
+ end
172
+
173
+ if last
174
+ last = adjust_last(first, last)
188
175
  else
189
- first = [1, @proc.line_no - center_correction].max
176
+ first = [1, first - center_correction].max
177
+ last = first + listsize - 1 unless last
190
178
  end
191
- last = first + listsize - 1 unless last
192
-
193
- LineCache::cache(container[1]) unless
194
- 'file' != container[0] || LineCache::cached?(container[1])
195
- return container, first, last
179
+ LineCache::cache(filename) unless LineCache::cached?(filename)
180
+ return iseq, filename, first, last
196
181
  end
197
182
 
198
183
  def no_frame_msg
@@ -201,6 +186,10 @@ disabled.
201
186
  end
202
187
 
203
188
  def run(args)
189
+ if args.empty? and not frame
190
+ errmsg("No Ruby program loaded.")
191
+ return
192
+ end
204
193
  listsize = settings[:maxlist]
205
194
  center_correction =
206
195
  if args[0][-1..-1] == '>'
@@ -209,22 +198,22 @@ disabled.
209
198
  (listsize-1) / 2
210
199
  end
211
200
 
212
- container, first, last =
213
- parse_list_cmd(args[1..-1], listsize, center_correction)
214
- frame = @proc.frame
215
- return unless container
201
+ iseq, filename, first, last =
202
+ parse_list_cmd(@proc.cmd_argstr, listsize, center_correction)
203
+ return unless filename
204
+ container = iseq ? iseq.source_container : ['file', filename]
216
205
  breaklist = @proc.brkpts.line_breaks(container)
217
206
 
218
207
  # We now have range information. Do the listing.
219
- max_line = LineCache::size(container[1])
208
+ max_line = LineCache::size(filename)
220
209
  unless max_line
221
- errmsg('File "%s" not found.' % container[1])
210
+ errmsg('File "%s" not found.' % filename)
222
211
  return
223
212
  end
224
213
 
225
214
  if first > max_line
226
215
  errmsg('Bad line range [%d...%d]; file "%s" has only %d lines' %
227
- [first, last, container[1], max_line])
216
+ [first, last, filename, max_line])
228
217
  return
229
218
  end
230
219
 
@@ -235,11 +224,12 @@ disabled.
235
224
 
236
225
  begin
237
226
  opts = {
238
- :reload_on_change => @proc.reload_on_change,
227
+ :reload_on_change => settings[:reload],
239
228
  :output => settings[:highlight]
240
229
  }
230
+ frame = @proc.frame
241
231
  first.upto(last).each do |lineno|
242
- line = LineCache::getline(container[1], lineno, opts)
232
+ line = LineCache::getline(filename, lineno, opts)
243
233
  unless line
244
234
  msg('[EOF]')
245
235
  break
@@ -256,7 +246,7 @@ disabled.
256
246
  ' '
257
247
  end
258
248
  s += (frame && lineno == @proc.frame_line &&
259
- container == frame.source_container) ? '->' : a_pad
249
+ filename == frame.source_container[1]) ? '->' : a_pad
260
250
  msg(s + "\t" + line, {:unlimited => true})
261
251
  @proc.line_no = lineno
262
252
  end
@@ -278,69 +268,77 @@ if __FILE__ == $0
278
268
  require_relative '../frame'
279
269
  dbgr, cmd = MockDebugger::setup
280
270
  cmd.proc.send('frame_initialize')
281
- LineCache::cache(__FILE__)
282
- cmd.run([cmd.name])
283
- cmd.run([cmd.name, __FILE__ + ':10'])
284
271
 
285
272
  def run_cmd(cmd, args)
273
+ cmd.proc.instance_variable_set('@cmd_argstr', args[1..-1].join(' '))
274
+ cmd.run(args)
275
+ end
276
+
277
+ LineCache::cache(__FILE__)
278
+ run_cmd(cmd, [cmd.name])
279
+ run_cmd(cmd, [cmd.name, __FILE__ + ':10'])
280
+
281
+ def run_cmd2(cmd, args)
286
282
  seps = '--' * 10
287
283
  puts "%s %s %s" % [seps, args.join(' '), seps]
288
- cmd.run(args)
284
+ run_cmd(cmd,args)
289
285
  end
290
286
 
291
287
 
292
288
  load 'tmpdir.rb'
293
- run_cmd(cmd, %w(list tmpdir.rb 10))
294
- run_cmd(cmd, %w(list tmpdir.rb))
289
+ run_cmd2(cmd, %w(list tmpdir.rb 10))
290
+ run_cmd2(cmd, %w(list tmpdir.rb))
295
291
 
296
292
  # cmd.proc.frame = sys._getframe()
297
293
  # cmd.proc.setup()
298
- # cmd.run(['list'])
294
+ # run_cmd2(['list'])
299
295
 
300
- run_cmd(cmd, %w(list .))
301
- run_cmd(cmd, %w(list 30))
296
+ run_cmd2(cmd, %w(list .))
297
+ run_cmd2(cmd, %w(list 30))
302
298
 
303
- # cmd.run(['list', '9+1'])
299
+ # run_cmd2(['list', '9+1'])
304
300
 
305
- run_cmd(cmd, %w(list> 10))
306
- run_cmd(cmd, %w(list 3000))
307
- run_cmd(cmd, %w(list run_cmd))
301
+ run_cmd2(cmd, %w(list> 10))
302
+ run_cmd2(cmd, %w(list 3000))
303
+ run_cmd2(cmd, %w(list run_cmd2))
308
304
 
309
305
  p = Proc.new do
310
306
  |x,y| x + y
311
307
  end
312
- run_cmd(cmd, %w(list p))
308
+ require 'thread_frame'
309
+ tf = RubyVM::ThreadFrame.current
310
+ cmd.proc.frame_setup(tf)
311
+ run_cmd2(cmd, %w(list p))
313
312
 
314
313
  # Function from a file found via an instruction sequence
315
- run_cmd(cmd, %w(list Columnize.columnize))
314
+ run_cmd2(cmd, %w(list Columnize.columnize))
316
315
 
317
316
  # Use Class/method name. 15 isn't in the function - should this be okay?
318
- run_cmd(cmd, %W(#{cmd.name} Columnize.columnize 15))
317
+ run_cmd2(cmd, %W(#{cmd.name} Columnize.columnize 15))
319
318
 
320
319
  # Start line and count, since 3 < 30
321
- run_cmd(cmd, %W(#{cmd.name} Columnize.columnize 30 3))
320
+ run_cmd2(cmd, %W(#{cmd.name} Columnize.columnize 30 3))
322
321
 
323
322
  # Start line finish line
324
- run_cmd(cmd, %W(#{cmd.name} Columnize.columnize 40 50))
323
+ run_cmd2(cmd, %W(#{cmd.name} Columnize.columnize 40 50))
325
324
 
326
325
  # puts '--' * 10
327
- # cmd.run([cmd.name, os.path.abspath(__file__)+':3', '4'])
326
+ # run_cmd2([cmd.name, os.path.abspath(__file__)+':3', '4'])
328
327
  # puts '--' * 10
329
- # cmd.run([cmd.name, os.path.abspath(__file__)+':3', '12-10'])
330
- # cmd.run([cmd.name, 'os.path:5'])
328
+ # run_cmd2([cmd.name, os.path.abspath(__file__)+':3', '12-10'])
329
+ # run_cmd2([cmd.name, 'os.path:5'])
331
330
 
332
- require 'thread_frame'
333
- tf = RubyVM::ThreadFrame.current
334
- cmd.proc.frame_setup(tf)
335
331
  brkpt_cmd = cmd.proc.instance_variable_get('@commands')['break']
336
332
  brkpt_cmd.run(['break'])
337
333
  line = __LINE__
338
- run_cmd(cmd, [cmd.name, __LINE__.to_s])
334
+ run_cmd2(cmd, [cmd.name, __LINE__.to_s])
339
335
 
340
336
  disable_cmd = cmd.proc.instance_variable_get('@commands')['disable']
341
337
  disable_cmd.run(['disable', '1'])
342
338
 
343
- run_cmd(cmd, [cmd.name, line.to_s])
344
- run_cmd(cmd, %W(#{cmd.name} run_cmd))
339
+ run_cmd2(cmd, [cmd.name, line.to_s])
340
+ run_cmd2(cmd, %W(#{cmd.name} run_cmd2))
341
+ run_cmd2(cmd, %W(#{cmd.name} run_cmd2))
342
+ run_cmd2(cmd, %W(#{cmd.name} @713))
345
343
  end
346
344
  end