trepanning 1.93.35 → 2.15.33

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +491 -55
  3. data/LICENSE +1 -1
  4. data/NEWS +18 -14
  5. data/README.md +5 -22
  6. data/Rakefile +22 -1
  7. data/app/breakpoint.rb +5 -3
  8. data/app/core.rb +147 -179
  9. data/app/default.rb +47 -46
  10. data/app/file.rb +6 -7
  11. data/app/frame.rb +183 -176
  12. data/app/markdown.rb +2 -9
  13. data/app/options.rb +1 -1
  14. data/app/run.rb +71 -37
  15. data/interface/script.rb +8 -8
  16. data/io.rb +19 -20
  17. data/lib/trepanning.rb +292 -297
  18. data/processor.rb +332 -344
  19. data/processor/breakpoint.rb +98 -96
  20. data/processor/command/base/submgr.rb +9 -9
  21. data/processor/command/break.rb +40 -38
  22. data/processor/command/continue.rb +15 -10
  23. data/processor/command/debug.rb +6 -25
  24. data/processor/command/delete.rb +21 -12
  25. data/processor/command/directory.rb +15 -13
  26. data/processor/command/disable.rb +12 -9
  27. data/processor/command/disassemble.rb +80 -74
  28. data/processor/command/display.rb +15 -12
  29. data/processor/command/down.rb +8 -3
  30. data/processor/command/edit.rb +37 -23
  31. data/processor/command/enable.rb +11 -8
  32. data/processor/command/eval.rb +24 -22
  33. data/processor/command/finish.rb +50 -48
  34. data/processor/command/help.rb +1 -1
  35. data/processor/command/info_subcmd/breakpoints.rb +7 -7
  36. data/processor/command/info_subcmd/files.rb +195 -196
  37. data/processor/command/info_subcmd/frame.rb +7 -4
  38. data/processor/command/info_subcmd/locals.rb +29 -12
  39. data/processor/command/info_subcmd/program.rb +48 -39
  40. data/processor/command/info_subcmd/registers_subcmd/ep.rb +46 -0
  41. data/processor/command/info_subcmd/registers_subcmd/helper.rb +32 -35
  42. data/processor/command/info_subcmd/registers_subcmd/sp.rb +29 -23
  43. data/processor/command/info_subcmd/return.rb +28 -10
  44. data/processor/command/info_subcmd/variables_subcmd/class.rb +3 -3
  45. data/processor/command/info_subcmd/variables_subcmd/constants.rb +77 -0
  46. data/processor/command/info_subcmd/variables_subcmd/globals.rb +7 -7
  47. data/processor/command/info_subcmd/variables_subcmd/instance.rb +68 -22
  48. data/processor/command/info_subcmd/variables_subcmd/locals.rb +148 -67
  49. data/processor/command/list.rb +14 -8
  50. data/processor/command/macro.rb +1 -1
  51. data/processor/command/next.rb +1 -0
  52. data/processor/command/set_subcmd/auto.rb +3 -3
  53. data/processor/command/set_subcmd/different.rb +30 -29
  54. data/processor/command/set_subcmd/events.rb +74 -48
  55. data/processor/command/set_subcmd/max_subcmd/list.rb +12 -5
  56. data/processor/command/set_subcmd/max_subcmd/width.rb +28 -19
  57. data/processor/command/set_subcmd/register.rb +37 -0
  58. data/processor/command/set_subcmd/register_subcmd/pc.rb +67 -0
  59. data/processor/command/set_subcmd/register_subcmd/sp.rb +75 -0
  60. data/processor/command/set_subcmd/reload.rb +12 -10
  61. data/processor/command/set_subcmd/return.rb +68 -44
  62. data/processor/command/shell.rb +3 -2
  63. data/processor/command/show_subcmd/different.rb +17 -14
  64. data/processor/command/show_subcmd/events.rb +25 -25
  65. data/processor/default.rb +1 -1
  66. data/processor/eval.rb +14 -15
  67. data/processor/frame.rb +43 -36
  68. data/processor/help.rb +5 -5
  69. data/processor/hook.rb +26 -29
  70. data/processor/location.rb +54 -51
  71. data/processor/mock.rb +4 -3
  72. data/processor/running.rb +113 -103
  73. data/processor/validate.rb +401 -373
  74. data/test/data/debug.cmd +8 -0
  75. data/test/data/debug.right +13 -0
  76. data/test/data/debugger-stop.right +6 -4
  77. data/test/data/fname-with-blank.cmd +1 -1
  78. data/test/data/fname-with-blank.right +5 -0
  79. data/test/data/pc.cmd +8 -0
  80. data/test/data/pc.right +10 -0
  81. data/test/data/quit.right +3 -1
  82. data/test/data/trace.cmd +2 -2
  83. data/test/data/trace.right +41 -20
  84. data/test/example/assign.rb +6 -0
  85. data/test/functional/fn_helper.rb +11 -17
  86. data/test/functional/test-break-long.rb +15 -16
  87. data/test/functional/test-break.rb +6 -8
  88. data/test/functional/test-condition.rb +8 -10
  89. data/test/functional/test-debugger-call-bug.rb +21 -22
  90. data/test/functional/test-delete.rb +57 -59
  91. data/test/functional/test-eval.rb +101 -103
  92. data/test/functional/test-finish.rb +24 -33
  93. data/test/functional/test-immediate-step-bug.rb +6 -10
  94. data/test/functional/test-next.rb +64 -65
  95. data/test/functional/test-raise.rb +63 -64
  96. data/test/functional/test-recursive-bt.rb +81 -76
  97. data/test/functional/test-remap.rb +6 -7
  98. data/test/functional/test-return.rb +44 -38
  99. data/test/functional/test-step.rb +55 -53
  100. data/test/functional/test-stepbug.rb +6 -9
  101. data/test/functional/test-watchg.rb +40 -39
  102. data/test/integration/test-debug.rb +12 -0
  103. data/test/integration/test-debugger-stop.rb +7 -7
  104. data/test/integration/test-pc.rb +24 -0
  105. data/test/integration/test-trace.rb +1 -1
  106. data/test/unit/cmd-helper.rb +0 -1
  107. data/test/unit/test-app-brkpt.rb +21 -21
  108. data/test/unit/test-app-brkptmgr.rb +7 -8
  109. data/test/unit/test-app-display.rb +3 -4
  110. data/test/unit/test-app-frame.rb +4 -5
  111. data/test/unit/test-base-subsubcmd.rb +2 -2
  112. data/test/unit/test-cmd-break.rb +6 -6
  113. data/test/unit/test-cmd-endisable.rb +7 -6
  114. data/test/unit/test-cmd-parse_list_cmd.rb +24 -24
  115. data/test/unit/test-io-tcpserver.rb +39 -35
  116. data/test/unit/test-proc-default.rb +23 -22
  117. data/test/unit/test-proc-eval.rb +1 -2
  118. data/test/unit/test-proc-frame.rb +8 -9
  119. data/test/unit/test-proc-list.rb +1 -1
  120. data/test/unit/test-proc-location.rb +2 -2
  121. data/test/unit/test-proc-main.rb +10 -10
  122. data/test/unit/test-proc-validate.rb +11 -13
  123. data/test/unit/test-subcmd-help.rb +1 -2
  124. data/trepanning.gemspec +8 -13
  125. metadata +44 -95
  126. data/COPYING +0 -57
  127. data/data/custom_require.rb +0 -44
  128. data/data/perldb.bindings +0 -17
  129. data/data/prelude.rb +0 -38
  130. data/processor/command/info_subcmd/variables_subcmd/constant.rb +0 -41
  131. data/processor/command/raise.rb +0 -48
  132. data/processor/command/set_subcmd/pc.rb +0 -62
  133. data/processor/command/set_subcmd/sp.rb +0 -67
  134. data/processor/eventbuf.rb +0 -133
