trepanning 1.93.35 → 2.15.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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