debug 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5ef5033a78a878b42dd6850ee75552d58a0a0e02bfb890b3bf8970d9b5076387
4
+ data.tar.gz: a20c0455d990c8d74975ee9d67c327cfd9165f50a6ae32e6a69d79d6334bed56
5
+ SHA512:
6
+ metadata.gz: 8421e8a499c15e797ccced0f4f6ee2e315c9a18332db39beac30978fdcc87ac541c765fbf1c6e31b577020949421a928139dc81d3bf0ed0fcc97f7d7e2158487
7
+ data.tar.gz: bcab6869de9e3522bfa139a610ad5964121da2fd69678966fc0ab2c10d0b544d9692bbb2614e794b2df44ab7469d556fb86983be8dc6971c402c33ba816a6dc3
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in debug.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem "rake"
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Debug
2
+
3
+ This library provides debugging functionality to Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'debug'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install debug
20
+
21
+ ## Usage
22
+
23
+ To add a debugger to your code, start by requiring +debug+ in your
24
+ program:
25
+
26
+ ```ruby
27
+ def say(word)
28
+ require 'debug'
29
+ puts word
30
+ end
31
+ ```
32
+
33
+ This will cause Ruby to interrupt execution and show a prompt when the +say+
34
+ method is run.
35
+
36
+ Once you're inside the prompt, you can start debugging your program.
37
+
38
+ ```
39
+ (rdb:1) p word
40
+ "hello"
41
+ ```
42
+
43
+ ## Development
44
+
45
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
46
+
47
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hsbt/debug.
52
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "debug"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/debug.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "debug"
3
+ spec.version = "0.2.0"
4
+ spec.authors = ["Yukihiro Matsumoto"]
5
+ spec.email = ["matz@ruby-lang.org"]
6
+
7
+ spec.summary = %q{Debugging functionality for Ruby}
8
+ spec.description = %q{Debugging functionality for Ruby}
9
+ spec.homepage = "https://github.com/ruby/debug"
10
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
12
+
13
+ spec.metadata["homepage_uri"] = spec.homepage
14
+ spec.metadata["source_code_uri"] = spec.homepage
15
+
16
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+ end
data/lib/debug.rb ADDED
@@ -0,0 +1,1111 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
3
+ # Copyright (C) 2000 Information-technology Promotion Agency, Japan
4
+ # Copyright (C) 2000-2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
5
+
6
+ require 'continuation'
7
+
8
+ if $SAFE > 0
9
+ STDERR.print "-r debug.rb is not available in safe mode\n"
10
+ exit 1
11
+ end
12
+
13
+ require 'tracer'
14
+ require 'pp'
15
+
16
+ class Tracer # :nodoc:
17
+ def Tracer.trace_func(*vars)
18
+ Single.trace_func(*vars)
19
+ end
20
+ end
21
+
22
+ SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__ # :nodoc:
23
+
24
+ ##
25
+ # This library provides debugging functionality to Ruby.
26
+ #
27
+ # To add a debugger to your code, start by requiring +debug+ in your
28
+ # program:
29
+ #
30
+ # def say(word)
31
+ # require 'debug'
32
+ # puts word
33
+ # end
34
+ #
35
+ # This will cause Ruby to interrupt execution and show a prompt when the +say+
36
+ # method is run.
37
+ #
38
+ # Once you're inside the prompt, you can start debugging your program.
39
+ #
40
+ # (rdb:1) p word
41
+ # "hello"
42
+ #
43
+ # == Getting help
44
+ #
45
+ # You can get help at any time by pressing +h+.
46
+ #
47
+ # (rdb:1) h
48
+ # Debugger help v.-0.002b
49
+ # Commands
50
+ # b[reak] [file:|class:]<line|method>
51
+ # b[reak] [class.]<line|method>
52
+ # set breakpoint to some position
53
+ # wat[ch] <expression> set watchpoint to some expression
54
+ # cat[ch] (<exception>|off) set catchpoint to an exception
55
+ # b[reak] list breakpoints
56
+ # cat[ch] show catchpoint
57
+ # del[ete][ nnn] delete some or all breakpoints
58
+ # disp[lay] <expression> add expression into display expression list
59
+ # undisp[lay][ nnn] delete one particular or all display expressions
60
+ # c[ont] run until program ends or hit breakpoint
61
+ # s[tep][ nnn] step (into methods) one line or till line nnn
62
+ # n[ext][ nnn] go over one line or till line nnn
63
+ # w[here] display frames
64
+ # f[rame] alias for where
65
+ # l[ist][ (-|nn-mm)] list program, - lists backwards
66
+ # nn-mm lists given lines
67
+ # up[ nn] move to higher frame
68
+ # down[ nn] move to lower frame
69
+ # fin[ish] return to outer frame
70
+ # tr[ace] (on|off) set trace mode of current thread
71
+ # tr[ace] (on|off) all set trace mode of all threads
72
+ # q[uit] exit from debugger
73
+ # v[ar] g[lobal] show global variables
74
+ # v[ar] l[ocal] show local variables
75
+ # v[ar] i[nstance] <object> show instance variables of object
76
+ # v[ar] c[onst] <object> show constants of object
77
+ # m[ethod] i[nstance] <obj> show methods of object
78
+ # m[ethod] <class|module> show instance methods of class or module
79
+ # th[read] l[ist] list all threads
80
+ # th[read] c[ur[rent]] show current thread
81
+ # th[read] [sw[itch]] <nnn> switch thread context to nnn
82
+ # th[read] stop <nnn> stop thread nnn
83
+ # th[read] resume <nnn> resume thread nnn
84
+ # p expression evaluate expression and print its value
85
+ # h[elp] print this help
86
+ # <everything else> evaluate
87
+ #
88
+ # == Usage
89
+ #
90
+ # The following is a list of common functionalities that the debugger
91
+ # provides.
92
+ #
93
+ # === Navigating through your code
94
+ #
95
+ # In general, a debugger is used to find bugs in your program, which
96
+ # often means pausing execution and inspecting variables at some point
97
+ # in time.
98
+ #
99
+ # Let's look at an example:
100
+ #
101
+ # def my_method(foo)
102
+ # require 'debug'
103
+ # foo = get_foo if foo.nil?
104
+ # raise if foo.nil?
105
+ # end
106
+ #
107
+ # When you run this program, the debugger will kick in just before the
108
+ # +foo+ assignment.
109
+ #
110
+ # (rdb:1) p foo
111
+ # nil
112
+ #
113
+ # In this example, it'd be interesting to move to the next line and
114
+ # inspect the value of +foo+ again. You can do that by pressing +n+:
115
+ #
116
+ # (rdb:1) n # goes to next line
117
+ # (rdb:1) p foo
118
+ # nil
119
+ #
120
+ # You now know that the original value of +foo+ was nil, and that it
121
+ # still was nil after calling +get_foo+.
122
+ #
123
+ # Other useful commands for navigating through your code are:
124
+ #
125
+ # +c+::
126
+ # Runs the program until it either exists or encounters another breakpoint.
127
+ # You usually press +c+ when you are finished debugging your program and
128
+ # want to resume its execution.
129
+ # +s+::
130
+ # Steps into method definition. In the previous example, +s+ would take you
131
+ # inside the method definition of +get_foo+.
132
+ # +r+::
133
+ # Restart the program.
134
+ # +q+::
135
+ # Quit the program.
136
+ #
137
+ # === Inspecting variables
138
+ #
139
+ # You can use the debugger to easily inspect both local and global variables.
140
+ # We've seen how to inspect local variables before:
141
+ #
142
+ # (rdb:1) p my_arg
143
+ # 42
144
+ #
145
+ # You can also pretty print the result of variables or expressions:
146
+ #
147
+ # (rdb:1) pp %w{a very long long array containing many words}
148
+ # ["a",
149
+ # "very",
150
+ # "long",
151
+ # ...
152
+ # ]
153
+ #
154
+ # You can list all local variables with +v l+:
155
+ #
156
+ # (rdb:1) v l
157
+ # foo => "hello"
158
+ #
159
+ # Similarly, you can show all global variables with +v g+:
160
+ #
161
+ # (rdb:1) v g
162
+ # all global variables
163
+ #
164
+ # Finally, you can omit +p+ if you simply want to evaluate a variable or
165
+ # expression
166
+ #
167
+ # (rdb:1) 5**2
168
+ # 25
169
+ #
170
+ # === Going beyond basics
171
+ #
172
+ # Ruby Debug provides more advanced functionalities like switching
173
+ # between threads, setting breakpoints and watch expressions, and more.
174
+ # The full list of commands is available at any time by pressing +h+.
175
+ #
176
+ # == Staying out of trouble
177
+ #
178
+ # Make sure you remove every instance of +require 'debug'+ before
179
+ # shipping your code. Failing to do so may result in your program
180
+ # hanging unpredictably.
181
+ #
182
+ # Debug is not available in safe mode.
183
+
184
+ class DEBUGGER__
185
+ MUTEX = Thread::Mutex.new # :nodoc:
186
+
187
+ class Context # :nodoc:
188
+ DEBUG_LAST_CMD = []
189
+
190
+ begin
191
+ require 'readline'
192
+ def readline(prompt, hist)
193
+ Readline::readline(prompt, hist)
194
+ end
195
+ rescue LoadError
196
+ def readline(prompt, hist)
197
+ STDOUT.print prompt
198
+ STDOUT.flush
199
+ line = STDIN.gets
200
+ exit unless line
201
+ line.chomp!
202
+ line
203
+ end
204
+ USE_READLINE = false
205
+ end
206
+
207
+ def initialize
208
+ if Thread.current == Thread.main
209
+ @stop_next = 1
210
+ else
211
+ @stop_next = 0
212
+ end
213
+ @last_file = nil
214
+ @file = nil
215
+ @line = nil
216
+ @no_step = nil
217
+ @frames = []
218
+ @finish_pos = 0
219
+ @trace = false
220
+ @catch = "StandardError"
221
+ @suspend_next = false
222
+ end
223
+
224
+ def stop_next(n=1)
225
+ @stop_next = n
226
+ end
227
+
228
+ def set_suspend
229
+ @suspend_next = true
230
+ end
231
+
232
+ def clear_suspend
233
+ @suspend_next = false
234
+ end
235
+
236
+ def suspend_all
237
+ DEBUGGER__.suspend
238
+ end
239
+
240
+ def resume_all
241
+ DEBUGGER__.resume
242
+ end
243
+
244
+ def check_suspend
245
+ while MUTEX.synchronize {
246
+ if @suspend_next
247
+ DEBUGGER__.waiting.push Thread.current
248
+ @suspend_next = false
249
+ true
250
+ end
251
+ }
252
+ end
253
+ end
254
+
255
+ def trace?
256
+ @trace
257
+ end
258
+
259
+ def set_trace(arg)
260
+ @trace = arg
261
+ end
262
+
263
+ def stdout
264
+ DEBUGGER__.stdout
265
+ end
266
+
267
+ def break_points
268
+ DEBUGGER__.break_points
269
+ end
270
+
271
+ def display
272
+ DEBUGGER__.display
273
+ end
274
+
275
+ def context(th)
276
+ DEBUGGER__.context(th)
277
+ end
278
+
279
+ def set_trace_all(arg)
280
+ DEBUGGER__.set_trace(arg)
281
+ end
282
+
283
+ def set_last_thread(th)
284
+ DEBUGGER__.set_last_thread(th)
285
+ end
286
+
287
+ def debug_eval(str, binding)
288
+ begin
289
+ eval(str, binding)
290
+ rescue StandardError, ScriptError => e
291
+ at = eval("caller(1)", binding)
292
+ stdout.printf "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
293
+ for i in at
294
+ stdout.printf "\tfrom %s\n", i
295
+ end
296
+ throw :debug_error
297
+ end
298
+ end
299
+
300
+ def debug_silent_eval(str, binding)
301
+ begin
302
+ eval(str, binding)
303
+ rescue StandardError, ScriptError
304
+ nil
305
+ end
306
+ end
307
+
308
+ def var_list(ary, binding)
309
+ ary.sort!
310
+ for v in ary
311
+ stdout.printf " %s => %s\n", v, eval(v.to_s, binding).inspect
312
+ end
313
+ end
314
+
315
+ def debug_variable_info(input, binding)
316
+ case input
317
+ when /^\s*g(?:lobal)?\s*$/
318
+ var_list(global_variables, binding)
319
+
320
+ when /^\s*l(?:ocal)?\s*$/
321
+ var_list(eval("local_variables", binding), binding)
322
+
323
+ when /^\s*i(?:nstance)?\s+/
324
+ obj = debug_eval($', binding)
325
+ var_list(obj.instance_variables, obj.instance_eval{binding()})
326
+
327
+ when /^\s*c(?:onst(?:ant)?)?\s+/
328
+ obj = debug_eval($', binding)
329
+ unless obj.kind_of? Module
330
+ stdout.print "Should be Class/Module: ", $', "\n"
331
+ else
332
+ var_list(obj.constants, obj.module_eval{binding()})
333
+ end
334
+ end
335
+ end
336
+
337
+ def debug_method_info(input, binding)
338
+ case input
339
+ when /^i(:?nstance)?\s+/
340
+ obj = debug_eval($', binding)
341
+
342
+ len = 0
343
+ for v in obj.methods.sort
344
+ len += v.size + 1
345
+ if len > 70
346
+ len = v.size + 1
347
+ stdout.print "\n"
348
+ end
349
+ stdout.print v, " "
350
+ end
351
+ stdout.print "\n"
352
+
353
+ else
354
+ obj = debug_eval(input, binding)
355
+ unless obj.kind_of? Module
356
+ stdout.print "Should be Class/Module: ", input, "\n"
357
+ else
358
+ len = 0
359
+ for v in obj.instance_methods(false).sort
360
+ len += v.size + 1
361
+ if len > 70
362
+ len = v.size + 1
363
+ stdout.print "\n"
364
+ end
365
+ stdout.print v, " "
366
+ end
367
+ stdout.print "\n"
368
+ end
369
+ end
370
+ end
371
+
372
+ def thnum
373
+ num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
374
+ unless num
375
+ DEBUGGER__.make_thread_list
376
+ num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
377
+ end
378
+ num
379
+ end
380
+
381
+ def debug_command(file, line, id, binding)
382
+ MUTEX.lock
383
+ unless defined?($debugger_restart) and $debugger_restart
384
+ callcc{|c| $debugger_restart = c}
385
+ end
386
+ set_last_thread(Thread.current)
387
+ frame_pos = 0
388
+ binding_file = file
389
+ binding_line = line
390
+ previous_line = nil
391
+ if ENV['EMACS']
392
+ stdout.printf "\032\032%s:%d:\n", binding_file, binding_line
393
+ else
394
+ stdout.printf "%s:%d:%s", binding_file, binding_line,
395
+ line_at(binding_file, binding_line)
396
+ end
397
+ @frames[0] = [binding, file, line, id]
398
+ display_expressions(binding)
399
+ prompt = true
400
+ while prompt and input = readline("(rdb:%d) "%thnum(), true)
401
+ catch(:debug_error) do
402
+ if input == ""
403
+ next unless DEBUG_LAST_CMD[0]
404
+ input = DEBUG_LAST_CMD[0]
405
+ stdout.print input, "\n"
406
+ else
407
+ DEBUG_LAST_CMD[0] = input
408
+ end
409
+
410
+ case input
411
+ when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
412
+ if defined?( $2 )
413
+ if $1 == 'on'
414
+ set_trace_all true
415
+ else
416
+ set_trace_all false
417
+ end
418
+ elsif defined?( $1 )
419
+ if $1 == 'on'
420
+ set_trace true
421
+ else
422
+ set_trace false
423
+ end
424
+ end
425
+ if trace?
426
+ stdout.print "Trace on.\n"
427
+ else
428
+ stdout.print "Trace off.\n"
429
+ end
430
+
431
+ when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:]+)$/
432
+ pos = $2
433
+ if $1
434
+ klass = debug_silent_eval($1, binding)
435
+ file = $1
436
+ end
437
+ if pos =~ /^\d+$/
438
+ pname = pos
439
+ pos = pos.to_i
440
+ else
441
+ pname = pos = pos.intern.id2name
442
+ end
443
+ break_points.push [true, 0, klass || file, pos]
444
+ stdout.printf "Set breakpoint %d at %s:%s\n", break_points.size, klass || file, pname
445
+
446
+ when /^\s*b(?:reak)?\s+(.+)[#.]([^.:]+)$/
447
+ pos = $2.intern.id2name
448
+ klass = debug_eval($1, binding)
449
+ break_points.push [true, 0, klass, pos]
450
+ stdout.printf "Set breakpoint %d at %s.%s\n", break_points.size, klass, pos
451
+
452
+ when /^\s*wat(?:ch)?\s+(.+)$/
453
+ exp = $1
454
+ break_points.push [true, 1, exp]
455
+ stdout.printf "Set watchpoint %d:%s\n", break_points.size, exp
456
+
457
+ when /^\s*b(?:reak)?$/
458
+ if break_points.find{|b| b[1] == 0}
459
+ n = 1
460
+ stdout.print "Breakpoints:\n"
461
+ break_points.each do |b|
462
+ if b[0] and b[1] == 0
463
+ stdout.printf " %d %s:%s\n", n, b[2], b[3]
464
+ end
465
+ n += 1
466
+ end
467
+ end
468
+ if break_points.find{|b| b[1] == 1}
469
+ n = 1
470
+ stdout.print "\n"
471
+ stdout.print "Watchpoints:\n"
472
+ for b in break_points
473
+ if b[0] and b[1] == 1
474
+ stdout.printf " %d %s\n", n, b[2]
475
+ end
476
+ n += 1
477
+ end
478
+ end
479
+ if break_points.size == 0
480
+ stdout.print "No breakpoints\n"
481
+ else
482
+ stdout.print "\n"
483
+ end
484
+
485
+ when /^\s*del(?:ete)?(?:\s+(\d+))?$/
486
+ pos = $1
487
+ unless pos
488
+ input = readline("Clear all breakpoints? (y/n) ", false)
489
+ if input == "y"
490
+ for b in break_points
491
+ b[0] = false
492
+ end
493
+ end
494
+ else
495
+ pos = pos.to_i
496
+ if break_points[pos-1]
497
+ break_points[pos-1][0] = false
498
+ else
499
+ stdout.printf "Breakpoint %d is not defined\n", pos
500
+ end
501
+ end
502
+
503
+ when /^\s*disp(?:lay)?\s+(.+)$/
504
+ exp = $1
505
+ display.push [true, exp]
506
+ stdout.printf "%d: ", display.size
507
+ display_expression(exp, binding)
508
+
509
+ when /^\s*disp(?:lay)?$/
510
+ display_expressions(binding)
511
+
512
+ when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
513
+ pos = $1
514
+ unless pos
515
+ input = readline("Clear all expressions? (y/n) ", false)
516
+ if input == "y"
517
+ for d in display
518
+ d[0] = false
519
+ end
520
+ end
521
+ else
522
+ pos = pos.to_i
523
+ if display[pos-1]
524
+ display[pos-1][0] = false
525
+ else
526
+ stdout.printf "Display expression %d is not defined\n", pos
527
+ end
528
+ end
529
+
530
+ when /^\s*c(?:ont)?$/
531
+ prompt = false
532
+
533
+ when /^\s*s(?:tep)?(?:\s+(\d+))?$/
534
+ if $1
535
+ lev = $1.to_i
536
+ else
537
+ lev = 1
538
+ end
539
+ @stop_next = lev
540
+ prompt = false
541
+
542
+ when /^\s*n(?:ext)?(?:\s+(\d+))?$/
543
+ if $1
544
+ lev = $1.to_i
545
+ else
546
+ lev = 1
547
+ end
548
+ @stop_next = lev
549
+ @no_step = @frames.size - frame_pos
550
+ prompt = false
551
+
552
+ when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
553
+ display_frames(frame_pos)
554
+
555
+ when /^\s*l(?:ist)?(?:\s+(.+))?$/
556
+ if not $1
557
+ b = previous_line ? previous_line + 10 : binding_line - 5
558
+ e = b + 9
559
+ elsif $1 == '-'
560
+ b = previous_line ? previous_line - 10 : binding_line - 5
561
+ e = b + 9
562
+ else
563
+ b, e = $1.split(/[-,]/)
564
+ if e
565
+ b = b.to_i
566
+ e = e.to_i
567
+ else
568
+ b = b.to_i - 5
569
+ e = b + 9
570
+ end
571
+ end
572
+ previous_line = b
573
+ display_list(b, e, binding_file, binding_line)
574
+
575
+ when /^\s*up(?:\s+(\d+))?$/
576
+ previous_line = nil
577
+ if $1
578
+ lev = $1.to_i
579
+ else
580
+ lev = 1
581
+ end
582
+ frame_pos += lev
583
+ if frame_pos >= @frames.size
584
+ frame_pos = @frames.size - 1
585
+ stdout.print "At toplevel\n"
586
+ end
587
+ binding, binding_file, binding_line = @frames[frame_pos]
588
+ stdout.print format_frame(frame_pos)
589
+
590
+ when /^\s*down(?:\s+(\d+))?$/
591
+ previous_line = nil
592
+ if $1
593
+ lev = $1.to_i
594
+ else
595
+ lev = 1
596
+ end
597
+ frame_pos -= lev
598
+ if frame_pos < 0
599
+ frame_pos = 0
600
+ stdout.print "At stack bottom\n"
601
+ end
602
+ binding, binding_file, binding_line = @frames[frame_pos]
603
+ stdout.print format_frame(frame_pos)
604
+
605
+ when /^\s*fin(?:ish)?$/
606
+ if frame_pos == @frames.size
607
+ stdout.print "\"finish\" not meaningful in the outermost frame.\n"
608
+ else
609
+ @finish_pos = @frames.size - frame_pos
610
+ frame_pos = 0
611
+ prompt = false
612
+ end
613
+
614
+ when /^\s*cat(?:ch)?(?:\s+(.+))?$/
615
+ if $1
616
+ excn = $1
617
+ if excn == 'off'
618
+ @catch = nil
619
+ stdout.print "Clear catchpoint.\n"
620
+ else
621
+ @catch = excn
622
+ stdout.printf "Set catchpoint %s.\n", @catch
623
+ end
624
+ else
625
+ if @catch
626
+ stdout.printf "Catchpoint %s.\n", @catch
627
+ else
628
+ stdout.print "No catchpoint.\n"
629
+ end
630
+ end
631
+
632
+ when /^\s*q(?:uit)?$/
633
+ input = readline("Really quit? (y/n) ", false)
634
+ if input == "y"
635
+ exit! # exit -> exit!: No graceful way to stop threads...
636
+ end
637
+
638
+ when /^\s*v(?:ar)?\s+/
639
+ debug_variable_info($', binding)
640
+
641
+ when /^\s*m(?:ethod)?\s+/
642
+ debug_method_info($', binding)
643
+
644
+ when /^\s*th(?:read)?\s+/
645
+ if DEBUGGER__.debug_thread_info($', binding) == :cont
646
+ prompt = false
647
+ end
648
+
649
+ when /^\s*pp\s+/
650
+ PP.pp(debug_eval($', binding), stdout)
651
+
652
+ when /^\s*p\s+/
653
+ stdout.printf "%s\n", debug_eval($', binding).inspect
654
+
655
+ when /^\s*r(?:estart)?$/
656
+ $debugger_restart.call
657
+
658
+ when /^\s*h(?:elp)?$/
659
+ debug_print_help()
660
+
661
+ else
662
+ v = debug_eval(input, binding)
663
+ stdout.printf "%s\n", v.inspect
664
+ end
665
+ end
666
+ end
667
+ MUTEX.unlock
668
+ resume_all
669
+ end
670
+
671
+ def debug_print_help
672
+ stdout.print <<EOHELP
673
+ Debugger help v.-0.002b
674
+ Commands
675
+ b[reak] [file:|class:]<line|method>
676
+ b[reak] [class.]<line|method>
677
+ set breakpoint to some position
678
+ wat[ch] <expression> set watchpoint to some expression
679
+ cat[ch] (<exception>|off) set catchpoint to an exception
680
+ b[reak] list breakpoints
681
+ cat[ch] show catchpoint
682
+ del[ete][ nnn] delete some or all breakpoints
683
+ disp[lay] <expression> add expression into display expression list
684
+ undisp[lay][ nnn] delete one particular or all display expressions
685
+ c[ont] run until program ends or hit breakpoint
686
+ s[tep][ nnn] step (into methods) one line or till line nnn
687
+ n[ext][ nnn] go over one line or till line nnn
688
+ w[here] display frames
689
+ f[rame] alias for where
690
+ l[ist][ (-|nn-mm)] list program, - lists backwards
691
+ nn-mm lists given lines
692
+ up[ nn] move to higher frame
693
+ down[ nn] move to lower frame
694
+ fin[ish] return to outer frame
695
+ tr[ace] (on|off) set trace mode of current thread
696
+ tr[ace] (on|off) all set trace mode of all threads
697
+ q[uit] exit from debugger
698
+ v[ar] g[lobal] show global variables
699
+ v[ar] l[ocal] show local variables
700
+ v[ar] i[nstance] <object> show instance variables of object
701
+ v[ar] c[onst] <object> show constants of object
702
+ m[ethod] i[nstance] <obj> show methods of object
703
+ m[ethod] <class|module> show instance methods of class or module
704
+ th[read] l[ist] list all threads
705
+ th[read] c[ur[rent]] show current thread
706
+ th[read] [sw[itch]] <nnn> switch thread context to nnn
707
+ th[read] stop <nnn> stop thread nnn
708
+ th[read] resume <nnn> resume thread nnn
709
+ pp expression evaluate expression and pretty_print its value
710
+ p expression evaluate expression and print its value
711
+ r[estart] restart program
712
+ h[elp] print this help
713
+ <everything else> evaluate
714
+ EOHELP
715
+ end
716
+
717
+ def display_expressions(binding)
718
+ n = 1
719
+ for d in display
720
+ if d[0]
721
+ stdout.printf "%d: ", n
722
+ display_expression(d[1], binding)
723
+ end
724
+ n += 1
725
+ end
726
+ end
727
+
728
+ def display_expression(exp, binding)
729
+ stdout.printf "%s = %s\n", exp, debug_silent_eval(exp, binding).to_s
730
+ end
731
+
732
+ def frame_set_pos(file, line)
733
+ if @frames[0]
734
+ @frames[0][1] = file
735
+ @frames[0][2] = line
736
+ end
737
+ end
738
+
739
+ def display_frames(pos)
740
+ 0.upto(@frames.size - 1) do |n|
741
+ if n == pos
742
+ stdout.print "--> "
743
+ else
744
+ stdout.print " "
745
+ end
746
+ stdout.print format_frame(n)
747
+ end
748
+ end
749
+
750
+ def format_frame(pos)
751
+ _, file, line, id = @frames[pos]
752
+ sprintf "#%d %s:%s%s\n", pos + 1, file, line,
753
+ (id ? ":in `#{id.id2name}'" : "")
754
+ end
755
+
756
+ def script_lines(file, line)
757
+ unless (lines = SCRIPT_LINES__[file]) and lines != true
758
+ Tracer::Single.get_line(file, line) if File.exist?(file)
759
+ lines = SCRIPT_LINES__[file]
760
+ lines = nil if lines == true
761
+ end
762
+ lines
763
+ end
764
+
765
+ def display_list(b, e, file, line)
766
+ if lines = script_lines(file, line)
767
+ stdout.printf "[%d, %d] in %s\n", b, e, file
768
+ b.upto(e) do |n|
769
+ if n > 0 && lines[n-1]
770
+ if n == line
771
+ stdout.printf "=> %d %s\n", n, lines[n-1].chomp
772
+ else
773
+ stdout.printf " %d %s\n", n, lines[n-1].chomp
774
+ end
775
+ end
776
+ end
777
+ else
778
+ stdout.printf "No sourcefile available for %s\n", file
779
+ end
780
+ end
781
+
782
+ def line_at(file, line)
783
+ lines = script_lines(file, line)
784
+ if lines and line = lines[line-1]
785
+ return line
786
+ end
787
+ return "\n"
788
+ end
789
+
790
+ def debug_funcname(id)
791
+ if id.nil?
792
+ "toplevel"
793
+ else
794
+ id.id2name
795
+ end
796
+ end
797
+
798
+ def check_break_points(file, klass, pos, binding, id)
799
+ return false if break_points.empty?
800
+ n = 1
801
+ for b in break_points
802
+ if b[0] # valid
803
+ if b[1] == 0 # breakpoint
804
+ if (b[2] == file and b[3] == pos) or
805
+ (klass and b[2] == klass and b[3] == pos)
806
+ stdout.printf "Breakpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
807
+ return true
808
+ end
809
+ elsif b[1] == 1 # watchpoint
810
+ if debug_silent_eval(b[2], binding)
811
+ stdout.printf "Watchpoint %d, %s at %s:%s\n", n, debug_funcname(id), file, pos
812
+ return true
813
+ end
814
+ end
815
+ end
816
+ n += 1
817
+ end
818
+ return false
819
+ end
820
+
821
+ def excn_handle(file, line, id, binding)
822
+ if $!.class <= SystemExit
823
+ set_trace_func nil
824
+ exit
825
+ end
826
+
827
+ if @catch and ($!.class.ancestors.find { |e| e.to_s == @catch })
828
+ stdout.printf "%s:%d: `%s' (%s)\n", file, line, $!, $!.class
829
+ fs = @frames.size
830
+ tb = caller(0)[-fs..-1]
831
+ if tb
832
+ for i in tb
833
+ stdout.printf "\tfrom %s\n", i
834
+ end
835
+ end
836
+ suspend_all
837
+ debug_command(file, line, id, binding)
838
+ end
839
+ end
840
+
841
+ def trace_func(event, file, line, id, binding, klass)
842
+ Tracer.trace_func(event, file, line, id, binding, klass) if trace?
843
+ context(Thread.current).check_suspend
844
+ @file = file
845
+ @line = line
846
+ case event
847
+ when 'line'
848
+ frame_set_pos(file, line)
849
+ if !@no_step or @frames.size == @no_step
850
+ @stop_next -= 1
851
+ @stop_next = -1 if @stop_next < 0
852
+ elsif @frames.size < @no_step
853
+ @stop_next = 0 # break here before leaving...
854
+ else
855
+ # nothing to do. skipped.
856
+ end
857
+ if @stop_next == 0 or check_break_points(file, nil, line, binding, id)
858
+ @no_step = nil
859
+ suspend_all
860
+ debug_command(file, line, id, binding)
861
+ end
862
+
863
+ when 'call'
864
+ @frames.unshift [binding, file, line, id]
865
+ if check_break_points(file, klass, id.id2name, binding, id)
866
+ suspend_all
867
+ debug_command(file, line, id, binding)
868
+ end
869
+
870
+ when 'c-call'
871
+ frame_set_pos(file, line)
872
+
873
+ when 'class'
874
+ @frames.unshift [binding, file, line, id]
875
+
876
+ when 'return', 'end'
877
+ if @frames.size == @finish_pos
878
+ @stop_next = 1
879
+ @finish_pos = 0
880
+ end
881
+ @frames.shift
882
+
883
+ when 'raise'
884
+ excn_handle(file, line, id, binding)
885
+
886
+ end
887
+ @last_file = file
888
+ end
889
+ end
890
+
891
+ trap("INT") { DEBUGGER__.interrupt }
892
+ @last_thread = Thread::main
893
+ @max_thread = 1
894
+ @thread_list = {Thread::main => 1}
895
+ @break_points = []
896
+ @display = []
897
+ @waiting = []
898
+ @stdout = STDOUT
899
+
900
+ class << DEBUGGER__
901
+ # Returns the IO used as stdout. Defaults to STDOUT
902
+ def stdout
903
+ @stdout
904
+ end
905
+
906
+ # Sets the IO used as stdout. Defaults to STDOUT
907
+ def stdout=(s)
908
+ @stdout = s
909
+ end
910
+
911
+ # Returns the display expression list
912
+ #
913
+ # See DEBUGGER__ for more usage
914
+ def display
915
+ @display
916
+ end
917
+
918
+ # Returns the list of break points where execution will be stopped.
919
+ #
920
+ # See DEBUGGER__ for more usage
921
+ def break_points
922
+ @break_points
923
+ end
924
+
925
+ # Returns the list of waiting threads.
926
+ #
927
+ # When stepping through the traces of a function, thread gets suspended, to
928
+ # be resumed later.
929
+ def waiting
930
+ @waiting
931
+ end
932
+
933
+ def set_trace( arg )
934
+ MUTEX.synchronize do
935
+ make_thread_list
936
+ for th, in @thread_list
937
+ context(th).set_trace arg
938
+ end
939
+ end
940
+ arg
941
+ end
942
+
943
+ def set_last_thread(th)
944
+ @last_thread = th
945
+ end
946
+
947
+ def suspend
948
+ MUTEX.synchronize do
949
+ make_thread_list
950
+ for th, in @thread_list
951
+ next if th == Thread.current
952
+ context(th).set_suspend
953
+ end
954
+ end
955
+ # Schedule other threads to suspend as soon as possible.
956
+ Thread.pass
957
+ end
958
+
959
+ def resume
960
+ MUTEX.synchronize do
961
+ make_thread_list
962
+ @thread_list.each do |th,|
963
+ next if th == Thread.current
964
+ context(th).clear_suspend
965
+ end
966
+ waiting.each do |th|
967
+ th.run
968
+ end
969
+ waiting.clear
970
+ end
971
+ # Schedule other threads to restart as soon as possible.
972
+ Thread.pass
973
+ end
974
+
975
+ def context(thread=Thread.current)
976
+ c = thread[:__debugger_data__]
977
+ unless c
978
+ thread[:__debugger_data__] = c = Context.new
979
+ end
980
+ c
981
+ end
982
+
983
+ def interrupt
984
+ context(@last_thread).stop_next
985
+ end
986
+
987
+ def get_thread(num)
988
+ th = @thread_list.key(num)
989
+ unless th
990
+ @stdout.print "No thread ##{num}\n"
991
+ throw :debug_error
992
+ end
993
+ th
994
+ end
995
+
996
+ def thread_list(num)
997
+ th = get_thread(num)
998
+ if th == Thread.current
999
+ @stdout.print "+"
1000
+ else
1001
+ @stdout.print " "
1002
+ end
1003
+ @stdout.printf "%d ", num
1004
+ @stdout.print th.inspect, "\t"
1005
+ file = context(th).instance_eval{@file}
1006
+ if file
1007
+ @stdout.print file,":",context(th).instance_eval{@line}
1008
+ end
1009
+ @stdout.print "\n"
1010
+ end
1011
+
1012
+ # Prints all threads in @thread_list to @stdout. Returns a sorted array of
1013
+ # values from the @thread_list hash.
1014
+ #
1015
+ # While in the debugger you can list all of
1016
+ # the threads with: <b>DEBUGGER__.thread_list_all</b>
1017
+ #
1018
+ # (rdb:1) DEBUGGER__.thread_list_all
1019
+ # +1 #<Thread:0x007fb2320c03f0 run> debug_me.rb.rb:3
1020
+ # 2 #<Thread:0x007fb23218a538@debug_me.rb.rb:3 sleep>
1021
+ # 3 #<Thread:0x007fb23218b0f0@debug_me.rb.rb:3 sleep>
1022
+ # [1, 2, 3]
1023
+ #
1024
+ # Your current thread is indicated by a <b>+</b>
1025
+ #
1026
+ # Additionally you can list all threads with <b>th l</b>
1027
+ #
1028
+ # (rdb:1) th l
1029
+ # +1 #<Thread:0x007f99328c0410 run> debug_me.rb:3
1030
+ # 2 #<Thread:0x007f9932938230@debug_me.rb:3 sleep> debug_me.rb:3
1031
+ # 3 #<Thread:0x007f9932938e10@debug_me.rb:3 sleep> debug_me.rb:3
1032
+ #
1033
+ # See DEBUGGER__ for more usage.
1034
+
1035
+ def thread_list_all
1036
+ for th in @thread_list.values.sort
1037
+ thread_list(th)
1038
+ end
1039
+ end
1040
+
1041
+ def make_thread_list
1042
+ hash = {}
1043
+ for th in Thread::list
1044
+ if @thread_list.key? th
1045
+ hash[th] = @thread_list[th]
1046
+ else
1047
+ @max_thread += 1
1048
+ hash[th] = @max_thread
1049
+ end
1050
+ end
1051
+ @thread_list = hash
1052
+ end
1053
+
1054
+ def debug_thread_info(input, binding)
1055
+ case input
1056
+ when /^l(?:ist)?/
1057
+ make_thread_list
1058
+ thread_list_all
1059
+
1060
+ when /^c(?:ur(?:rent)?)?$/
1061
+ make_thread_list
1062
+ thread_list(@thread_list[Thread.current])
1063
+
1064
+ when /^(?:sw(?:itch)?\s+)?(\d+)/
1065
+ make_thread_list
1066
+ th = get_thread($1.to_i)
1067
+ if th == Thread.current
1068
+ @stdout.print "It's the current thread.\n"
1069
+ else
1070
+ thread_list(@thread_list[th])
1071
+ context(th).stop_next
1072
+ th.run
1073
+ return :cont
1074
+ end
1075
+
1076
+ when /^stop\s+(\d+)/
1077
+ make_thread_list
1078
+ th = get_thread($1.to_i)
1079
+ if th == Thread.current
1080
+ @stdout.print "It's the current thread.\n"
1081
+ elsif th.stop?
1082
+ @stdout.print "Already stopped.\n"
1083
+ else
1084
+ thread_list(@thread_list[th])
1085
+ context(th).suspend
1086
+ end
1087
+
1088
+ when /^resume\s+(\d+)/
1089
+ make_thread_list
1090
+ th = get_thread($1.to_i)
1091
+ if th == Thread.current
1092
+ @stdout.print "It's the current thread.\n"
1093
+ elsif !th.stop?
1094
+ @stdout.print "Already running."
1095
+ else
1096
+ thread_list(@thread_list[th])
1097
+ th.run
1098
+ end
1099
+ end
1100
+ end
1101
+ end
1102
+
1103
+ stdout.printf "Debug.rb\n"
1104
+ stdout.printf "Emacs support available.\n\n"
1105
+ RubyVM::InstructionSequence.compile_option = {
1106
+ trace_instruction: true
1107
+ }
1108
+ set_trace_func proc { |event, file, line, id, binding, klass, *rest|
1109
+ DEBUGGER__.context.trace_func event, file, line, id, binding, klass
1110
+ }
1111
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: debug
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Yukihiro Matsumoto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-03-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Debugging functionality for Ruby
14
+ email:
15
+ - matz@ruby-lang.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - Gemfile
22
+ - LICENSE.txt
23
+ - README.md
24
+ - Rakefile
25
+ - bin/console
26
+ - bin/setup
27
+ - debug.gemspec
28
+ - lib/debug.rb
29
+ homepage: https://github.com/ruby/debug
30
+ licenses:
31
+ - Ruby
32
+ - BSD-2-Clause
33
+ metadata:
34
+ homepage_uri: https://github.com/ruby/debug
35
+ source_code_uri: https://github.com/ruby/debug
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 2.3.0
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubygems_version: 3.2.14
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Debugging functionality for Ruby
55
+ test_files: []