@@ -7,61 +7,62 @@ class Trepan
7
7
 
8
8
  # Default settings for a Trepan class object
9
9
  DEFAULT_SETTINGS = {
10
- :cmdproc_opts => {}, # Default Trepan::CmdProcessor settings
11
- :core_opts => {}, # Default Trepan::Core settings
12
- :delete_restore => true, # Delete restore profile after reading?
13
- :initial_dir => nil, # If --cd option was given, we save it here.
14
- :nx => false, # Don't run user startup file (e.g. .trepanrc)
10
+ :cmdproc_opts => {}, # Default Trepan::CmdProcessor settings
11
+ :core_opts => {}, # Default Trepan::Core settings
12
+ :delete_restore => true, # Delete restore profile after reading?
13
+ :initial_dir => nil, # If --cd option was given, we save it here.
14
+ :nx => false, # Don't run user startup file (e.g. .trepanrc)
15
+ :cmdloop_on_exit => true, # Stay in debugger after program finishes
15
16
 
16
- # Default values used only when 'server' or 'client'
17
- # (out-of-process debugging)
18
- :port => 1955,
19
- :post_mortem => false,
20
- :host => 'localhost',
17
+ # Default values used only when 'server' or 'client'
18
+ # (out-of-process debugging)
19
+ :port => 1955,
20
+ :post_mortem => false,
21
+ :host => 'localhost',
21
22
 
22
- :restart_argv => RubyVM::OS_ARGV,
23
- # Command run when "restart" is given.
24
- :server => false, # Out-of-process debugging?
25
- } unless defined?(DEFAULT_SETTINGS)
23
+ :restart_argv => RubyVM::OS_ARGV,
24
+ # Command run when "restart" is given.
25
+ :server => false, # Out-of-process debugging?
26
+ } unless defined?(DEFAULT_SETTINGS)
26
27
 
