trepanning 1.93.35 → 2.15.33
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +491 -55
- data/LICENSE +1 -1
- data/NEWS +18 -14
- data/README.md +5 -22
- data/Rakefile +22 -1
- data/app/breakpoint.rb +5 -3
- data/app/core.rb +147 -179
- data/app/default.rb +47 -46
- data/app/file.rb +6 -7
- data/app/frame.rb +183 -176
- data/app/markdown.rb +2 -9
- data/app/options.rb +1 -1
- data/app/run.rb +71 -37
- data/interface/script.rb +8 -8
- data/io.rb +19 -20
- data/lib/trepanning.rb +292 -297
- data/processor.rb +332 -344
- data/processor/breakpoint.rb +98 -96
- data/processor/command/base/submgr.rb +9 -9
- data/processor/command/break.rb +40 -38
- data/processor/command/continue.rb +15 -10
- data/processor/command/debug.rb +6 -25
- data/processor/command/delete.rb +21 -12
- data/processor/command/directory.rb +15 -13
- data/processor/command/disable.rb +12 -9
- data/processor/command/disassemble.rb +80 -74
- data/processor/command/display.rb +15 -12
- data/processor/command/down.rb +8 -3
- data/processor/command/edit.rb +37 -23
- data/processor/command/enable.rb +11 -8
- data/processor/command/eval.rb +24 -22
- data/processor/command/finish.rb +50 -48
- data/processor/command/help.rb +1 -1
- data/processor/command/info_subcmd/breakpoints.rb +7 -7
- data/processor/command/info_subcmd/files.rb +195 -196
- data/processor/command/info_subcmd/frame.rb +7 -4
- data/processor/command/info_subcmd/locals.rb +29 -12
- data/processor/command/info_subcmd/program.rb +48 -39
- data/processor/command/info_subcmd/registers_subcmd/ep.rb +46 -0
- data/processor/command/info_subcmd/registers_subcmd/helper.rb +32 -35
- data/processor/command/info_subcmd/registers_subcmd/sp.rb +29 -23
- data/processor/command/info_subcmd/return.rb +28 -10
- data/processor/command/info_subcmd/variables_subcmd/class.rb +3 -3
- data/processor/command/info_subcmd/variables_subcmd/constants.rb +77 -0
- data/processor/command/info_subcmd/variables_subcmd/globals.rb +7 -7
- data/processor/command/info_subcmd/variables_subcmd/instance.rb +68 -22
- data/processor/command/info_subcmd/variables_subcmd/locals.rb +148 -67
- data/processor/command/list.rb +14 -8
- data/processor/command/macro.rb +1 -1
- data/processor/command/next.rb +1 -0
- data/processor/command/set_subcmd/auto.rb +3 -3
- data/processor/command/set_subcmd/different.rb +30 -29
- data/processor/command/set_subcmd/events.rb +74 -48
- data/processor/command/set_subcmd/max_subcmd/list.rb +12 -5
- data/processor/command/set_subcmd/max_subcmd/width.rb +28 -19
- data/processor/command/set_subcmd/register.rb +37 -0
- data/processor/command/set_subcmd/register_subcmd/pc.rb +67 -0
- data/processor/command/set_subcmd/register_subcmd/sp.rb +75 -0
- data/processor/command/set_subcmd/reload.rb +12 -10
- data/processor/command/set_subcmd/return.rb +68 -44
- data/processor/command/shell.rb +3 -2
- data/processor/command/show_subcmd/different.rb +17 -14
- data/processor/command/show_subcmd/events.rb +25 -25
- data/processor/default.rb +1 -1
- data/processor/eval.rb +14 -15
- data/processor/frame.rb +43 -36
- data/processor/help.rb +5 -5
- data/processor/hook.rb +26 -29
- data/processor/location.rb +54 -51
- data/processor/mock.rb +4 -3
- data/processor/running.rb +113 -103
- data/processor/validate.rb +401 -373
- data/test/data/debug.cmd +8 -0
- data/test/data/debug.right +13 -0
- data/test/data/debugger-stop.right +6 -4
- data/test/data/fname-with-blank.cmd +1 -1
- data/test/data/fname-with-blank.right +5 -0
- data/test/data/pc.cmd +8 -0
- data/test/data/pc.right +10 -0
- data/test/data/quit.right +3 -1
- data/test/data/trace.cmd +2 -2
- data/test/data/trace.right +41 -20
- data/test/example/assign.rb +6 -0
- data/test/functional/fn_helper.rb +11 -17
- data/test/functional/test-break-long.rb +15 -16
- data/test/functional/test-break.rb +6 -8
- data/test/functional/test-condition.rb +8 -10
- data/test/functional/test-debugger-call-bug.rb +21 -22
- data/test/functional/test-delete.rb +57 -59
- data/test/functional/test-eval.rb +101 -103
- data/test/functional/test-finish.rb +24 -33
- data/test/functional/test-immediate-step-bug.rb +6 -10
- data/test/functional/test-next.rb +64 -65
- data/test/functional/test-raise.rb +63 -64
- data/test/functional/test-recursive-bt.rb +81 -76
- data/test/functional/test-remap.rb +6 -7
- data/test/functional/test-return.rb +44 -38
- data/test/functional/test-step.rb +55 -53
- data/test/functional/test-stepbug.rb +6 -9
- data/test/functional/test-watchg.rb +40 -39
- data/test/integration/test-debug.rb +12 -0
- data/test/integration/test-debugger-stop.rb +7 -7
- data/test/integration/test-pc.rb +24 -0
- data/test/integration/test-trace.rb +1 -1
- data/test/unit/cmd-helper.rb +0 -1
- data/test/unit/test-app-brkpt.rb +21 -21
- data/test/unit/test-app-brkptmgr.rb +7 -8
- data/test/unit/test-app-display.rb +3 -4
- data/test/unit/test-app-frame.rb +4 -5
- data/test/unit/test-base-subsubcmd.rb +2 -2
- data/test/unit/test-cmd-break.rb +6 -6
- data/test/unit/test-cmd-endisable.rb +7 -6
- data/test/unit/test-cmd-parse_list_cmd.rb +24 -24
- data/test/unit/test-io-tcpserver.rb +39 -35
- data/test/unit/test-proc-default.rb +23 -22
- data/test/unit/test-proc-eval.rb +1 -2
- data/test/unit/test-proc-frame.rb +8 -9
- data/test/unit/test-proc-list.rb +1 -1
- data/test/unit/test-proc-location.rb +2 -2
- data/test/unit/test-proc-main.rb +10 -10
- data/test/unit/test-proc-validate.rb +11 -13
- data/test/unit/test-subcmd-help.rb +1 -2
- data/trepanning.gemspec +8 -13
- metadata +44 -95
- data/COPYING +0 -57
- data/data/custom_require.rb +0 -44
- data/data/perldb.bindings +0 -17
- data/data/prelude.rb +0 -38
- data/processor/command/info_subcmd/variables_subcmd/constant.rb +0 -41
- data/processor/command/raise.rb +0 -48
- data/processor/command/set_subcmd/pc.rb +0 -62
- data/processor/command/set_subcmd/sp.rb +0 -67
- data/processor/eventbuf.rb +0 -133
data/app/default.rb
CHANGED
@@ -7,61 +7,62 @@ class Trepan
|
|
7
7
|
|
8
8
|
# Default settings for a Trepan class object
|
9
9
|
DEFAULT_SETTINGS = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
:core_opts => {
|
44
|
+
:cmdproc_opts => {:different => true, :highlight => true}},
|
45
|
+
:hide_stack => true,
|
46
|
+
} unless defined?(DEFAULT_DEBUG_STR_SETTINGS)
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
data/app/file.rb
CHANGED
@@ -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
|
data/app/frame.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Copyright (C) 2010,
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
97
|
-
" #{obj.class}#"
|
98
|
-
else
|
99
|
-
''
|
100
|
-
end
|
95
|
+
" #{frame.klass}#" rescue ''
|
101
96
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
120
|
-
s
|
121
|
-
rescue ThreadFrameError
|
122
|
-
'invalid frame'
|
114
|
+
s
|
123
115
|
end
|
124
116
|
|
125
117
|
def format_stack_entry(frame, opts={})
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
if
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
s +=
|
152
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
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
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
bat(1,
|
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
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|