trepanning 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|