27
28
  # Default settings for Trepan run from the command line.
28
29
  DEFAULT_CMDLINE_SETTINGS = {
29
- :basename => false,
30
- :cmdfiles => [], # Initialization command files to run
31
- :client => false, # Attach to out-of-process program?
32
- :nx => false, # Don't run user startup file (e.g. .trepanrc)
33
- :output => nil,
34
- :port => DEFAULT_SETTINGS[:port],
35
- :host => DEFAULT_SETTINGS[:host],
36
- :server => false, # Out-of-process debugging?
37
- :readline => true, # Try to use GNU Readline?
38
- # Note that at most one of :server or :client can be true.
39
- } unless defined?(DEFAULT_CMDLINE_SETTINGS)
30
+ :basename => false,
31
+ :cmdfiles => [], # Initialization command files to run
32
+ :client => false, # Attach to out-of-process program?
33
+ :nx => false, # Don't run user startup file (e.g. .trepanrc)
34
+ :output => nil,
35
+ :port => DEFAULT_SETTINGS[:port],
36
+ :host => DEFAULT_SETTINGS[:host],
37
+ :server => false, # Out-of-process debugging?
38
+ :readline => true, # Try to use GNU Readline?
39
+ # Note that at most one of :server or :client can be true.
40
+ } unless defined?(DEFAULT_CMDLINE_SETTINGS)
40
41
 
41
42
  DEFAULT_DEBUG_STR_SETTINGS = {
42
- :core_opts => {
43
- :cmdproc_opts => {:different => true, :highlight => true}},
44
- :hide_stack => true,
45
- } unless defined?(DEFAULT_DEBUG_STR_SETTINGS)
43
+ :core_opts => {
44
+ :cmdproc_opts => {:different => true, :highlight => true}},
45
+ :hide_stack => true,
46
+ } unless defined?(DEFAULT_DEBUG_STR_SETTINGS)
46
47
 
