ruby-debug 0.1.5-mswin32 → 0.2-mswin32
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/CHANGES +7 -0
- data/Rakefile +1 -1
- data/bin/rdebug +79 -8
- data/bin/remote +30 -0
- data/ext/ruby_debug.c +65 -54
- data/lib/ruby-debug.rb +36 -561
- data/lib/ruby-debug/interface.rb +69 -0
- data/lib/ruby-debug/processor.rb +627 -0
- data/lib/ruby_debug.so +0 -0
- metadata +6 -2
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.2 (2006-06-17)
|
2
|
+
- Added the remote debugging. It should be activated by calling Debugger#start_server method.
|
3
|
+
- CHANGED: In order to activate the debugger, it's not enough to require 'ruby-debug'.
|
4
|
+
Debugger#start method must be called explicitly.
|
5
|
+
- Debugger used to evaluate anything you enter as long as it's not a command. Starting from
|
6
|
+
this version the 'eval' command must be used to evaluate an expression.
|
7
|
+
|
1
8
|
0.1.5 (2006-06-13)
|
2
9
|
- Now the check for a breakpoint uses base filename of the source file.
|
3
10
|
- Removed compilation warnings when compiling with -Wall
|
data/Rakefile
CHANGED
data/bin/rdebug
CHANGED
@@ -1,13 +1,84 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
if ARGV.empty?
|
4
|
-
puts "Usage: #{__FILE__} <script>"
|
5
|
-
exit(1)
|
6
|
-
end
|
7
|
-
|
8
3
|
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require "ostruct"
|
9
6
|
require 'ruby-debug'
|
10
|
-
trap('INT') { Debugger.interrupt_last }
|
11
7
|
|
12
|
-
|
13
|
-
|
8
|
+
options = OpenStruct.new(
|
9
|
+
'server' => false,
|
10
|
+
'client' => false,
|
11
|
+
'host' => nil,
|
12
|
+
'port' => Debugger::PORT
|
13
|
+
)
|
14
|
+
|
15
|
+
opts = OptionParser.new do |opts|
|
16
|
+
opts.banner = <<EOB
|
17
|
+
ruby-debug #{Debugger::VERSION}
|
18
|
+
Usage: rdebug [options] <script.rb> <script.rb parameters>
|
19
|
+
EOB
|
20
|
+
opts.separator ""
|
21
|
+
opts.separator "Options:"
|
22
|
+
opts.on("-s", "--server", "Listen for remote connections") {options.server = true}
|
23
|
+
opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
|
24
|
+
opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
|
25
|
+
opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
|
26
|
+
opts.separator ""
|
27
|
+
opts.separator "Common options:"
|
28
|
+
opts.on_tail("--help", "Show this message") do
|
29
|
+
puts opts
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
opts.on_tail("-v", "--version", "Show version") do
|
33
|
+
puts "ruby-debug #{Debugger::VERSION}"
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
opts.parse! ARGV
|
40
|
+
rescue StandardError => e
|
41
|
+
puts opts
|
42
|
+
puts
|
43
|
+
puts e.message
|
44
|
+
exit(-1)
|
45
|
+
end
|
46
|
+
|
47
|
+
if options.client
|
48
|
+
require "socket"
|
49
|
+
interface = Debugger::LocalInterface.new
|
50
|
+
socket = TCPSocket.new(options.host, options.port)
|
51
|
+
puts "Connected."
|
52
|
+
|
53
|
+
catch(:exit) do
|
54
|
+
while (line = socket.gets)
|
55
|
+
case line
|
56
|
+
when /^PROMPT (.*)$/
|
57
|
+
input = interface.read_command($1)
|
58
|
+
throw :exit unless input
|
59
|
+
socket.puts input
|
60
|
+
when /^CONFIRM (.*)$/
|
61
|
+
input = interface.confirm($1)
|
62
|
+
throw :exit unless input
|
63
|
+
socket.puts input
|
64
|
+
else
|
65
|
+
print line
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
socket.close
|
70
|
+
puts
|
71
|
+
else
|
72
|
+
if ARGV.empty?
|
73
|
+
puts opts
|
74
|
+
puts
|
75
|
+
puts "Must specify a script to run"
|
76
|
+
exit(-1)
|
77
|
+
end
|
78
|
+
|
79
|
+
trap('INT') { Debugger.interrupt_last }
|
80
|
+
Debugger.start_server(options.host, options.port) if options.server
|
81
|
+
Debugger.start
|
82
|
+
debugger 2
|
83
|
+
load ARGV.shift
|
84
|
+
end
|
data/bin/remote
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require "ruby-debug/inputs"
|
5
|
+
|
6
|
+
host = ARGV[0] || "localhost"
|
7
|
+
port = 8989
|
8
|
+
|
9
|
+
input = Debugger::LocalInput.new
|
10
|
+
socket = TCPSocket.new(host, port)
|
11
|
+
puts "Connected."
|
12
|
+
|
13
|
+
catch(:exit) do
|
14
|
+
while (line = socket.gets)
|
15
|
+
case line
|
16
|
+
when /^PROMPT (.*)$/
|
17
|
+
data = input.read_command($1)
|
18
|
+
throw :exit unless data
|
19
|
+
socket.puts data
|
20
|
+
when /^CONFIRM (.*)$/
|
21
|
+
data = input.confirm($1)
|
22
|
+
throw :exit unless data
|
23
|
+
socket.puts data
|
24
|
+
else
|
25
|
+
print line
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
socket.close
|
30
|
+
puts
|
data/ext/ruby_debug.c
CHANGED
@@ -4,13 +4,15 @@
|
|
4
4
|
#include <rubysig.h>
|
5
5
|
#include <st.h>
|
6
6
|
|
7
|
-
#define DEBUG_VERSION "0.
|
7
|
+
#define DEBUG_VERSION "0.2"
|
8
8
|
|
9
9
|
typedef struct {
|
10
10
|
int thnum;
|
11
|
+
VALUE last_file;
|
12
|
+
VALUE last_line;
|
13
|
+
int moved;
|
11
14
|
int stop_next;
|
12
15
|
int dest_frame;
|
13
|
-
int src_line;
|
14
16
|
int stop_line;
|
15
17
|
int stop_frame;
|
16
18
|
int suspend;
|
@@ -43,7 +45,7 @@ static VALUE cContext;
|
|
43
45
|
static VALUE cFrame;
|
44
46
|
static VALUE cBreakpoint;
|
45
47
|
|
46
|
-
static ID
|
48
|
+
static ID idAtLine;
|
47
49
|
static ID idAtBreakpoint;
|
48
50
|
static ID idAtCatchpoint;
|
49
51
|
static ID idAtTracing;
|
@@ -81,6 +83,8 @@ debug_context_mark(void* data)
|
|
81
83
|
debug_context_t *debug_context = (debug_context_t *)data;
|
82
84
|
rb_gc_mark(debug_context->frames);
|
83
85
|
rb_gc_mark(debug_context->thread);
|
86
|
+
rb_gc_mark(debug_context->last_file);
|
87
|
+
rb_gc_mark(debug_context->last_line);
|
84
88
|
}
|
85
89
|
|
86
90
|
static VALUE
|
@@ -91,9 +95,13 @@ debug_context_create(VALUE thread)
|
|
91
95
|
|
92
96
|
debug_context = ALLOC(debug_context_t);
|
93
97
|
debug_context-> thnum = ++thnum_max;
|
98
|
+
|
99
|
+
debug_context->last_file = Qnil;
|
100
|
+
debug_context->last_line = Qnil;
|
101
|
+
debug_context->moved = 0;
|
102
|
+
|
94
103
|
debug_context->stop_next = -1;
|
95
104
|
debug_context->dest_frame = -1;
|
96
|
-
debug_context->src_line = -1;
|
97
105
|
debug_context->stop_line = -1;
|
98
106
|
debug_context->stop_frame = -1;
|
99
107
|
debug_context->suspend = 0;
|
@@ -145,16 +153,36 @@ debug_frame_create(VALUE file, VALUE line, VALUE binding, ID id)
|
|
145
153
|
return result;
|
146
154
|
}
|
147
155
|
|
148
|
-
static
|
149
|
-
|
156
|
+
static void
|
157
|
+
save_current_position(VALUE context)
|
150
158
|
{
|
151
|
-
VALUE
|
159
|
+
VALUE cur_frame;
|
160
|
+
debug_context_t *debug_context;
|
161
|
+
debug_frame_t *debug_frame;
|
162
|
+
|
163
|
+
Data_Get_Struct(context, debug_context_t, debug_context);
|
164
|
+
if(RARRAY(debug_context->frames)->len == 0)
|
165
|
+
return;
|
166
|
+
|
167
|
+
cur_frame = *RARRAY(debug_context->frames)->ptr;
|
168
|
+
Data_Get_Struct(cur_frame, debug_frame_t, debug_frame);
|
169
|
+
|
170
|
+
debug_context->last_file = debug_frame->file;
|
171
|
+
debug_context->last_line = debug_frame->line;
|
172
|
+
debug_context->moved = 0;
|
173
|
+
}
|
152
174
|
|
153
|
-
|
175
|
+
#define did_moved() (debug_context->last_line != line || \
|
176
|
+
debug_context->last_file == Qnil || \
|
177
|
+
rb_str_cmp(debug_context->last_file, file) != 0)
|
154
178
|
|
179
|
+
static VALUE
|
180
|
+
call_at_line(VALUE context, int thnum, VALUE binding, VALUE file, VALUE line)
|
181
|
+
{
|
155
182
|
last_debugged_thnum = thnum;
|
183
|
+
save_current_position(context);
|
156
184
|
debug_suspend(mDebugger);
|
157
|
-
return rb_funcall(context,
|
185
|
+
return rb_funcall(context, idAtLine, 3, file, line, binding);
|
158
186
|
}
|
159
187
|
|
160
188
|
static void
|
@@ -189,7 +217,7 @@ basename(VALUE filename)
|
|
189
217
|
}
|
190
218
|
|
191
219
|
static int
|
192
|
-
check_breakpoints(
|
220
|
+
check_breakpoints(debug_context_t *debug_context, VALUE file, VALUE klass, VALUE pos)
|
193
221
|
{
|
194
222
|
VALUE breakpoint;
|
195
223
|
debug_breakpoint_t *debug_breakpoint;
|
@@ -197,6 +225,9 @@ check_breakpoints(VALUE context, VALUE file, VALUE klass, VALUE pos)
|
|
197
225
|
|
198
226
|
if(RARRAY(breakpoints)->len == 0)
|
199
227
|
return -1;
|
228
|
+
if(!debug_context->moved)
|
229
|
+
return -1;
|
230
|
+
|
200
231
|
for(i = 0; i < RARRAY(breakpoints)->len; i++)
|
201
232
|
{
|
202
233
|
breakpoint = rb_ary_entry(breakpoints, i);
|
@@ -282,10 +313,12 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
282
313
|
debug_context_t *debug_context;
|
283
314
|
VALUE file = Qnil, line = Qnil;
|
284
315
|
int breakpoint_index = -1;
|
285
|
-
|
316
|
+
|
286
317
|
static int debugging = 0;
|
287
318
|
|
319
|
+
if (mid == ID_ALLOCATOR) return;
|
288
320
|
if(debugging) return;
|
321
|
+
if(!node) return;
|
289
322
|
|
290
323
|
debugging++;
|
291
324
|
|
@@ -294,11 +327,11 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
294
327
|
Data_Get_Struct(context, debug_context_t, debug_context);
|
295
328
|
check_suspend(debug_context);
|
296
329
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
330
|
+
file = rb_str_new2(node->nd_file);
|
331
|
+
line = INT2FIX(nd_line(node));
|
332
|
+
|
333
|
+
if(did_moved())
|
334
|
+
debug_context->moved = 1;
|
302
335
|
|
303
336
|
switch(event)
|
304
337
|
{
|
@@ -310,15 +343,15 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
310
343
|
{
|
311
344
|
rb_funcall(context, idAtTracing, 2, file, line);
|
312
345
|
}
|
313
|
-
|
346
|
+
|
314
347
|
if(debug_context->dest_frame == -1 ||
|
315
348
|
RARRAY(debug_context->frames)->len == debug_context->dest_frame)
|
316
349
|
{
|
317
350
|
debug_context->stop_next--;
|
318
351
|
if(debug_context->stop_next < 0)
|
319
|
-
|
352
|
+
debug_context->stop_next = -1;
|
320
353
|
/* we check that we actualy moved to another line */
|
321
|
-
if(
|
354
|
+
if(did_moved())
|
322
355
|
{
|
323
356
|
debug_context->stop_line--;
|
324
357
|
}
|
@@ -334,7 +367,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
334
367
|
}
|
335
368
|
|
336
369
|
if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
|
337
|
-
(breakpoint_index = check_breakpoints(
|
370
|
+
(breakpoint_index = check_breakpoints(debug_context, file, klass, line)) != -1)
|
338
371
|
{
|
339
372
|
binding = self? create_binding(self) : Qnil;
|
340
373
|
/* check breakpoint expression */
|
@@ -342,41 +375,37 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
342
375
|
{
|
343
376
|
breakpoint = get_breakpoint_at(breakpoint_index);
|
344
377
|
if(check_breakpoint_expression(breakpoint, binding))
|
345
|
-
rb_funcall(context, idAtBreakpoint,
|
378
|
+
rb_funcall(context, idAtBreakpoint, 1, breakpoint);
|
346
379
|
else
|
347
380
|
break;
|
348
381
|
}
|
349
382
|
|
350
383
|
/* reset all pointers */
|
351
384
|
debug_context->dest_frame = -1;
|
352
|
-
debug_context->src_line = -1;
|
353
385
|
debug_context->stop_line = -1;
|
354
386
|
debug_context->stop_next = -1;
|
355
387
|
|
356
|
-
|
388
|
+
call_at_line(context, debug_context->thnum, binding, file, line);
|
357
389
|
}
|
358
390
|
break;
|
359
391
|
}
|
360
392
|
case RUBY_EVENT_C_CALL:
|
361
|
-
{
|
362
|
-
if(node)
|
363
393
|
{
|
364
394
|
set_frame_source(debug_context, file, line);
|
365
|
-
|
366
|
-
break;
|
395
|
+
break;
|
367
396
|
}
|
368
397
|
case RUBY_EVENT_CALL:
|
369
398
|
{
|
370
399
|
save_call_frame(self, file, line, mid, debug_context);
|
371
|
-
breakpoint_index = check_breakpoints(
|
400
|
+
breakpoint_index = check_breakpoints(debug_context, file, klass, rb_str_new2(rb_id2name(mid)));
|
372
401
|
if(breakpoint_index != -1)
|
373
402
|
{
|
374
403
|
binding = self? create_binding(self) : Qnil;
|
375
404
|
breakpoint = get_breakpoint_at(breakpoint_index);
|
376
405
|
if(check_breakpoint_expression(breakpoint, binding))
|
377
406
|
{
|
378
|
-
rb_funcall(context, idAtBreakpoint,
|
379
|
-
|
407
|
+
rb_funcall(context, idAtBreakpoint, 1, breakpoint);
|
408
|
+
call_at_line(context, debug_context->thnum, binding, file, line);
|
380
409
|
}
|
381
410
|
}
|
382
411
|
break;
|
@@ -407,7 +436,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
407
436
|
if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
|
408
437
|
{
|
409
438
|
debug_stop(mDebugger);
|
410
|
-
|
439
|
+
break;
|
411
440
|
}
|
412
441
|
|
413
442
|
if(catchpoint == Qnil)
|
@@ -419,10 +448,10 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
419
448
|
aclass = rb_ary_entry(ancestors, i);
|
420
449
|
if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
|
421
450
|
{
|
422
|
-
rb_funcall(context, idAtCatchpoint,
|
451
|
+
rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
|
423
452
|
binding = self? create_binding(self) : Qnil;
|
424
|
-
|
425
|
-
|
453
|
+
call_at_line(context, debug_context->thnum, binding, file, line);
|
454
|
+
break;
|
426
455
|
}
|
427
456
|
}
|
428
457
|
|
@@ -437,18 +466,6 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
437
466
|
debugging--;
|
438
467
|
}
|
439
468
|
|
440
|
-
static VALUE
|
441
|
-
debug_thnum(VALUE self)
|
442
|
-
{
|
443
|
-
VALUE thread, context;
|
444
|
-
debug_context_t *debug_context;
|
445
|
-
|
446
|
-
thread = rb_thread_current();
|
447
|
-
context = thread_context_lookup(thread);
|
448
|
-
Data_Get_Struct(context, debug_context_t, debug_context);
|
449
|
-
return INT2FIX(debug_context->thnum);
|
450
|
-
}
|
451
|
-
|
452
469
|
static VALUE
|
453
470
|
debug_start(VALUE self)
|
454
471
|
{
|
@@ -743,9 +760,8 @@ context_stop_next(VALUE self, VALUE steps)
|
|
743
760
|
static VALUE
|
744
761
|
context_step_over(int argc, VALUE *argv, VALUE self)
|
745
762
|
{
|
746
|
-
VALUE lines, frame
|
763
|
+
VALUE lines, frame;
|
747
764
|
debug_context_t *debug_context;
|
748
|
-
debug_frame_t *debug_frame;
|
749
765
|
|
750
766
|
debug_check_started();
|
751
767
|
|
@@ -766,10 +782,6 @@ context_step_over(int argc, VALUE *argv, VALUE self)
|
|
766
782
|
debug_context->dest_frame = FIX2INT(frame);
|
767
783
|
}
|
768
784
|
|
769
|
-
cur_frame = *RARRAY(debug_context->frames)->ptr;
|
770
|
-
Data_Get_Struct(cur_frame, debug_frame_t, debug_frame);
|
771
|
-
debug_context->src_line = FIX2INT(debug_frame->line);
|
772
|
-
|
773
785
|
return Qnil;
|
774
786
|
}
|
775
787
|
|
@@ -937,7 +949,6 @@ Init_ruby_debug()
|
|
937
949
|
rb_define_module_function(mDebugger, "start", debug_start, 0);
|
938
950
|
rb_define_module_function(mDebugger, "stop", debug_stop, 0);
|
939
951
|
rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
|
940
|
-
rb_define_module_function(mDebugger, "thnum", debug_thnum, 0);
|
941
952
|
rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
|
942
953
|
rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
|
943
954
|
rb_define_module_function(mDebugger, "catchpoint", debug_catchpoint, 0);
|
@@ -974,7 +985,7 @@ Init_ruby_debug()
|
|
974
985
|
rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
|
975
986
|
rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
|
976
987
|
|
977
|
-
|
988
|
+
idAtLine = rb_intern("at_line");
|
978
989
|
idAtBreakpoint = rb_intern("at_breakpoint");
|
979
990
|
idAtCatchpoint = rb_intern("at_catchpoint");
|
980
991
|
idAtTracing = rb_intern("at_tracing");
|
data/lib/ruby-debug.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
require 'ruby_debug.so'
|
2
1
|
require 'pp'
|
2
|
+
require 'stringio'
|
3
|
+
require 'thread'
|
4
|
+
require 'ruby_debug.so'
|
5
|
+
require 'ruby-debug/processor'
|
3
6
|
|
4
7
|
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
5
8
|
|
6
9
|
module Debugger
|
7
|
-
|
10
|
+
MUTEX = Class.new do
|
8
11
|
def initialize
|
9
12
|
@locker = nil
|
10
13
|
@waiting = []
|
@@ -42,582 +45,56 @@ module Debugger
|
|
42
45
|
t.run if t
|
43
46
|
self
|
44
47
|
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
@stdout = STDOUT
|
50
|
-
@display = []
|
51
|
-
@trace_proc = nil
|
48
|
+
end.new
|
49
|
+
|
50
|
+
PORT = 8989
|
52
51
|
|
52
|
+
@processor = CommandProcessor.new
|
53
|
+
|
53
54
|
class Context
|
54
|
-
DEBUG_LAST_CMD = []
|
55
|
-
|
56
55
|
private
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
def readline(prompt, hist)
|
61
|
-
Readline::readline(prompt, hist)
|
62
|
-
end
|
63
|
-
rescue LoadError
|
64
|
-
def readline(prompt, hist)
|
65
|
-
STDOUT.print prompt
|
66
|
-
STDOUT.flush
|
67
|
-
line = STDIN.gets
|
68
|
-
exit unless line
|
69
|
-
line.chomp!
|
70
|
-
line
|
71
|
-
end
|
72
|
-
USE_READLINE = false
|
57
|
+
def processor
|
58
|
+
Debugger.processor
|
73
59
|
end
|
74
60
|
|
75
|
-
def
|
76
|
-
|
61
|
+
def at_breakpoint(breakpoint)
|
62
|
+
processor.at_breakpoint(self, breakpoint)
|
77
63
|
end
|
78
64
|
|
79
|
-
def
|
80
|
-
|
81
|
-
stdout.printf "Breakpoint %d, %s at %s:%s\n", n, method_name, breakpoint.source, breakpoint.pos
|
82
|
-
end
|
83
|
-
|
84
|
-
def at_catchpoint
|
85
|
-
frames = Debugger.current_context.frames
|
86
|
-
stdout.printf "%s:%d: `%s' (%s)\n", frames[0].file, frames[0].line, $!, $!.class
|
87
|
-
fs = frames.size
|
88
|
-
tb = caller(0)[-fs..-1]
|
89
|
-
if tb
|
90
|
-
for i in tb
|
91
|
-
stdout.printf "\tfrom %s\n", i
|
92
|
-
end
|
93
|
-
end
|
65
|
+
def at_catchpoint(excpt)
|
66
|
+
processor.at_catchpoint(self, excpt)
|
94
67
|
end
|
95
68
|
|
96
69
|
def at_tracing(file, line)
|
97
|
-
|
98
|
-
Debugger.trace_proc.call(self.thnum, file, line)
|
99
|
-
else
|
100
|
-
stdout.puts sprintf("Tracing(%d):%s:%s %s", self.thnum, file, line, line_at(file, line))
|
101
|
-
end
|
70
|
+
processor.at_tracing(self, file, line)
|
102
71
|
end
|
103
72
|
|
104
|
-
def
|
73
|
+
def at_line(file, line, binding)
|
105
74
|
MUTEX.lock
|
106
|
-
|
107
|
-
binding_file = file
|
108
|
-
binding_line = line
|
109
|
-
previous_line = nil
|
110
|
-
stdout.printf "%s:%d: %s", binding_file, binding_line, line_at(binding_file, binding_line)
|
111
|
-
display_expressions(binding)
|
112
|
-
prompt = true
|
113
|
-
while prompt and input = readline("(rdb:%d) " % Debugger.thnum, true)
|
114
|
-
catch(:debug_error) do
|
115
|
-
if input == ""
|
116
|
-
next unless DEBUG_LAST_CMD[0]
|
117
|
-
input = DEBUG_LAST_CMD[0]
|
118
|
-
else
|
119
|
-
DEBUG_LAST_CMD[0] = input
|
120
|
-
end
|
121
|
-
|
122
|
-
case input
|
123
|
-
when /^\s*s(?:tep)?(?:\s+(\d+))?$/
|
124
|
-
self.stop_next = $1 ? $1.to_i : 1
|
125
|
-
prompt = false
|
126
|
-
|
127
|
-
when /^\s*c(?:ont)?$|^\s*r(?:un)?$/
|
128
|
-
prompt = false
|
129
|
-
|
130
|
-
when /^\s*v(?:ar)?\s+/
|
131
|
-
debug_variable_info($', binding)
|
132
|
-
|
133
|
-
when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
|
134
|
-
display_frames(frame_pos)
|
135
|
-
|
136
|
-
when /^\s*l(?:ist)?(?:\s+(.+))?$/
|
137
|
-
if not $1
|
138
|
-
b = previous_line ? previous_line + 10 : binding_line - 5
|
139
|
-
e = b + 9
|
140
|
-
elsif $1 == '-'
|
141
|
-
b = previous_line ? previous_line - 10 : binding_line - 5
|
142
|
-
e = b + 9
|
143
|
-
else
|
144
|
-
b, e = $1.split(/[-,]/)
|
145
|
-
if e
|
146
|
-
b = b.to_i
|
147
|
-
e = e.to_i
|
148
|
-
else
|
149
|
-
b = b.to_i - 5
|
150
|
-
e = b + 9
|
151
|
-
end
|
152
|
-
end
|
153
|
-
previous_line = b
|
154
|
-
display_list(b, e, binding_file, binding_line)
|
155
|
-
|
156
|
-
when /^\s*n(?:ext)?(?:\s+(\d+))?$/
|
157
|
-
steps = $1 ? $1.to_i : 1
|
158
|
-
self.step_over steps, self.frames.size - frame_pos
|
159
|
-
prompt = false
|
160
|
-
|
161
|
-
when /^\s*up(?:\s+(\d+))?$/
|
162
|
-
previous_line = nil
|
163
|
-
frame_pos += $1 ? $1.to_i : 1
|
164
|
-
if frame_pos >= self.frames.size
|
165
|
-
frame_pos = self.frames.size - 1
|
166
|
-
stdout.puts "At toplevel"
|
167
|
-
end
|
168
|
-
frame = self.frames[frame_pos]
|
169
|
-
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
170
|
-
stdout.print format_frame(frame, frame_pos)
|
171
|
-
|
172
|
-
when /^\s*down(?:\s+(\d+))?$/
|
173
|
-
previous_line = nil
|
174
|
-
frame_pos -= $1 ? $1.to_i : 1
|
175
|
-
if frame_pos < 0
|
176
|
-
frame_pos = 0
|
177
|
-
stdout.print "At stack bottom\n"
|
178
|
-
end
|
179
|
-
frame = self.frames[frame_pos]
|
180
|
-
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
181
|
-
stdout.print format_frame(frame, frame_pos)
|
182
|
-
|
183
|
-
when /^\s*fin(?:ish)?$/
|
184
|
-
if frame_pos == self.frames.size
|
185
|
-
stdout.print "\"finish\" not meaningful in the outermost frame.\n"
|
186
|
-
else
|
187
|
-
self.stop_frame = self.frames.size - frame_pos
|
188
|
-
frame_pos = 0
|
189
|
-
prompt = false
|
190
|
-
end
|
191
|
-
|
192
|
-
when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:\s]+)\s*(?:\sif\s+(.+))?$/
|
193
|
-
pos = $2
|
194
|
-
expr = $3
|
195
|
-
if $1
|
196
|
-
klass = debug_silent_eval($1, binding)
|
197
|
-
if klass && !klass.kind_of?(Module)
|
198
|
-
stdout.puts "Unknown class #$1"
|
199
|
-
throw :debug_error
|
200
|
-
end
|
201
|
-
klass = klass.name if klass
|
202
|
-
file = $1
|
203
|
-
end
|
204
|
-
if pos =~ /^\d+$/
|
205
|
-
pname = pos
|
206
|
-
pos = pos.to_i
|
207
|
-
else
|
208
|
-
pname = pos = pos.intern.id2name
|
209
|
-
end
|
210
|
-
Debugger.add_breakpoint klass || file, pos, expr
|
211
|
-
stdout.printf "Set breakpoint %d at %s:%s\n", Debugger.breakpoints.size, klass || file, pname
|
212
|
-
|
213
|
-
when /^\s*b(?:reak)?\s+(.+)[#.]([^.:\s]+)(?:\s+if\s+(.+))?$/
|
214
|
-
pos = $2.intern.id2name
|
215
|
-
expr = $3
|
216
|
-
klass = debug_eval($1, binding)
|
217
|
-
if klass.nil? || !klass.kind_of?(Module)
|
218
|
-
stdout.puts "Unknown class #$1"
|
219
|
-
throw :debug_error
|
220
|
-
end
|
221
|
-
Debugger.add_breakpoint klass.name, pos, expr
|
222
|
-
stdout.printf "Set breakpoint %d at %s.%s\n", Debugger.breakpoints.size, klass, pos
|
223
|
-
|
224
|
-
when /^\s*b(?:reak)?$/
|
225
|
-
unless Debugger.breakpoints.empty?
|
226
|
-
stdout.print "Breakpoints:\n"
|
227
|
-
Debugger.breakpoints.each_with_index do |b, n|
|
228
|
-
if b.expr.nil?
|
229
|
-
stdout.printf " %d %s:%s\n", n+1, b.source, b.pos
|
230
|
-
else
|
231
|
-
stdout.printf " %d %s:%s if %s\n", n+1, b.source, b.pos, b.expr
|
232
|
-
end
|
233
|
-
end
|
234
|
-
stdout.puts
|
235
|
-
else
|
236
|
-
stdout.print "No breakpoints\n"
|
237
|
-
end
|
238
|
-
when /^\s*del(?:ete)?(?:\s+(\d+))?$/
|
239
|
-
pos = $1
|
240
|
-
unless pos
|
241
|
-
input = readline("Clear all breakpoints? (y/n) ", false)
|
242
|
-
if input == "y"
|
243
|
-
Debugger.breakpoints.clear
|
244
|
-
end
|
245
|
-
else
|
246
|
-
pos = pos.to_i
|
247
|
-
unless Debugger.breakpoints.delete_at(pos-1)
|
248
|
-
stdout.printf "Breakpoint %d is not defined\n", pos
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
when /^\s*th(?:read)?\s+/
|
253
|
-
if Debugger.debug_thread_info($') == :cont
|
254
|
-
prompt = false
|
255
|
-
end
|
256
|
-
|
257
|
-
when /^\s*m(?:ethod)?\s+/
|
258
|
-
debug_method_info($', binding)
|
259
|
-
|
260
|
-
when /^\s*pp\s+/
|
261
|
-
PP.pp(debug_eval($', binding), stdout) rescue stdout.puts $!.message
|
262
|
-
|
263
|
-
when /^\s*p\s+/
|
264
|
-
stdout.printf "%s\n", debug_eval($', binding).inspect
|
265
|
-
|
266
|
-
when /^\s*h(?:elp)?$/
|
267
|
-
debug_print_help()
|
268
|
-
|
269
|
-
when /^\s*q(?:uit)?$/
|
270
|
-
input = readline("Really quit? (y/n) ", false)
|
271
|
-
if input == "y"
|
272
|
-
exit! # exit -> exit!: No graceful way to stop threads...
|
273
|
-
end
|
274
|
-
|
275
|
-
when /^\s*disp(?:lay)?\s+(.+)$/
|
276
|
-
exp = $1
|
277
|
-
display.push [true, exp]
|
278
|
-
stdout.printf "%d: ", display.size
|
279
|
-
display_expression(exp, binding)
|
280
|
-
|
281
|
-
when /^\s*disp(?:lay)?$/
|
282
|
-
display_expressions(binding)
|
283
|
-
|
284
|
-
when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
|
285
|
-
pos = $1
|
286
|
-
unless pos
|
287
|
-
input = readline("Clear all expressions? (y/n) ", false)
|
288
|
-
if input == "y"
|
289
|
-
for d in display
|
290
|
-
d[0] = false
|
291
|
-
end
|
292
|
-
end
|
293
|
-
else
|
294
|
-
pos = pos.to_i
|
295
|
-
if display[pos-1]
|
296
|
-
display[pos-1][0] = false
|
297
|
-
else
|
298
|
-
stdout.printf "Display expression %d is not defined\n", pos
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
when /^\s*cat(?:ch)?(?:\s+(.+))?$/
|
303
|
-
if $1
|
304
|
-
excn = $1
|
305
|
-
if excn == 'off'
|
306
|
-
Debugger.catchpoint = nil
|
307
|
-
stdout.print "Clear catchpoint.\n"
|
308
|
-
else
|
309
|
-
Debugger.catchpoint = excn
|
310
|
-
stdout.printf "Set catchpoint %s.\n", excn
|
311
|
-
end
|
312
|
-
else
|
313
|
-
if Debugger.catchpoint
|
314
|
-
stdout.printf "Catchpoint %s.\n", Debugger.catchpoint
|
315
|
-
else
|
316
|
-
stdout.print "No catchpoint.\n"
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
|
321
|
-
if defined?( $2 )
|
322
|
-
Debugger.tracing = $1 == 'on'
|
323
|
-
elsif defined?( $1 )
|
324
|
-
self.tracing = $1 == 'on'
|
325
|
-
end
|
326
|
-
if Debugger.tracing || self.tracing
|
327
|
-
stdout.print "Trace on.\n"
|
328
|
-
else
|
329
|
-
stdout.print "Trace off.\n"
|
330
|
-
end
|
331
|
-
|
332
|
-
else
|
333
|
-
v = debug_eval(input, binding)
|
334
|
-
stdout.printf "%s\n", v.inspect
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
75
|
+
processor.at_line(self, file, line, binding)
|
338
76
|
MUTEX.unlock
|
339
77
|
Debugger.resume
|
340
78
|
end
|
341
|
-
|
342
|
-
def debug_print_help
|
343
|
-
stdout.print <<EOHELP
|
344
|
-
ruby-debug help v.#{Debugger::VERSION}
|
345
|
-
Commands
|
346
|
-
b[reak] [file|class:]<line|method> [if expr]
|
347
|
-
b[reak] [class.]<line|method> [if expr]
|
348
|
-
set breakpoint to some position,
|
349
|
-
optionally if expr == true
|
350
|
-
cat[ch] <an Exception> set catchpoint to an exception
|
351
|
-
cat[ch] show catchpoint
|
352
|
-
disp[lay] <expression> add expression into display expression list
|
353
|
-
undisp[lay][ nnn] delete one particular or all display expressions
|
354
|
-
b[reak] list breakpoints
|
355
|
-
del[ete][ nnn] delete some or all breakpoints
|
356
|
-
c[ont] run until program ends or hit breakpoint
|
357
|
-
r[un] alias for cont
|
358
|
-
s[tep][ nnn] step (into methods) one line or till line nnn
|
359
|
-
n[ext][ nnn] go over one line or till line nnn
|
360
|
-
w[here] display frames
|
361
|
-
f[rame] alias for where
|
362
|
-
l[ist][ (-|nn-mm)] list program, - list backwards, nn-mm list given lines
|
363
|
-
up[ nn] move to higher frame
|
364
|
-
down[ nn] move to lower frame
|
365
|
-
fin[ish] return to outer frame
|
366
|
-
q[uit] exit from debugger
|
367
|
-
v[ar] g[lobal] show global variables
|
368
|
-
v[ar] l[ocal] show local variables
|
369
|
-
v[ar] i[nstance] <object> show instance variables of object
|
370
|
-
v[ar] c[onst] <object> show constants of object
|
371
|
-
m[ethod] i[nstance] <obj> show methods of object
|
372
|
-
m[ethod] <class|module> show instance methods of class or module
|
373
|
-
th[read] l[ist] list all threads
|
374
|
-
th[read] c[ur[rent]] show current thread
|
375
|
-
th[read] [sw[itch]] <nnn> switch thread context to nnn
|
376
|
-
th[read] stop <nnn> stop thread nnn
|
377
|
-
th[read] resume <nnn> resume thread nnn
|
378
|
-
p expression evaluate expression and print its value
|
379
|
-
pp expression evaluate expression and print its value
|
380
|
-
h[elp] print this help
|
381
|
-
<everything else> evaluate
|
382
|
-
EOHELP
|
383
|
-
end
|
384
|
-
|
385
|
-
def display_expressions(binding)
|
386
|
-
n = 1
|
387
|
-
for d in display
|
388
|
-
if d[0]
|
389
|
-
stdout.printf "%d: ", n
|
390
|
-
display_expression(d[1], binding)
|
391
|
-
end
|
392
|
-
n += 1
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
def display_expression(exp, binding)
|
397
|
-
stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
|
398
|
-
end
|
399
|
-
|
400
|
-
def debug_eval(str, binding)
|
401
|
-
begin
|
402
|
-
val = eval(str, binding)
|
403
|
-
rescue StandardError, ScriptError => e
|
404
|
-
at = eval("caller(1)", binding)
|
405
|
-
stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
|
406
|
-
for i in at
|
407
|
-
stdout.printf "\tfrom %s\n", i
|
408
|
-
end
|
409
|
-
throw :debug_error
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
def debug_silent_eval(str, binding)
|
414
|
-
begin
|
415
|
-
eval(str, binding)
|
416
|
-
rescue StandardError, ScriptError
|
417
|
-
nil
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
def debug_variable_info(input, binding)
|
422
|
-
case input
|
423
|
-
when /^\s*g(?:lobal)?\s*$/
|
424
|
-
var_list(global_variables, binding)
|
425
|
-
|
426
|
-
when /^\s*l(?:ocal)?\s*$/
|
427
|
-
var_list(eval("local_variables", binding), binding)
|
428
|
-
|
429
|
-
when /^\s*i(?:nstance)?\s+/
|
430
|
-
obj = debug_eval($', binding)
|
431
|
-
var_list(obj.instance_variables, obj.instance_eval{binding()})
|
432
|
-
|
433
|
-
when /^\s*c(?:onst(?:ant)?)?\s+/
|
434
|
-
obj = debug_eval($', binding)
|
435
|
-
unless obj.kind_of? Module
|
436
|
-
stdout.print "Should be Class/Module: ", $', "\n"
|
437
|
-
else
|
438
|
-
var_list(obj.constants, obj.module_eval{binding()})
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
def display_frames(pos)
|
444
|
-
self.frames.each_with_index do |frame, idx|
|
445
|
-
if idx == pos
|
446
|
-
stdout.print "--> "
|
447
|
-
else
|
448
|
-
stdout.print " "
|
449
|
-
end
|
450
|
-
stdout.print format_frame(frame, idx)
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
def format_frame(frame, pos)
|
455
|
-
bind, file, line, id = frame.binding, frame.file, frame.line, frame.id
|
456
|
-
sprintf "#%d %s:%s%s\n", pos + 1, file, line,
|
457
|
-
(id ? ":in `#{id.id2name}'" : "")
|
458
|
-
end
|
459
|
-
|
460
|
-
def var_list(ary, binding)
|
461
|
-
ary.sort!
|
462
|
-
for v in ary
|
463
|
-
stdout.printf " %s => %s\n", v, eval(v, binding).inspect
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
def display_list(b, e, file, line)
|
468
|
-
stdout.printf "[%d, %d] in %s\n", b, e, file
|
469
|
-
if lines = SCRIPT_LINES__[file] and lines != true
|
470
|
-
n = 0
|
471
|
-
b.upto(e) do |n|
|
472
|
-
if n > 0 && lines[n-1]
|
473
|
-
if n == line
|
474
|
-
stdout.printf "=> %d %s\n", n, lines[n-1].chomp
|
475
|
-
else
|
476
|
-
stdout.printf " %d %s\n", n, lines[n-1].chomp
|
477
|
-
end
|
478
|
-
end
|
479
|
-
end
|
480
|
-
else
|
481
|
-
stdout.printf "No sourcefile available for %s\n", file
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
def line_at(file, line)
|
486
|
-
lines = SCRIPT_LINES__[file]
|
487
|
-
if lines
|
488
|
-
return "\n" if lines == true
|
489
|
-
line = lines[line-1]
|
490
|
-
return "\n" unless line
|
491
|
-
return line.gsub(/^\s+/, '')
|
492
|
-
end
|
493
|
-
return "\n"
|
494
|
-
end
|
495
|
-
|
496
|
-
def display
|
497
|
-
Debugger.display
|
498
|
-
end
|
499
79
|
end
|
500
80
|
|
501
81
|
class << self
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
def display
|
519
|
-
@display
|
520
|
-
end
|
521
|
-
|
522
|
-
def debug_method_info(input, binding)
|
523
|
-
case input
|
524
|
-
when /^i(:?nstance)?\s+/
|
525
|
-
obj = debug_eval($', binding)
|
526
|
-
|
527
|
-
len = 0
|
528
|
-
for v in obj.methods.sort
|
529
|
-
len += v.size + 1
|
530
|
-
if len > 70
|
531
|
-
len = v.size + 1
|
532
|
-
stdout.print "\n"
|
533
|
-
end
|
534
|
-
stdout.print v, " "
|
535
|
-
end
|
536
|
-
stdout.print "\n"
|
537
|
-
|
538
|
-
else
|
539
|
-
obj = debug_eval(input, binding)
|
540
|
-
unless obj.kind_of? Module
|
541
|
-
stdout.print "Should be Class/Module: ", input, "\n"
|
542
|
-
else
|
543
|
-
len = 0
|
544
|
-
for v in obj.instance_methods(false).sort
|
545
|
-
len += v.size + 1
|
546
|
-
if len > 70
|
547
|
-
len = v.size + 1
|
548
|
-
stdout.print "\n"
|
549
|
-
end
|
550
|
-
stdout.print v, " "
|
551
|
-
end
|
552
|
-
stdout.print "\n"
|
553
|
-
end
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
|
-
def display_context(c)
|
558
|
-
if c.thread == Thread.current
|
559
|
-
stdout.print "+"
|
560
|
-
else
|
561
|
-
stdout.print " "
|
562
|
-
end
|
563
|
-
stdout.printf "%d ", c.thnum
|
564
|
-
stdout.print c.thread.inspect, "\t"
|
565
|
-
last_frame = c.frames.first
|
566
|
-
if last_frame
|
567
|
-
@stdout.print last_frame.file,":",last_frame.line
|
568
|
-
end
|
569
|
-
@stdout.print "\n"
|
570
|
-
end
|
571
|
-
|
572
|
-
def display_all_contexts
|
573
|
-
threads = contexts.sort_by{|c| c.thnum}.each do |c|
|
574
|
-
display_context(c)
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
def get_context(thnum)
|
579
|
-
contexts.find{|c| c.thnum = thnum}
|
580
|
-
end
|
581
|
-
|
582
|
-
def debug_thread_info(input)
|
583
|
-
case input
|
584
|
-
when /^l(?:ist)?/
|
585
|
-
display_all_contexts
|
586
|
-
|
587
|
-
when /^c(?:ur(?:rent)?)?$/
|
588
|
-
display_context(current_context)
|
589
|
-
|
590
|
-
when /^(?:sw(?:itch)?\s+)?(\d+)/
|
591
|
-
c = get_context($1.to_i)
|
592
|
-
if c == current_context
|
593
|
-
stdout.print "It's the current thread.\n"
|
594
|
-
else
|
595
|
-
display_context(c)
|
596
|
-
c.stop_next = 1
|
597
|
-
c.thread.run
|
598
|
-
return :cont
|
599
|
-
end
|
600
|
-
|
601
|
-
when /^stop\s+(\d+)/
|
602
|
-
c = get_context($1.to_i)
|
603
|
-
if c == current_context
|
604
|
-
stdout.print "It's the current thread.\n"
|
605
|
-
elsif c.thread.stop?
|
606
|
-
stdout.print "Already stopped.\n"
|
607
|
-
else
|
608
|
-
display_context(c)
|
609
|
-
c.set_suspend
|
610
|
-
end
|
611
|
-
|
612
|
-
when /^resume\s+(\d+)/
|
613
|
-
c = get_context($1.to_i)
|
614
|
-
if c == current_context
|
615
|
-
stdout.print "It's the current thread.\n"
|
616
|
-
elsif !c.thread.stop?
|
617
|
-
stdout.print "Already running."
|
618
|
-
else
|
619
|
-
display_context(c)
|
620
|
-
c.thread.run
|
82
|
+
attr_accessor :processor
|
83
|
+
attr_reader :thread
|
84
|
+
|
85
|
+
def interface=(value)
|
86
|
+
processor.interface = value
|
87
|
+
end
|
88
|
+
|
89
|
+
def start_server(host = nil, port = PORT)
|
90
|
+
return if @thread
|
91
|
+
require "socket"
|
92
|
+
|
93
|
+
server = TCPServer.new(host, port)
|
94
|
+
@thread = Thread.start do
|
95
|
+
while (session = server.accept)
|
96
|
+
interface = RemoteInterface.new(session)
|
97
|
+
self.interface = interface
|
621
98
|
end
|
622
99
|
end
|
623
100
|
end
|
@@ -628,6 +105,4 @@ module Kernel
|
|
628
105
|
def debugger(steps = 1)
|
629
106
|
Debugger.current_context.stop_next = steps
|
630
107
|
end
|
631
|
-
end
|
632
|
-
|
633
|
-
Debugger.start
|
108
|
+
end
|