trepanning 0.0.4
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.
- data/ChangeLog +4422 -0
- data/LICENSE +23 -0
- data/NEWS +12 -0
- data/README.textile +56 -0
- data/Rakefile +171 -0
- data/app/Makefile +7 -0
- data/app/breakpoint.rb +157 -0
- data/app/brkptmgr.rb +149 -0
- data/app/condition.rb +22 -0
- data/app/core.rb +203 -0
- data/app/default.rb +54 -0
- data/app/disassemble.rb +61 -0
- data/app/display.rb +148 -0
- data/app/file.rb +135 -0
- data/app/frame.rb +275 -0
- data/app/irb.rb +112 -0
- data/app/mock.rb +22 -0
- data/app/options.rb +122 -0
- data/app/run.rb +95 -0
- data/app/thread.rb +24 -0
- data/app/util.rb +32 -0
- data/bin/trepan +63 -0
- data/data/custom_require.rb +44 -0
- data/data/irbrc +55 -0
- data/data/prelude.rb +38 -0
- data/interface/base_intf.rb +95 -0
- data/interface/script.rb +103 -0
- data/interface/user.rb +90 -0
- data/io/base_io.rb +92 -0
- data/io/input.rb +111 -0
- data/io/string_array.rb +155 -0
- data/lib/Makefile +7 -0
- data/lib/trepanning.rb +277 -0
- data/processor/breakpoint.rb +108 -0
- data/processor/command/alias.rb +55 -0
- data/processor/command/backtrace.rb +95 -0
- data/processor/command/base/cmd.rb +97 -0
- data/processor/command/base/subcmd.rb +207 -0
- data/processor/command/base/submgr.rb +178 -0
- data/processor/command/base/subsubcmd.rb +102 -0
- data/processor/command/base/subsubmgr.rb +182 -0
- data/processor/command/break.rb +85 -0
- data/processor/command/condition.rb +64 -0
- data/processor/command/continue.rb +61 -0
- data/processor/command/debug.rb +85 -0
- data/processor/command/delete.rb +54 -0
- data/processor/command/directory.rb +43 -0
- data/processor/command/disable.rb +65 -0
- data/processor/command/disassemble.rb +103 -0
- data/processor/command/display.rb +81 -0
- data/processor/command/down.rb +56 -0
- data/processor/command/enable.rb +43 -0
- data/processor/command/exit.rb +54 -0
- data/processor/command/finish.rb +81 -0
- data/processor/command/frame.rb +117 -0
- data/processor/command/help.rb +146 -0
- data/processor/command/info.rb +28 -0
- data/processor/command/info_subcmd/args.rb +56 -0
- data/processor/command/info_subcmd/breakpoints.rb +162 -0
- data/processor/command/info_subcmd/file.rb +162 -0
- data/processor/command/info_subcmd/frame.rb +39 -0
- data/processor/command/info_subcmd/iseq.rb +83 -0
- data/processor/command/info_subcmd/locals.rb +88 -0
- data/processor/command/info_subcmd/program.rb +54 -0
- data/processor/command/info_subcmd/registers.rb +72 -0
- data/processor/command/info_subcmd/registers_subcmd/dfp.rb +38 -0
- data/processor/command/info_subcmd/registers_subcmd/helper.rb +40 -0
- data/processor/command/info_subcmd/registers_subcmd/lfp.rb +54 -0
- data/processor/command/info_subcmd/registers_subcmd/pc.rb +44 -0
- data/processor/command/info_subcmd/registers_subcmd/sp.rb +75 -0
- data/processor/command/info_subcmd/return.rb +40 -0
- data/processor/command/info_subcmd/thread.rb +106 -0
- data/processor/command/irb.rb +106 -0
- data/processor/command/kill.rb +58 -0
- data/processor/command/list.rb +327 -0
- data/processor/command/macro.rb +65 -0
- data/processor/command/next.rb +89 -0
- data/processor/command/nocache.rb +33 -0
- data/processor/command/print.rb +37 -0
- data/processor/command/ps.rb +40 -0
- data/processor/command/quit.rb +62 -0
- data/processor/command/raise.rb +47 -0
- data/processor/command/reload.rb +28 -0
- data/processor/command/reload_subcmd/command.rb +34 -0
- data/processor/command/restart.rb +57 -0
- data/processor/command/save.rb +60 -0
- data/processor/command/set.rb +47 -0
- data/processor/command/set_subcmd/auto.rb +27 -0
- data/processor/command/set_subcmd/auto_subcmd/eval.rb +67 -0
- data/processor/command/set_subcmd/auto_subcmd/irb.rb +49 -0
- data/processor/command/set_subcmd/auto_subcmd/list.rb +51 -0
- data/processor/command/set_subcmd/basename.rb +39 -0
- data/processor/command/set_subcmd/debug.rb +27 -0
- data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +49 -0
- data/processor/command/set_subcmd/debug_subcmd/except.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/macro.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/skip.rb +35 -0
- data/processor/command/set_subcmd/debug_subcmd/stack.rb +45 -0
- data/processor/command/set_subcmd/different.rb +67 -0
- data/processor/command/set_subcmd/events.rb +71 -0
- data/processor/command/set_subcmd/max.rb +35 -0
- data/processor/command/set_subcmd/max_subcmd/list.rb +50 -0
- data/processor/command/set_subcmd/max_subcmd/stack.rb +60 -0
- data/processor/command/set_subcmd/max_subcmd/string.rb +53 -0
- data/processor/command/set_subcmd/max_subcmd/width.rb +50 -0
- data/processor/command/set_subcmd/return.rb +66 -0
- data/processor/command/set_subcmd/sp.rb +62 -0
- data/processor/command/set_subcmd/substitute.rb +25 -0
- data/processor/command/set_subcmd/substitute_subcmd/eval.rb +98 -0
- data/processor/command/set_subcmd/substitute_subcmd/path.rb +55 -0
- data/processor/command/set_subcmd/substitute_subcmd/string.rb +72 -0
- data/processor/command/set_subcmd/timer.rb +68 -0
- data/processor/command/set_subcmd/trace.rb +43 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +56 -0
- data/processor/command/set_subcmd/trace_subcmd/print.rb +54 -0
- data/processor/command/set_subcmd/trace_subcmd/var.rb +61 -0
- data/processor/command/show.rb +27 -0
- data/processor/command/show_subcmd/alias.rb +50 -0
- data/processor/command/show_subcmd/args.rb +50 -0
- data/processor/command/show_subcmd/auto.rb +27 -0
- data/processor/command/show_subcmd/auto_subcmd/eval.rb +38 -0
- data/processor/command/show_subcmd/auto_subcmd/irb.rb +34 -0
- data/processor/command/show_subcmd/auto_subcmd/list.rb +36 -0
- data/processor/command/show_subcmd/basename.rb +28 -0
- data/processor/command/show_subcmd/debug.rb +27 -0
- data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +31 -0
- data/processor/command/show_subcmd/debug_subcmd/except.rb +33 -0
- data/processor/command/show_subcmd/debug_subcmd/macro.rb +32 -0
- data/processor/command/show_subcmd/debug_subcmd/skip.rb +33 -0
- data/processor/command/show_subcmd/debug_subcmd/stack.rb +32 -0
- data/processor/command/show_subcmd/different.rb +37 -0
- data/processor/command/show_subcmd/events.rb +40 -0
- data/processor/command/show_subcmd/macro.rb +45 -0
- data/processor/command/show_subcmd/max.rb +31 -0
- data/processor/command/show_subcmd/max_subcmd/list.rb +39 -0
- data/processor/command/show_subcmd/max_subcmd/stack.rb +35 -0
- data/processor/command/show_subcmd/max_subcmd/string.rb +41 -0
- data/processor/command/show_subcmd/max_subcmd/width.rb +36 -0
- data/processor/command/show_subcmd/trace.rb +29 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +84 -0
- data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
- data/processor/command/source.rb +74 -0
- data/processor/command/step.rb +139 -0
- data/processor/command/stepi.rb +63 -0
- data/processor/command/unalias.rb +44 -0
- data/processor/command/undisplay.rb +63 -0
- data/processor/command/up.rb +92 -0
- data/processor/default.rb +45 -0
- data/processor/display.rb +17 -0
- data/processor/eval.rb +88 -0
- data/processor/eventbuf.rb +131 -0
- data/processor/frame.rb +230 -0
- data/processor/help.rb +72 -0
- data/processor/hook.rb +128 -0
- data/processor/load_cmds.rb +102 -0
- data/processor/location.rb +126 -0
- data/processor/main.rb +364 -0
- data/processor/mock.rb +100 -0
- data/processor/msg.rb +26 -0
- data/processor/running.rb +170 -0
- data/processor/subcmd.rb +159 -0
- data/processor/validate.rb +395 -0
- data/test/example/fname with blank.rb +1 -0
- data/test/example/gcd-xx.rb +18 -0
- data/test/example/gcd.rb +19 -0
- data/test/example/gcd1.rb +24 -0
- data/test/example/null.rb +1 -0
- data/test/example/thread1.rb +3 -0
- data/test/functional/fn_helper.rb +119 -0
- data/test/functional/test-break.rb +87 -0
- data/test/functional/test-condition.rb +59 -0
- data/test/functional/test-debugger-call-bug.rb +31 -0
- data/test/functional/test-delete.rb +71 -0
- data/test/functional/test-finish.rb +44 -0
- data/test/functional/test-immediate-step-bug.rb +35 -0
- data/test/functional/test-next.rb +77 -0
- data/test/functional/test-raise.rb +73 -0
- data/test/functional/test-return.rb +100 -0
- data/test/functional/test-step.rb +274 -0
- data/test/functional/test-stepbug.rb +40 -0
- data/test/functional/test-trace-var.rb +40 -0
- data/test/functional/tmp/b1.rb +5 -0
- data/test/functional/tmp/s1.rb +9 -0
- data/test/functional/tmp/t2.rb +6 -0
- data/test/integration/file-diff.rb +88 -0
- data/test/integration/helper.rb +52 -0
- data/test/integration/test-fname-with-blank.rb +11 -0
- data/test/integration/test-quit.rb +11 -0
- data/test/integration/try-test-enable.rb +11 -0
- data/test/unit/cmd-helper.rb +44 -0
- data/test/unit/test-app-brkpt.rb +30 -0
- data/test/unit/test-app-brkptmgr.rb +56 -0
- data/test/unit/test-app-disassemble.rb +60 -0
- data/test/unit/test-app-file.rb +46 -0
- data/test/unit/test-app-frame.rb +49 -0
- data/test/unit/test-app-options.rb +60 -0
- data/test/unit/test-app-run.rb +19 -0
- data/test/unit/test-app-thread.rb +25 -0
- data/test/unit/test-app-util.rb +17 -0
- data/test/unit/test-base-subcmd.rb +59 -0
- data/test/unit/test-bin-trepan.rb +48 -0
- data/test/unit/test-cmd-alias.rb +50 -0
- data/test/unit/test-cmd-break.rb +80 -0
- data/test/unit/test-cmd-endisable.rb +59 -0
- data/test/unit/test-cmd-help.rb +100 -0
- data/test/unit/test-cmd-kill.rb +47 -0
- data/test/unit/test-cmd-quit.rb +26 -0
- data/test/unit/test-cmd-step.rb +45 -0
- data/test/unit/test-intf-user.rb +45 -0
- data/test/unit/test-io-input.rb +26 -0
- data/test/unit/test-proc-eval.rb +26 -0
- data/test/unit/test-proc-frame.rb +77 -0
- data/test/unit/test-proc-help.rb +15 -0
- data/test/unit/test-proc-hook.rb +29 -0
- data/test/unit/test-proc-load_cmds.rb +40 -0
- data/test/unit/test-proc-main.rb +99 -0
- data/test/unit/test-proc-validate.rb +90 -0
- data/test/unit/test-subcmd-help.rb +48 -0
- metadata +358 -0
data/app/core.rb
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
3
|
+
require 'thread_frame'
|
|
4
|
+
require 'trace'
|
|
5
|
+
# require_relative '../../rb-trace/app/trace'
|
|
6
|
+
require_relative '../processor/main'
|
|
7
|
+
class Trepan
|
|
8
|
+
# This class contains the Trepan core routines, such as an event
|
|
9
|
+
# processor which is responsible of handling what to do when an event is
|
|
10
|
+
# triggered.
|
|
11
|
+
#
|
|
12
|
+
# See also 'rdbgr' the top-level Trepan class and command-line routine
|
|
13
|
+
# which ultimately will call this.
|
|
14
|
+
|
|
15
|
+
class Core
|
|
16
|
+
attr_accessor :async_events # bitmask of asyncronous events - used all
|
|
17
|
+
# the time
|
|
18
|
+
attr_reader :dbgr # Trepan instance
|
|
19
|
+
attr_reader :event # String - event which triggering event
|
|
20
|
+
# processor
|
|
21
|
+
attr_reader :event_proc # Proc of method event_processor
|
|
22
|
+
attr_accessor :exception # Return exception to pass back. A 'raise'
|
|
23
|
+
# command can set this.
|
|
24
|
+
attr_reader :frame # ThreadFrame instance
|
|
25
|
+
attr_reader :hook_arg # 'arg' passed from trace hook
|
|
26
|
+
attr_accessor :mutex # mutex to lock out other threads from
|
|
27
|
+
# entering debugger while we are in it.
|
|
28
|
+
attr_accessor :processor # Trepan::CmdProc instance
|
|
29
|
+
attr_reader :settings # Hash of things you can configure
|
|
30
|
+
attr_accessor :step_count # Fixnum. Negative means no tracing,
|
|
31
|
+
# 0 means stop on next event, 1 means
|
|
32
|
+
# ignore one event. Step events gives the
|
|
33
|
+
# kind of things to count as a step.
|
|
34
|
+
attr_accessor :step_events # bitmask of events - used only when
|
|
35
|
+
# we are stepping
|
|
36
|
+
attr_accessor :unmaskable_events
|
|
37
|
+
|
|
38
|
+
include Trace
|
|
39
|
+
|
|
40
|
+
unless defined?(CORE_DEFAULT_SETTINGS)
|
|
41
|
+
# Synchronous events
|
|
42
|
+
STEPPING_EVENT_MASK =
|
|
43
|
+
LINE_EVENT_MASK | CLASS_EVENT_MASK | CALL_EVENT_MASK |
|
|
44
|
+
RETURN_EVENT_MASK | C_CALL_EVENT_MASK | C_RETURN_EVENT_MASK |
|
|
45
|
+
INSN_EVENT_MASK | BRKPT_EVENT_MASK
|
|
46
|
+
|
|
47
|
+
ASYNC_EVENT_MASK =
|
|
48
|
+
RAISE_EVENT_MASK | VM_EVENT_MASK | SWITCH_EVENT_MASK
|
|
49
|
+
|
|
50
|
+
CORE_DEFAULT_SETTINGS = {
|
|
51
|
+
:cmdproc_opts => {},
|
|
52
|
+
:debug_core_events => false,
|
|
53
|
+
:hook_name => :event_processor, # or :old_event_processor
|
|
54
|
+
:step_count => 0, # Stop at next event
|
|
55
|
+
:async_events => ASYNC_EVENT_MASK,
|
|
56
|
+
|
|
57
|
+
# FIXME:
|
|
58
|
+
# Somewhere inside the VM we allow I guess nested tracing which is messing
|
|
59
|
+
# up ThreadFrame pointers and information. When this is fixed we can do the below.
|
|
60
|
+
# Until then we need to at least remove C calls and returns and possibly other
|
|
61
|
+
# events as well.
|
|
62
|
+
# :step_events =>
|
|
63
|
+
# (DEFAULT_EVENT_MASK | INSN_EVENT_MASK)
|
|
64
|
+
|
|
65
|
+
:step_events =>
|
|
66
|
+
(DEFAULT_EVENT_MASK | INSN_EVENT_MASK) &
|
|
67
|
+
~(C_CALL_EVENT_MASK | C_RETURN_EVENT_MASK)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def initialize(debugger, settings={})
|
|
73
|
+
@dbgr = debugger
|
|
74
|
+
@exception = nil
|
|
75
|
+
@mutex = Mutex.new
|
|
76
|
+
@settings = CORE_DEFAULT_SETTINGS.merge(settings)
|
|
77
|
+
|
|
78
|
+
@step_count = @settings[:step_count]
|
|
79
|
+
@step_events = @settings[:step_events]
|
|
80
|
+
@async_events = @settings[:async_events]
|
|
81
|
+
@debug_events = @settings[:debug_core_events]
|
|
82
|
+
|
|
83
|
+
hook_name = @settings[:hook_name]
|
|
84
|
+
@event_proc = self.method(hook_name).to_proc
|
|
85
|
+
@processor = CmdProcessor.new(self, @settings[:cmdproc_opts])
|
|
86
|
+
@unmaskable_events = %w(brkpt raise switch vm)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def step_events_list
|
|
90
|
+
if 0 == @step_events
|
|
91
|
+
return nil
|
|
92
|
+
else
|
|
93
|
+
Trace.bitmask2events(@step_events).join(', ')
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# A trace-hook processor with the interface a trace hook should have.
|
|
98
|
+
def event_processor(event, frame, arg=nil)
|
|
99
|
+
|
|
100
|
+
return_exception = nil
|
|
101
|
+
# FIXME: check for breakpoints or other unmaskable events.
|
|
102
|
+
# For now there are none.
|
|
103
|
+
|
|
104
|
+
@mutex.synchronize do
|
|
105
|
+
@frame = frame
|
|
106
|
+
while @frame.type == 'IFUNC'
|
|
107
|
+
@frame = @frame.prev
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if @step_count > 0
|
|
111
|
+
@step_count -= 1
|
|
112
|
+
break
|
|
113
|
+
elsif @step_count < 0 && ! @unmaskable_events.member?(event)
|
|
114
|
+
break
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
@event = event
|
|
118
|
+
@hook_arg = arg
|
|
119
|
+
|
|
120
|
+
### debug:
|
|
121
|
+
### puts "#{frame.source_container[1]}:#{frame.source_location[0]}:in `#{frame.method}' #{event}" # if %w(line).member?(event)
|
|
122
|
+
@processor.process_commands(@frame)
|
|
123
|
+
|
|
124
|
+
# FIXME: There should be a Trace.event_mask which should return the first
|
|
125
|
+
# mask that matches the given trace hook.
|
|
126
|
+
if @step_count < 0
|
|
127
|
+
# If we are continuing, no need to stop at stepping events.
|
|
128
|
+
Trace.event_masks[0] &= ~STEPPING_EVENT_MASK
|
|
129
|
+
else
|
|
130
|
+
# Set to trace only those events we are interested in.
|
|
131
|
+
|
|
132
|
+
# Don't step/trace into Ruby routines called from here in the code
|
|
133
|
+
# below (e.g. "trace_hooks").
|
|
134
|
+
step_count_save = step_count
|
|
135
|
+
@step_count = -1
|
|
136
|
+
|
|
137
|
+
unless @event_proc == dbgr.trace_filter.hook_proc
|
|
138
|
+
dbgr.trace_filter.add_trace_func(@event_proc)
|
|
139
|
+
## debug: p '+++1', @event_proc, dbgr.trace_filter.hook_proc
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# FIXME: this doesn't work. Bug in rb-trace?
|
|
143
|
+
# Trace.event_masks[0] = @step_events | @async_events
|
|
144
|
+
RubyVM::TraceHook::trace_hooks[0].event_mask =
|
|
145
|
+
@step_events | @async_events
|
|
146
|
+
@step_count = step_count_save
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Nil out variables just in case...
|
|
150
|
+
|
|
151
|
+
return_exception = @exception
|
|
152
|
+
@frame = @event = @arg = @exception = nil
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
return return_exception
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# A Ruby 1.8-style event processor. We don't use file, line, id, bind.
|
|
159
|
+
def old_event_processor(event, file, line, id, bind, klass)
|
|
160
|
+
event_processor(event, RubyVM::ThreadFrame.current.prev)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Call this from inside the program you want to get a synchronous
|
|
164
|
+
# call to the debugger. set prev_count to the number of levels
|
|
165
|
+
# *before* the caller you want to skip.
|
|
166
|
+
def debugger(prev_count=0)
|
|
167
|
+
while @frame && @frame.type == 'IFUNC'
|
|
168
|
+
@frame = @frame.prev
|
|
169
|
+
end
|
|
170
|
+
frame = RubyVM::ThreadFrame.current.prev(prev_count+1)
|
|
171
|
+
@step_count = 0 # Make event processor stop
|
|
172
|
+
event_processor('debugger-call', frame)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# A trace-hook processor for 'trace var'
|
|
176
|
+
def trace_var_processor(val)
|
|
177
|
+
frame = RubyVM::ThreadFrame.current.prev
|
|
178
|
+
if 'CFUNC' == frame.type
|
|
179
|
+
# Don't need the C call that got us here.
|
|
180
|
+
prev = frame.prev
|
|
181
|
+
frame = frame.prev if prev
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Stop future tracing into the debugger
|
|
185
|
+
Thread.current.tracing = true
|
|
186
|
+
|
|
187
|
+
@step_count = 0 # Make event processor stop
|
|
188
|
+
event_processor('trace-var', frame)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
if __FILE__ == $0
|
|
194
|
+
require_relative '../lib/trepanning'
|
|
195
|
+
dbg = Trepan.new()
|
|
196
|
+
if ARGV.size > 0
|
|
197
|
+
def foo(dbg)
|
|
198
|
+
p 'foo here'
|
|
199
|
+
dbg.debugger(:immediate=>true)
|
|
200
|
+
end
|
|
201
|
+
foo(dbg)
|
|
202
|
+
end
|
|
203
|
+
end
|
data/app/default.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# A place for the default settings
|
|
3
|
+
# This could be put elsewhere but it is expected that this will grow
|
|
4
|
+
# get quite large.
|
|
5
|
+
module Trepanning
|
|
6
|
+
|
|
7
|
+
# I am not sure if we need to sets of hashes, but we'll start out
|
|
8
|
+
# that way.
|
|
9
|
+
|
|
10
|
+
# Default settings for a Trepan class object
|
|
11
|
+
DEFAULT_SETTINGS = {
|
|
12
|
+
:cmdproc_opts => {}, # Default Trepan::CmdProcessor settings
|
|
13
|
+
:core_opts => {}, # Default Trepan::Core settings
|
|
14
|
+
:delete_restore => true, # Delete restore profile after reading?
|
|
15
|
+
:initial_dir => nil, # Current directory run when "restart" is given
|
|
16
|
+
:nx => false, # Don't run user startup file (e.g. .rbdbgrc)
|
|
17
|
+
:restart_argv => [], # Command run when "restart" is given
|
|
18
|
+
:restore_profile => nil # Profile used to set/restore debugger state
|
|
19
|
+
} unless defined?(DEFAULT_SETTINGS)
|
|
20
|
+
|
|
21
|
+
# Default settings for Trepan run from the command line.
|
|
22
|
+
DEFAULT_CMDLINE_SETTINGS = {
|
|
23
|
+
:cmdfiles => [], # Initialization command files to run
|
|
24
|
+
:nx => false, # Don't run user startup file (e.g. .rbdbgrc)
|
|
25
|
+
:output => nil,
|
|
26
|
+
} unless defined?(DEFAULT_CMDLINE_SETTINGS)
|
|
27
|
+
|
|
28
|
+
DEFAULT_DEBUG_STR_SETTINGS = {
|
|
29
|
+
:core_opts => {
|
|
30
|
+
:cmdproc_opts => {:different => false}},
|
|
31
|
+
:hide_stack => true,
|
|
32
|
+
} unless defined?(DEFAULT_DEBUG_STR_SETTINGS)
|
|
33
|
+
|
|
34
|
+
CMD_INITFILE_BASE =
|
|
35
|
+
if RUBY_PLATFORM =~ /mswin/
|
|
36
|
+
# Of course MS Windows has to be different
|
|
37
|
+
HOME_DIR = (ENV['HOME'] ||
|
|
38
|
+
ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
|
|
39
|
+
'trepan.ini'
|
|
40
|
+
else
|
|
41
|
+
HOME_DIR = ENV['HOME'].to_s
|
|
42
|
+
'.trepanrc'
|
|
43
|
+
end unless defined?(CMD_INITFILE_BASE)
|
|
44
|
+
CMD_INITFILE = File.join(HOME_DIR, CMD_INITFILE_BASE) unless
|
|
45
|
+
defined?(CMD_INITFILE)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if __FILE__ == $0
|
|
49
|
+
# Show it:
|
|
50
|
+
require 'pp'
|
|
51
|
+
PP.pp(Trepanning::DEFAULT_SETTINGS)
|
|
52
|
+
puts '=' * 30
|
|
53
|
+
PP.pp(Trepanning::DEFAULT_CMDLINE_SETTINGS)
|
|
54
|
+
end
|
data/app/disassemble.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
2
|
+
# Splits String dissasemble_str into an array for for each
|
|
3
|
+
# line. Line(s) that Fixnum pc_offset matches at the beginning of the
|
|
4
|
+
# line will have prefix "--> " added, otherwise the line will have " "
|
|
5
|
+
# added to the beginning. This array is returned.
|
|
6
|
+
|
|
7
|
+
class Trepan
|
|
8
|
+
module Disassemble
|
|
9
|
+
def mark_disassembly(disassembly_str, iseq_equal, pc_offset,
|
|
10
|
+
brkpt_offsets=[])
|
|
11
|
+
dis_array = disassembly_str.split(/\n/)
|
|
12
|
+
dis_array.map do |line|
|
|
13
|
+
prefix =
|
|
14
|
+
if line =~ /^(\d{4}) /
|
|
15
|
+
offset = $1.to_i
|
|
16
|
+
bp = brkpt_offsets && brkpt_offsets.member?(offset) ? 'B' : ' '
|
|
17
|
+
bp + if offset == pc_offset && iseq_equal
|
|
18
|
+
'--> '
|
|
19
|
+
else
|
|
20
|
+
' '
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
''
|
|
24
|
+
end
|
|
25
|
+
prefix + line
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
module_function :mark_disassembly
|
|
29
|
+
|
|
30
|
+
def disassemble_split(disassembly_str)
|
|
31
|
+
dis_array = disassembly_str.split(/\n/)
|
|
32
|
+
dis_hash = {}
|
|
33
|
+
dis_array.each do |line|
|
|
34
|
+
dis_hash[$1.to_i] = line if line =~ /^(\d{4}) /
|
|
35
|
+
end
|
|
36
|
+
dis_hash
|
|
37
|
+
end
|
|
38
|
+
module_function :disassemble_split
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if __FILE__ == $0
|
|
44
|
+
# Demo it.
|
|
45
|
+
include Trepan::Disassemble
|
|
46
|
+
dis_string='
|
|
47
|
+
local table (size: 6, argc: 1 [opts: 0, rest: -1, post: 0, block: -1] s1)
|
|
48
|
+
[ 6] relative_feature<Arg>[ 5] c [ 4] e [ 3] file [ 2] absolute_feature
|
|
49
|
+
0000 trace 8 ( 26)
|
|
50
|
+
0002 trace 1 ( 27)
|
|
51
|
+
0004 putnil
|
|
52
|
+
'
|
|
53
|
+
[[-1, []], [2, [2]], [10, [0, 4]]].each do |pc_offset, brkpts|
|
|
54
|
+
puts '-' * 40
|
|
55
|
+
puts mark_disassembly(dis_string, true, pc_offset, brkpts).join("\n")
|
|
56
|
+
end
|
|
57
|
+
puts mark_disassembly(dis_string, false, 2).join("\n")
|
|
58
|
+
puts '-' * 40
|
|
59
|
+
require 'pp'
|
|
60
|
+
PP.pp(disassemble_split(dis_string), $stdout)
|
|
61
|
+
end
|
data/app/display.rb
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
3
|
+
# Classes to support gdb-like display/undisplay.
|
|
4
|
+
|
|
5
|
+
require_relative 'frame'
|
|
6
|
+
|
|
7
|
+
# return suitable frame signature to key display expressions off of.
|
|
8
|
+
def display_signature(frame)
|
|
9
|
+
return nil unless frame
|
|
10
|
+
frame.iseq.object_id
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Manage a list of display expressions.
|
|
14
|
+
class DisplayMgr
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
@next = 0
|
|
18
|
+
@list = []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add(frame, arg, fmt=nil)
|
|
22
|
+
return nil unless frame
|
|
23
|
+
begin
|
|
24
|
+
eval(arg, frame.binding)
|
|
25
|
+
rescue
|
|
26
|
+
return nil
|
|
27
|
+
end
|
|
28
|
+
@next += 1
|
|
29
|
+
d = Display.new(frame, arg, fmt, @next)
|
|
30
|
+
@list << d
|
|
31
|
+
d
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# List all display items; return 0 if none
|
|
35
|
+
def all
|
|
36
|
+
s = []
|
|
37
|
+
unless @list.empty?
|
|
38
|
+
s << "Auto-display expressions now in effect:
|
|
39
|
+
Num Enb Expression"
|
|
40
|
+
@list.each do |display|
|
|
41
|
+
s << display.format
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
s
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Delete all display expressions"""
|
|
48
|
+
def clear
|
|
49
|
+
@list = []
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Delete display expression i
|
|
53
|
+
def delete_index(display_number)
|
|
54
|
+
@list.each_with_index do |display, i|
|
|
55
|
+
if display_number == display.number
|
|
56
|
+
@list[i..i] = []
|
|
57
|
+
return true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# display any items that are active'''
|
|
64
|
+
def display(frame)
|
|
65
|
+
return unless frame
|
|
66
|
+
s = []
|
|
67
|
+
sig = display_signature(frame)
|
|
68
|
+
@list.each do |display|
|
|
69
|
+
if display.enabled # && display.signature == sig
|
|
70
|
+
s << display.to_s(frame)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
return s
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def enable_disable(display_number, b_enable_disable)
|
|
77
|
+
@list.each do |display|
|
|
78
|
+
if display_number == display.number
|
|
79
|
+
display.enabled = b_enable_disable
|
|
80
|
+
return true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
false
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Display
|
|
88
|
+
attr_reader :number
|
|
89
|
+
attr_reader :signature
|
|
90
|
+
attr_accessor :enabled
|
|
91
|
+
|
|
92
|
+
def initialize(frame, arg, fmt, number)
|
|
93
|
+
@signature = display_signature(frame)
|
|
94
|
+
@fmt = fmt
|
|
95
|
+
@arg = arg
|
|
96
|
+
@enabled = true
|
|
97
|
+
@number = number
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def to_s(frame)
|
|
101
|
+
return 'No symbol "' + @arg + '" in current context.' unless frame
|
|
102
|
+
|
|
103
|
+
begin
|
|
104
|
+
val = eval(@arg, frame.binding)
|
|
105
|
+
rescue
|
|
106
|
+
return "No symbol \"#{@arg}\" in current context."
|
|
107
|
+
end
|
|
108
|
+
s = "#{self.format(false)} = #{val}"
|
|
109
|
+
return s
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# format display item
|
|
113
|
+
def format(show_enabled=true)
|
|
114
|
+
what = ''
|
|
115
|
+
what += @enabled ? ' y ' : ' n ' if
|
|
116
|
+
show_enabled
|
|
117
|
+
what += (@fmt + ' ') if @fmt
|
|
118
|
+
what += @arg if @arg
|
|
119
|
+
'%3d: %s' % [@number, what]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if __FILE__ == $0
|
|
124
|
+
# Demo it.
|
|
125
|
+
mgr = DisplayMgr.new
|
|
126
|
+
|
|
127
|
+
def print_display(mgr)
|
|
128
|
+
mgr.all.each {|line| puts line}
|
|
129
|
+
puts '=' * 40
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
require 'thread_frame'
|
|
133
|
+
frame = RubyVM::ThreadFrame::current
|
|
134
|
+
|
|
135
|
+
x = 1
|
|
136
|
+
mgr.add(frame, 'x > 1')
|
|
137
|
+
print_display(mgr)
|
|
138
|
+
|
|
139
|
+
mgr.enable_disable(1, false)
|
|
140
|
+
print_display(mgr)
|
|
141
|
+
|
|
142
|
+
mgr.enable_disable(1, true)
|
|
143
|
+
print_display(mgr)
|
|
144
|
+
|
|
145
|
+
mgr.clear()
|
|
146
|
+
print_display(mgr)
|
|
147
|
+
|
|
148
|
+
end
|
data/app/file.rb
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
|
|
3
|
+
# Things related to file/module status
|
|
4
|
+
require 'thread_frame'
|
|
5
|
+
|
|
6
|
+
SCRIPT_ISEQS__ = {} unless
|
|
7
|
+
defined?(SCRIPT_ISEQS__) && SCRIPT_ISEQS__.is_a?(Hash)
|
|
8
|
+
ISEQS__ = {} unless
|
|
9
|
+
defined?(ISEQS__) && ISEQS__.is_a?(Hash)
|
|
10
|
+
|
|
11
|
+
module Trepanning
|
|
12
|
+
def file_match_pat(filename)
|
|
13
|
+
prefix =
|
|
14
|
+
if filename[0..0] == File::SEPARATOR
|
|
15
|
+
# An absolute filename has to match at the beginning and
|
|
16
|
+
# the end.
|
|
17
|
+
'^'
|
|
18
|
+
else
|
|
19
|
+
# An nonabsolute filename has to match either at the
|
|
20
|
+
# beginning of the file name or have a path separator before
|
|
21
|
+
# the supplied part, e.g. "file.rb" does not match "myfile.rb"
|
|
22
|
+
# but matches "my/file.rb"
|
|
23
|
+
'(?:^|[/])'
|
|
24
|
+
end
|
|
25
|
+
"#{prefix}#{Regexp.escape(filename)}$"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def filter_scripts(dirname)
|
|
29
|
+
match_block = Proc.new{|filename, iseq| filename =~ /^#{dirname}/}
|
|
30
|
+
scripts = SCRIPT_ISEQS__.select(&match_block)
|
|
31
|
+
SCRIPT_ISEQS__.delete_if(&match_block)
|
|
32
|
+
match_block = Proc.new{|iseq|
|
|
33
|
+
iseq.source_container[1] =~ /^#{dirname}/
|
|
34
|
+
}
|
|
35
|
+
rejected = {}
|
|
36
|
+
# SCRIPT_ISEQS__ is updated automatically. Dup copy is to make
|
|
37
|
+
# sure we we aren't iterating over something that some other
|
|
38
|
+
# process, thread or hook is filling.
|
|
39
|
+
script_iseqs = SCRIPT_ISEQS__.dup
|
|
40
|
+
script_iseqs.each do |name, iseqs|
|
|
41
|
+
ary = iseqs.select(&match_block)
|
|
42
|
+
rejected[name] = ary unless ary.empty?
|
|
43
|
+
iseqs.delete_if(&match_block)
|
|
44
|
+
end
|
|
45
|
+
return [scripts, rejected]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find_scripts(filename)
|
|
49
|
+
filename_pat = file_match_pat(filename)
|
|
50
|
+
return SCRIPT_ISEQS__.keys.grep(/#{filename_pat}/)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def find_iseqs(iseqs_hash, name)
|
|
54
|
+
iseq_name, filename = name.split(/@/)
|
|
55
|
+
return [] unless iseqs_hash.member?(iseq_name)
|
|
56
|
+
iseqs = iseqs_hash[iseq_name]
|
|
57
|
+
# FIXME: filter out debugger iseqs
|
|
58
|
+
if filename
|
|
59
|
+
filename_pat = file_match_pat(filename)
|
|
60
|
+
iseqs.select{|iseq| iseq.source_container[1] =~ /#{filename_pat}/}
|
|
61
|
+
else
|
|
62
|
+
return iseqs
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def find_iseqs_with_lineno(filename, lineno)
|
|
67
|
+
files = find_scripts(filename)
|
|
68
|
+
files.each do |file|
|
|
69
|
+
found =
|
|
70
|
+
SCRIPT_ISEQS__[file].detect do |iseq|
|
|
71
|
+
iseq.offsetlines.values.flatten.uniq.member?(lineno)
|
|
72
|
+
end
|
|
73
|
+
return found if found
|
|
74
|
+
end
|
|
75
|
+
return nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# parse_position(errmsg, arg)->(fn, name, lineno)
|
|
79
|
+
#
|
|
80
|
+
# Parse arg as [filename|module:]lineno
|
|
81
|
+
# Make sure it works for C:\foo\bar.rb:12
|
|
82
|
+
def parse_position(errmsg, arg)
|
|
83
|
+
colon = arg.rindex(':')
|
|
84
|
+
if colon
|
|
85
|
+
# FIXME: Handle double colons, e.g. File::open
|
|
86
|
+
filename = arg[0..colon-1].rstrip
|
|
87
|
+
m, f = lookupmodule(filename)
|
|
88
|
+
if not f
|
|
89
|
+
errmsg.call("'%s' not found using sys.path" % filename)
|
|
90
|
+
return nil, nil, nil
|
|
91
|
+
else
|
|
92
|
+
filename = f
|
|
93
|
+
arg = arg[colon+1..-1].lstrip
|
|
94
|
+
end
|
|
95
|
+
begin
|
|
96
|
+
lineno = Integer(arg)
|
|
97
|
+
rescue
|
|
98
|
+
errmsg.call("Bad line number: %s", arg)
|
|
99
|
+
return nil, filename, nil
|
|
100
|
+
end
|
|
101
|
+
return nil, filename, lineno
|
|
102
|
+
end
|
|
103
|
+
return nil, nil, nil
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
# Demo it
|
|
107
|
+
if __FILE__ == $0
|
|
108
|
+
include Trepanning
|
|
109
|
+
if !(ARGV.size == 1 && ARGV[0] == 'noload')
|
|
110
|
+
ISEQS__ = {}
|
|
111
|
+
SCRIPT_ISEQS__ = {}
|
|
112
|
+
ARGV[0..-1] = ['noload']
|
|
113
|
+
load(__FILE__)
|
|
114
|
+
else
|
|
115
|
+
load 'tmpdir.rb'
|
|
116
|
+
tmpdir_dir = File.dirname(find_scripts('tmpdir.rb')[0])
|
|
117
|
+
p tmpdir_dir
|
|
118
|
+
%w(tmpdir.rb /tmpdir.rb sometmpdir.rb).each do |filename|
|
|
119
|
+
p find_scripts(filename)
|
|
120
|
+
end
|
|
121
|
+
p find_scripts(__FILE__)
|
|
122
|
+
def tmpdir
|
|
123
|
+
'to conflict with the other tmpdir'
|
|
124
|
+
end
|
|
125
|
+
p find_iseqs(ISEQS__, "tmpdir@#{__FILE__}")
|
|
126
|
+
puts '-' * 20
|
|
127
|
+
p SCRIPT_ISEQS__.keys
|
|
128
|
+
puts '-' * 20
|
|
129
|
+
scripts, rejected = filter_scripts(tmpdir_dir)
|
|
130
|
+
p scripts.keys
|
|
131
|
+
p rejected.keys
|
|
132
|
+
puts '-' * 20
|
|
133
|
+
p SCRIPT_ISEQS__.keys
|
|
134
|
+
end
|
|
135
|
+
end
|