47
- CMD_INITFILE_BASE =
48
- if RUBY_PLATFORM =~ /mswin/
49
- # Of course MS Windows has to be different
50
- HOME_DIR = (ENV['HOME'] ||
51
- ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
52
- 'trepan.ini'
53
- else
54
- HOME_DIR = ENV['HOME'].to_s
55
- '.trepanrc'
56
- end unless defined?(CMD_INITFILE_BASE)
57
- CMD_INITFILE = File.join(HOME_DIR, CMD_INITFILE_BASE) unless
58
- defined?(CMD_INITFILE)
48
+ CMD_INITFILE_BASE =
49
+ if RUBY_PLATFORM =~ /mswin/
50
+ # Of course MS Windows has to be different
51
+ HOME_DIR = (ENV['HOME'] ||
52
+ ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
53
+ 'trepan.ini'
54
+ else
55
+ HOME_DIR = ENV['HOME'].to_s
56
+ '.trepanrc'
57
+ end unless defined?(CMD_INITFILE_BASE)
58
+ CMD_INITFILE = File.join(HOME_DIR, CMD_INITFILE_BASE) unless
59
+ defined?(CMD_INITFILE)
59
60
  end
60
61
 
61
62
  if __FILE__ == $0
62
- # Show it:
63
- require 'pp'
64
- PP.pp(Trepan::DEFAULT_SETTINGS)
65
- puts '=' * 30
66
- PP.pp(Trepan::DEFAULT_CMDLINE_SETTINGS)
63
+ # Show it:
64
+ require 'pp'
65
+ PP.pp(Trepan::DEFAULT_SETTINGS)
66
+ puts '=' * 30
67
+ PP.pp(Trepan::DEFAULT_CMDLINE_SETTINGS)
67
68
  end
@@ -1,17 +1,16 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
3
  # Things related to file/module status
4
- require 'thread_frame'
5
4
  require_relative 'iseq'
6
5
 
7
- SCRIPT_ISEQS__ = {} unless
6
+ SCRIPT_ISEQS__ = {} unless
8
7
  defined?(SCRIPT_ISEQS__) && SCRIPT_ISEQS__.is_a?(Hash)
9
- ISEQS__ = {} unless
8
+ ISEQS__ = {} unless
10
9
  defined?(ISEQS__) && ISEQS__.is_a?(Hash)
11
10
 
12
11
  module Trepanning
13
12
  def file_match_pat(filename)
14
- prefix =
13
+ prefix =
15
14
  if filename[0..0] == File::SEPARATOR
16
15
  # An absolute filename has to match at the beginning and
17
16
  # the end.
@@ -30,7 +29,7 @@ module Trepanning
30
29
  match_block = Proc.new{|filename, iseq| filename =~ /^#{dirname}/}
31
30
  scripts = SCRIPT_ISEQS__.select(&match_block)
32
31
  SCRIPT_ISEQS__.delete_if(&match_block)
33
- match_block = Proc.new{|iseq|
32
+ match_block = Proc.new{|iseq|
34
33
  iseq.source_container[1] =~ /^#{dirname}/
35
34
  }
36
35
  rejected = {}
@@ -55,7 +54,7 @@ module Trepanning
55
54
  filename_pat = file_match_pat(filename)
56
55
  iseqs.select{|iseq| iseq.source_container[1] =~ /#{filename_pat}/}
57
56
  else
58
- return iseqs
57
+ return iseqs
59
58
  end
60
59
  end
61
60
 
@@ -85,7 +84,7 @@ if __FILE__ == $0
85
84
  SCRIPT_LINES__ = {}
86
85
  ARGV[0..-1] = ['noload']
87
86
  load(__FILE__)
88
- else
87
+ else
89
88
  load 'tmpdir.rb'
90
89
  tmpdir_dir = File.dirname(find_scripts('tmpdir.rb')[0])
91
90
  p tmpdir_dir
@@ -1,8 +1,8 @@
1
- # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
1
+ # Copyright (C) 2010-2011, 2015 Rocky Bernstein <rockyb@rubyforge.net>
2
2
  require_relative 'util'
3
3
 
4
4
  class Trepan
5
-
5
+
6
6
  # Call-Stack frame methods
7
7
  module Frame
8
8
 
@@ -22,48 +22,50 @@ class Trepan
22
22
  return '' unless iseq
23
23
  params = param_names(iseq, 0, iseq.argc-1, '')
24
24
  if iseq.arg_opts > 0
25
- opt_params = param_names(iseq, iseq.argc,
25
+ opt_params = param_names(iseq, iseq.argc,
26
26
  iseq.argc + iseq.arg_opts-2, '')
27
27
  opt_params[0] = "optional: #{opt_params[0]}" if delineate
28
28
  params += opt_params
29
29
  end
30
- params += param_names(iseq, iseq.arg_rest, iseq.arg_rest, '*') if
30
+ params += param_names(iseq, iseq.arg_rest, iseq.arg_rest, '*') if
31
31
  iseq.arg_rest != -1
32
32
  if iseq.arg_post_len > 0
33
33
  # Manditory arguments after optional ones - new in Ruby 1.9
34
- post_params = param_names(iseq, iseq.arg_post_start,
34
+ post_params = param_names(iseq, iseq.arg_post_start,
35
35
  iseq.post_start + iseq.arg_post_len, '')
36
36
  post_params[0] = "post: #{post_params[0]}" if delineate
37
37
  params += post_params
38
38
  end
39
- params += param_names(iseq, iseq.arg_block, iseq.arg_block, '&') if
39
+ params += param_names(iseq, iseq.arg_block, iseq.arg_block, '&') if
40
40
  iseq.arg_block != -1
41
41
 
42
42
  return params
43
43
  end
44
44
 
45
45
  def c_params(frame, maxstring=20)
46
- argc = frame.argc
47
- # FIXME should figure out why exception is raised.
48
- begin
49
- args =
50
- if 0 == argc
51
- ''
52
- elsif frame
53
- 1.upto(argc).map do
54
- |i|
55
- safe_repr(frame.sp(argc-i+3).inspect, 10)
56
- end.join(', ')
57
- else
46
+ argc = frame.argc
47
+ # FIXME should figure out why exception is raised.
48
+ begin
49
+ args =
50
+ if 0 == argc
51
+ ''
52
+ elsif frame
53
+ 1.upto(argc).map do
54
+ |i|
55
+ # FIXME: figure out why
56
+ # Trepan::Frame:Module throws an error
57
+ safe_repr(frame.sp(argc-i+3).inspect, 10) rescue ''
58
+ end.join(', ')
59
+ else
60
+ '??'
61
+ end
62
+ safe_repr(args, maxstring) rescue ''
63
+ rescue NotImplementedError
58
64
  '??'
59
- end
60
- safe_repr(args, maxstring)
61
- rescue NotImplementedError
62
- '??'
63
- end
65
+ end
64
66
  end
65
67
 
66
- # Return the eval string. We get this as the
68
+ # Return the eval string. We get this as the
67
69
  # parameter to the eval C call. A bit of checking is done
68
70
  # to make sure everything is okay:
69
71
  # - we have to be in an EVAL type frame which has an iseq
@@ -73,7 +75,7 @@ class Trepan
73
75
  return nil unless 'EVAL' == frame.type && frame.iseq
74
76
  prev = frame.prev
75
77
  return nil unless prev && 'CFUNC' == prev.type && 'eval' == prev.method
76
- retval = prev.sp 3
78
+ retval = prev.sp 3
77
79
  retval = $1 if retval =~ /^\(eval "(.+)"\)/
78
80
  retval
79
81
  end
@@ -83,84 +85,86 @@ class Trepan
83
85
  end
84
86
 
85
87
  def format_stack_call(frame, opts)
86
- # FIXME: prettify
87
- s = "#{frame.type}"
88
- s += if opts[:class]
89
- " #{opts[:class]}#"
90
- else
91
- begin
92
- obj = eval('self', frame.binding)
93
- rescue
94
- ''
88
+ # FIXME: prettify
89
+ s = "#{frame.type}"
90
+ # FIXME: Figure why frame.class can throw a NoMethodError
91
+ # on to_s.
92
+ s += if opts[:class]
93
+ " #{opts[:class]}#"
95
94
  else
96
- if obj
97
- " #{obj.class}#"
98
- else
99
- ''
100
- end
95
+ " #{frame.klass}#" rescue ''
101
96
  end
102
- end
103
- meth = frame.method
104
- if meth and frame.type != 'IFUNC'
105
- iseq = frame.iseq
106
- args = if 'CFUNC' == frame.type
107
- c_params(frame)
108
- elsif iseq
109
- all_param_names(iseq).join(', ')
110
- end
111
- s += meth
112
- if %w(CFUNC METHOD).member?(frame.type)
113
- s += "(#{args})"
114
- elsif %w(BLOCK LAMBDA TOP EVAL).member?(frame.type)
115
- s += " |#{args}|" unless args.nil? || args.empty?
116
- else
117
- s += "(#{all_param_names(iseq)})"
97
+ meth = frame.method
98
+ if meth and frame.type != 'IFUNC'
99
+ iseq = frame.iseq
100
+ args = if 'CFUNC' == frame.type
101
+ c_params(frame)
102
+ elsif iseq
103
+ all_param_names(iseq).join(', ')
104
+ end
105
+ s += meth
106
+ if %w(CFUNC METHOD).member?(frame.type)
107
+ s += "(#{args})"
108
+ elsif %w(BLOCK LAMBDA TOP EVAL).member?(frame.type)
109
+ s += " |#{args}|" unless args.nil? || args.empty?
110
+ else
111
+ s += "(#{all_param_names(iseq)})"
112
+ end
118
113
  end
119
- end
120
- s
121
- rescue ThreadFrameError
122
- 'invalid frame'
114
+ s
123
115
  end
124
116
 
125
117
  def format_stack_entry(frame, opts={})
126
- return 'invalid frame' if frame.invalid?
127
- s = format_stack_call(frame, opts)
128
- s += " in #{frame.source_container[0]} "
129
- s +=
130
- if (eval_str = eval_string(frame))
131
- safe_repr(eval_str.inspect, 15)
132
- else
133
- if 'file' == frame.source_container[0] &&
134
- opts[:basename]
135
- File.basename(frame.source_container[1])
136
- else
137
- frame.source_container[1]
138
- end
139
- end
118
+ return 'invalid frame' unless frame.valid?
119
+ container_type = frame.source_container[0]
120
+ s = format_stack_call(frame, opts)
121
+ s += " in #{container_type}"
122
+ sep = if opts[:maxwidth] && s.size > opts[:maxwidth]
123
+ "\n\t"
124
+ else
125
+ ' '
126
+ end
127
+ s +=
128
+ if (eval_str = eval_string(frame))
129
+ sep + safe_repr(eval_str.inspect, 15)
130
+ else
131
+ if 'file' == container_type && opts[:basename]
132
+ sep + File.basename(frame.source_container[1])
133
+ elsif 'binary' == container_type
134
+ ''
135
+ else
136
+ sep + frame.source_container[1]
137
+ end
138
+ end
140
139
  if frame.source_location
141
- s +=
142
- if opts[:maxwidth] && s.size > opts[:maxwidth]
143
- "\n\t"
144
- else
145
- ' '
146
- end
147
- if frame.source_location.size == 1
148
- s += "at line #{frame.source_location[0]}" if
149
- frame.source_location[0] != 0
150
- else
151
- s += " at lines #{frame.source_location}"
152
- end
140
+ loc = ''
141
+ loc +=
142
+ if container_type == 'binary'
143
+ "at address 0x%x" % frame.source_location[0]
144
+ elsif frame.source_location.size == 1
145
+ frame.source_location[0] != 0 ?
146
+ "at line #{frame.source_location[0]}" : ''
147
+ else
148
+ "at lines #{frame.source_location}"
149
+ end
150
+ s +=
151
+ if opts[:maxwidth] && s.size + loc.size > opts[:maxwidth]
152
+ "\n\t"
153
+ else
154
+ ' '
155
+ end
156
+ s += loc
153
157
  end
154
- s += ", pc: #{frame.pc_offset}" if
155
- frame.pc_offset > 0 && opts[:show_pc]
156
- return s
158
+ s += ", pc: #{frame.pc_offset}" if
159
+ frame.pc_offset > 0 && opts[:show_pc]
160
+ return s
157
161
  end
158
162
 
159
163
  # Return true if frame1 and frame2 are at the same place.
160
164
  # We use this for example in detecting tail recursion.
161
165
  def location_equal(frame1, frame2)
162
166
  frame1 && frame2 && frame1.source_location == frame2.source_location &&
163
- frame1.pc_offset == frame2.pc_offset &&
167
+ frame1.pc_offset == frame2.pc_offset &&
164
168
  frame1.source_container == frame2.source_container
165
169
  end
166
170
 
@@ -172,7 +176,7 @@ class Trepan
172
176
  end
173
177
 
174
178
  def param_names(iseq, start, stop, prefix='')
175
- start.upto(stop).map do |i|
179
+ start.upto(stop).map do |i|
176
180
  begin
177
181
  prefix + iseq.local_name(i)
178
182
  rescue
@@ -187,40 +191,41 @@ class Trepan
187
191
  end
188
192
 
189
193
  def print_stack_trace_from_to(from, to, frame, opts)
190
- last_frame = nil
191
- # TODO: handle indirect recursion.
192
- direct_recursion_count = 0
193
- from.upto(to) do |i|
194
- if location_equal(last_frame, frame)
195
- direct_recursion_count += 1
196
- else
197
- if direct_recursion_count > 0
198
- msg("... above line repeated #{direct_recursion_count} times")
199
- direct_recursion_count = 0
200
- end
201
- prefix = (i == opts[:current_pos]) ? '-->' : ' '
202
- prefix += ' #%d ' % [i]
203
- print_stack_entry(frame, i, prefix, opts)
194
+ last_frame = nil
195
+ # TODO: handle indirect recursion.
196
+ direct_recursion_count = 0
197
+ from.upto(to) do |i|
198
+ if location_equal(last_frame, frame)
199
+ direct_recursion_count += 1
200
+ else
201
+ if direct_recursion_count > 0
202
+ msg("... above line repeated #{direct_recursion_count} times")
203
+ direct_recursion_count = 0
204
+ end
205
+ prefix = (i == opts[:current_pos]) ? '-->' : ' '
206
+ prefix += ' #%d ' % [i]
207
+ print_stack_entry(frame, i, prefix, opts)
208
+ end
209
+ last_frame = frame
210
+ frame = frame.prev
204
211
  end
205
- last_frame = frame
206
- frame = frame.prev
207
- end
212
+ return last_frame
208
213
  end
209
214
 
210
215
  # Print `count' frame entries
211
216
  def print_stack_trace(frame, opts={})
212
- opts = DEFAULT_STACK_TRACE_SETTINGS.merge(opts)
213
- halfstack = (opts[:maxstack]+1) / 2
214
- n = frame.stack_size
215
- n = [n, opts[:count]].min if opts[:count]
216
- if n > (halfstack * 2)
217
- print_stack_trace_from_to(0, halfstack-1, frame, opts)
218
- msg "... %d levels ..." % (n - halfstack*2)
219
- print_stack_trace_from_to(n - halfstack, n-1, frame, opts)
220
- else
221
- print_stack_trace_from_to(0, n-1, frame, opts)
222
- end
223
- msg "(More stack frames follow...)" if n < frame.stack_size
217
+ opts = DEFAULT_STACK_TRACE_SETTINGS.merge(opts)
218
+ halfstack = (opts[:maxstack]+1) / 2
219
+ n = frame.stack_size
220
+ n = [n, opts[:count]].min if opts[:count]
221
+ if n > (halfstack * 2)
222
+ print_stack_trace_from_to(0, halfstack-1, frame, opts)
223
+ msg "... %d levels ..." % (n - halfstack*2)
224
+ last_frame = print_stack_trace_from_to(n - halfstack, n-1, frame, opts)
225
+ else
226
+ last_frame = print_stack_trace_from_to(0, n-1, frame, opts)
227
+ end
228
+ msg "(More stack frames follow...)" if last_frame.type != 'TOP'
224
229
  end
225
230
 
226
231
  def set_return_value(frame, event, value)
@@ -236,67 +241,69 @@ class Trepan
236
241
  end
237
242
 
238
243
  if __FILE__ == $0
239
- # Demo it.
240
- require 'thread_frame'
241
- include Trepan::Frame
242
- def msg(msg)
243
- puts msg
244
- end
245
- print_stack_trace(RubyVM::Frame.current, :basename => true)
246
- def foo
247
- puts '=' * 10
248
- print_stack_trace(RubyVM::Frame.current, :show_pc => true)
249
- end
250
- foo
244
+ # Demo it.
245
+ include Trepan::Frame
246
+ def msg(msg)
247
+ puts msg
248
+ end
249
+ width = (ENV['COLUMNS'] || `tput cols &2>/dev/null`).to_i rescue 80
250
+ opts = {:maxwidth => width}
251
+ print_stack_trace(RubyVM::Frame.get,
252
+ :basename => true, :maxwidth => width)
253
+ def foo(width)
254
+ puts '=' * 10
255
+ print_stack_trace(RubyVM::Frame.get,
256
+ :show_pc => true, :maxwidth => width)
257
+ end
258
+ foo(width)
251
259
 
252
- def bar(a, b, c)
253
- puts '=' * 10
254
- print_stack_trace(RubyVM::Frame.current,
255
- )
256
- end
257
- bar(1, 2, 3)
260
+ def bar(a, b, opts)
261
+ puts '=' * 10
262
+ print_stack_trace(RubyVM::Frame.get, opts)
263
+ end
264
+ bar(1, 2, opts)
258
265
 
259
- def baz(a, b, c=5)
260
- puts '=' * 10
261
- print_stack_trace(RubyVM::Frame.current)
262
- end
263
- baz(1, 2)
266
+ def baz(a, opts, c=5)
267
+ puts '=' * 10
268
+ print_stack_trace(RubyVM::Frame.get, opts)
269
+ end
270
+ baz(1, opts)
264
271
 
265
- def bat(a, b, &block)
266
- puts '=' * 10
267
- print_stack_trace(RubyVM::Frame.current)
268
- end
269
- bat(1, 2)
272
+ def bat(a, opts, &block)
273
+ puts '=' * 10
274
+ print_stack_trace(RubyVM::Frame.get, opts)
275
+ end
276
+ bat(1, opts)
270
277
 
271
- def babe(a, b, *rest)
272
- puts '=' * 10
273
- print_stack_trace(RubyVM::Frame.current)
274
- end
275
- babe(1, 2)
278
+ def babe(a, b, *rest)
279
+ puts '=' * 10
280
+ print_stack_trace(RubyVM::Frame.get)
281
+ end
282
+ babe(1, 2)
276
283
 
277
- puts '=' * 10
278
- x = lambda { |a,b| print_stack_trace(RubyVM::Frame::current) }
279
- x.call(1,2)
280
- puts '=' * 10
281
- x = Proc.new do |a|
282
- print_stack_trace(RubyVM::Frame::current)
283
- end
284
- x.call(1,2)
285
- class C # :nodoc
286
- def initialize(a)
287
- print_stack_trace(RubyVM::Frame::current)
284
+ puts '=' * 10
285
+ x = lambda { |a,b| print_stack_trace(RubyVM::Frame::get, opts) }
286
+ x.call(1,2)
287
+ puts '=' * 10
288
+ x = Proc.new do |a|
289
+ print_stack_trace(RubyVM::Frame::get, opts)
290
+ end
291
+ x.call(1,2)
292
+ class C # :nodoc
293
+ def initialize(opts)
294
+ print_stack_trace(RubyVM::Frame::get, opts)
295
+ end
296
+ end
297
+ puts '=' * 30
298
+ C.new(opts)
299
+ puts '=' * 30
300
+ eval("print_stack_trace(RubyVM::Frame.get, opts)")
301
+ puts '=' * 30
302
+ eval("eval('print_stack_trace(RubyVM::Frame.get, opts)')")
303
+ puts '=' * 30
304
+ eval("eval('print_stack_trace(RubyVM::Frame.get, :maxstack => 2)')")
305
+ puts '=' * 30
306
+ 1.upto(1) do |a; b|
307
+ print_stack_trace(RubyVM::Frame::get)
288
308
  end
289
- end
290
- puts '=' * 30
291
- C.new('Hi')
292
- puts '=' * 30
293
- eval("print_stack_trace(RubyVM::Frame.current)")
294
- puts '=' * 30
295
- eval("eval('print_stack_trace(RubyVM::Frame.current)')")
296
- puts '=' * 30
297
- eval("eval('print_stack_trace(RubyVM::Frame.current, :maxstack => 2)')")
298
- puts '=' * 30
299
- 1.times do |a; b|
300
- print_stack_trace(RubyVM::Frame::current)
301
- end
302
309
  end