debase 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +23 -0
- data/MIT_LICENSE +22 -0
- data/README +22 -0
- data/Rakefile +34 -0
- data/debase.gemspec +30 -0
- data/ext/breakpoint.c +233 -0
- data/ext/context.c +377 -0
- data/ext/debase_internals.c +427 -0
- data/ext/debase_internals.h +94 -0
- data/ext/extconf.rb +14 -0
- data/ext/locker.c +52 -0
- data/lib/debase.rb +57 -0
- data/lib/debase/context.rb +44 -0
- data/lib/debase/version.rb +3 -0
- data/test/example/a/example.rb +1 -0
- data/test/example/at-exit.rb +3 -0
- data/test/example/b/example.rb +1 -0
- data/test/example/bp_loop_issue.rb +3 -0
- data/test/example/breakpoints-basename.rb +2 -0
- data/test/example/brkpt-class-bug.rb +8 -0
- data/test/example/classes.rb +11 -0
- data/test/example/dollar-0.rb +6 -0
- data/test/example/except-bug1.rb +4 -0
- data/test/example/file with space.rb +1 -0
- data/test/example/gcd.rb +18 -0
- data/test/example/info-var-bug.rb +47 -0
- data/test/example/info-var-bug2.rb +2 -0
- data/test/example/null.rb +1 -0
- data/test/example/output.rb +2 -0
- data/test/example/pm-bug.rb +3 -0
- data/test/example/pm.rb +11 -0
- data/test/example/raise.rb +3 -0
- data/test/helper.rb +2 -0
- data/test/test_base.rb +77 -0
- data/test/test_breakpoints.rb +14 -0
- data/test/test_catchpoint.rb +19 -0
- data/test/test_load.rb +44 -0
- data/test/test_reload_bug.rb +8 -0
- metadata +142 -0
data/ext/extconf.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
# Allow use customization of compile options. For example, the
|
4
|
+
# following lines could be put in config_options to to turn off
|
5
|
+
# optimization:
|
6
|
+
# $CFLAGS='-fPIC -fno-strict-aliasing -g3 -ggdb -O2 -fPIC'
|
7
|
+
config_file = File.join(File.dirname(__FILE__), 'config_options.rb')
|
8
|
+
load config_file if File.exist?(config_file)
|
9
|
+
|
10
|
+
$CFLAGS='-Wall -Werror'
|
11
|
+
$CFLAGS+=' -g3' if ENV['debug']
|
12
|
+
|
13
|
+
dir_config("ruby")
|
14
|
+
create_makefile("debase_internals")
|
data/ext/locker.c
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#include <debase_internals.h>
|
2
|
+
static locked_thread_t *locked_head = NULL;
|
3
|
+
static locked_thread_t *locked_tail = NULL;
|
4
|
+
|
5
|
+
extern int
|
6
|
+
is_in_locked(VALUE thread)
|
7
|
+
{
|
8
|
+
locked_thread_t *node;
|
9
|
+
|
10
|
+
if(!locked_head) return 0;
|
11
|
+
|
12
|
+
for(node = locked_head; node != locked_tail; node = node->next)
|
13
|
+
{
|
14
|
+
if(node->thread == thread) return 1;
|
15
|
+
}
|
16
|
+
return 0;
|
17
|
+
}
|
18
|
+
|
19
|
+
extern void
|
20
|
+
add_to_locked(VALUE thread)
|
21
|
+
{
|
22
|
+
locked_thread_t *node;
|
23
|
+
|
24
|
+
if(is_in_locked(thread)) return;
|
25
|
+
|
26
|
+
node = ALLOC(locked_thread_t);
|
27
|
+
node->thread = thread;
|
28
|
+
node->next = NULL;
|
29
|
+
if(locked_tail)
|
30
|
+
locked_tail->next = node;
|
31
|
+
locked_tail = node;
|
32
|
+
if(!locked_head)
|
33
|
+
locked_head = node;
|
34
|
+
}
|
35
|
+
|
36
|
+
extern VALUE
|
37
|
+
remove_from_locked()
|
38
|
+
{
|
39
|
+
VALUE thread;
|
40
|
+
locked_thread_t *node;
|
41
|
+
|
42
|
+
if(locked_head == NULL)
|
43
|
+
return Qnil;
|
44
|
+
|
45
|
+
node = locked_head;
|
46
|
+
locked_head = locked_head->next;
|
47
|
+
if(locked_tail == node)
|
48
|
+
locked_tail = NULL;
|
49
|
+
thread = node->thread;
|
50
|
+
xfree(node);
|
51
|
+
return thread;
|
52
|
+
}
|
data/lib/debase.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "debase_internals"
|
2
|
+
require "debase/version"
|
3
|
+
require "debase/context"
|
4
|
+
|
5
|
+
module Debase
|
6
|
+
class << self
|
7
|
+
attr_accessor :handler
|
8
|
+
|
9
|
+
alias start_ setup_tracepoints
|
10
|
+
alias stop remove_tracepoints
|
11
|
+
|
12
|
+
# possibly deprecated options
|
13
|
+
attr_accessor :keep_frame_binding, :tracing
|
14
|
+
|
15
|
+
def start(options={}, &block)
|
16
|
+
Debugger.const_set('ARGV', ARGV.clone) unless defined? Debugger::ARGV
|
17
|
+
Debugger.const_set('PROG_SCRIPT', $0) unless defined? Debugger::PROG_SCRIPT
|
18
|
+
Debugger.const_set('INITIAL_DIR', Dir.pwd) unless defined? Debugger::INITIAL_DIR
|
19
|
+
return Debugger.started? ? block && block.call(self) : Debugger.start_(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [String] file
|
23
|
+
# @param [Fixnum] line
|
24
|
+
# @param [String] expr
|
25
|
+
def add_breakpoint(file, line, expr=nil)
|
26
|
+
breakpoint = Breakpoint.new(file, line, expr)
|
27
|
+
breakpoints << breakpoint
|
28
|
+
breakpoint
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove_breakpoint(id)
|
32
|
+
Breakpoint.remove breakpoints, id
|
33
|
+
end
|
34
|
+
|
35
|
+
def source_reload; {} end
|
36
|
+
|
37
|
+
def post_mortem?
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def debug
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_catchpoint(exception)
|
46
|
+
catchpoints[exception] = 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class DebugThread < Thread
|
51
|
+
def self.inherited
|
52
|
+
raise RuntimeError.new("Can't inherit Debugger::DebugThread class")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Debugger = Debase
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Debase
|
2
|
+
class Context
|
3
|
+
def frame_locals(frame_no=0)
|
4
|
+
result = {}
|
5
|
+
binding = frame_binding(frame_no)
|
6
|
+
locals = eval("local_variables", binding)
|
7
|
+
locals.each {|local| result[local.to_s] = eval(local.to_s, binding)}
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def frame_class(frame_no=0)
|
12
|
+
frame_self(frame_no).class
|
13
|
+
end
|
14
|
+
|
15
|
+
def frame_args_info(frame_no=0)
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def handler
|
20
|
+
Debase.handler or raise "No interface loaded"
|
21
|
+
end
|
22
|
+
|
23
|
+
def at_breakpoint(breakpoint)
|
24
|
+
handler.at_breakpoint(self, breakpoint)
|
25
|
+
end
|
26
|
+
|
27
|
+
def at_catchpoint(excpt)
|
28
|
+
handler.at_catchpoint(self, excpt)
|
29
|
+
end
|
30
|
+
|
31
|
+
def at_tracing(file, line)
|
32
|
+
@tracing_started = true if File.identical?(file, File.join(Debugger::INITIAL_DIR, Debugger::PROG_SCRIPT))
|
33
|
+
handler.at_tracing(self, file, line) if @tracing_started
|
34
|
+
end
|
35
|
+
|
36
|
+
def at_line(file, line)
|
37
|
+
handler.at_line(self, file, line)
|
38
|
+
end
|
39
|
+
|
40
|
+
def at_return(file, line)
|
41
|
+
handler.at_return(self, file, line)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
puts "a"
|
@@ -0,0 +1 @@
|
|
1
|
+
puts "b"
|
@@ -0,0 +1 @@
|
|
1
|
+
puts 'Ha!'
|
data/test/example/gcd.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class Lousy_inspect
|
2
|
+
attr_accessor :var
|
3
|
+
def inspect # An unhelpful inspect
|
4
|
+
throw "Foo" # Raises an exception
|
5
|
+
end
|
6
|
+
def initialize
|
7
|
+
@var = 'initialized'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
class Lousy_inspect_and_to_s
|
11
|
+
attr_accessor :var
|
12
|
+
def inspect # An unhelpful inspect
|
13
|
+
throw "Foo" # Raises an exception
|
14
|
+
end
|
15
|
+
def to_s # An unhelpful to_s
|
16
|
+
throw "bar" # Raises an exception
|
17
|
+
end
|
18
|
+
def initialize
|
19
|
+
@var = 'initialized' # Something to inspect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Something that will be passed objects with
|
24
|
+
# bad inspect or to_s methods
|
25
|
+
class UnsuspectingClass
|
26
|
+
@@Const = 'A constant'
|
27
|
+
@@var = 'a class variable'
|
28
|
+
def initialize(a)
|
29
|
+
@a = a # "info locals" will try to use
|
30
|
+
# inspect or to_s here
|
31
|
+
@b = 5
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def test_Lousy_inspect
|
35
|
+
x = Lousy_inspect.new
|
36
|
+
return x
|
37
|
+
end
|
38
|
+
def test_lousy_inspect_and_to_s
|
39
|
+
x = Lousy_inspect_and_to_s.new
|
40
|
+
return x
|
41
|
+
end
|
42
|
+
x = test_Lousy_inspect
|
43
|
+
y = test_lousy_inspect_and_to_s
|
44
|
+
UnsuspectingClass.new(10)
|
45
|
+
UnsuspectingClass.new(x)
|
46
|
+
UnsuspectingClass.new(y)
|
47
|
+
y = 2
|
@@ -0,0 +1 @@
|
|
1
|
+
# Nothing here. Move along.
|
data/test/example/pm.rb
ADDED
data/test/helper.rb
ADDED
data/test/test_base.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
# Some tests of Debugger module in C extension ruby_debug
|
5
|
+
class TestRubyDebug < Test::Unit::TestCase
|
6
|
+
def test_version
|
7
|
+
assert(defined?(Debugger::VERSION))
|
8
|
+
end
|
9
|
+
|
10
|
+
# test current_context
|
11
|
+
def test_current_context
|
12
|
+
assert_equal(false, Debugger.started?,
|
13
|
+
'debugger should not initially be started.')
|
14
|
+
Debugger.start_
|
15
|
+
assert(Debugger.started?,
|
16
|
+
'debugger should now be started.')
|
17
|
+
assert_equal(__LINE__, Debugger.current_context.frame_line)
|
18
|
+
assert_equal(nil, Debugger.current_context.frame_args_info,
|
19
|
+
'no frame args info.')
|
20
|
+
assert_equal(Debugger.current_context.frame_file,
|
21
|
+
Debugger.current_context.frame_file(0))
|
22
|
+
assert_equal(File.basename(__FILE__),
|
23
|
+
File.basename(Debugger.current_context.frame_file))
|
24
|
+
assert_raises(ArgumentError) {Debugger.current_context.frame_file(1, 2)}
|
25
|
+
assert_raises(ArgumentError) {Debugger.current_context.frame_file(15)}
|
26
|
+
assert_equal(1, Debugger.current_context.stack_size)
|
27
|
+
assert_equal(TestRubyDebug, Debugger.current_context.frame_class)
|
28
|
+
assert_equal(false, Debugger.current_context.dead?, 'Not dead yet!')
|
29
|
+
ensure
|
30
|
+
Debugger.stop
|
31
|
+
assert_equal(false, Debugger.started?,
|
32
|
+
'Debugger should no longer be started.')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Test initial variables and setting/getting state.
|
36
|
+
def test_debugger_base
|
37
|
+
assert_equal(false, Debugger.started?,
|
38
|
+
'Debugger should not initially be started.')
|
39
|
+
Debugger.start_
|
40
|
+
assert(Debugger.started?,
|
41
|
+
'Debugger should now be started.')
|
42
|
+
assert_equal(false, Debugger.debug,
|
43
|
+
'Debug variable should not be set.')
|
44
|
+
assert_equal(false, Debugger.post_mortem?,
|
45
|
+
'Post mortem debugging should not be set.')
|
46
|
+
a = Debugger.contexts
|
47
|
+
assert_equal(1, a.size,
|
48
|
+
'There should only be one context.')
|
49
|
+
assert_equal(Array, a.class,
|
50
|
+
'Context should be an array.')
|
51
|
+
ensure
|
52
|
+
Debugger.stop
|
53
|
+
assert_equal(false, Debugger.started?,
|
54
|
+
'debugger should no longer be started.')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Test breakpoint handling
|
58
|
+
def test_breakpoints
|
59
|
+
Debugger.start_
|
60
|
+
assert_equal(0, Debugger.breakpoints.size,
|
61
|
+
'There should not be any breakpoints set.')
|
62
|
+
brk = Debugger.add_breakpoint(__FILE__, 1)
|
63
|
+
assert_equal(Debugger::Breakpoint, brk.class,
|
64
|
+
'Breakpoint should have been set and returned.')
|
65
|
+
assert_equal(1, Debugger.breakpoints.size,
|
66
|
+
'There should now be one breakpoint set.')
|
67
|
+
Debugger.remove_breakpoint(0)
|
68
|
+
assert_equal(1, Debugger.breakpoints.size,
|
69
|
+
'There should still be one breakpoint set.')
|
70
|
+
Debugger.remove_breakpoint(brk.id)
|
71
|
+
assert_equal(0, Debugger.breakpoints.size,
|
72
|
+
'There should no longer be any breakpoints set.')
|
73
|
+
ensure
|
74
|
+
Debugger.stop
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
# Some tests of Debugger module in C extension ruby_debug
|
5
|
+
class TestBreakpoints < Test::Unit::TestCase
|
6
|
+
def test_find
|
7
|
+
Debugger.start
|
8
|
+
Debugger.add_breakpoint("foo.rb", 11, nil)
|
9
|
+
assert_not_nil(Debugger::Breakpoint.find(Debugger.breakpoints, "foo.rb", 11, binding))
|
10
|
+
assert_nil(Debugger::Breakpoint.find(Debugger.breakpoints, "bar.rb", 11, binding))
|
11
|
+
assert_nil(Debugger::Breakpoint.find(Debugger.breakpoints, "foo.rb", 10, binding))
|
12
|
+
Debugger.stop
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
# Test catchpoint in C ruby_debug extension.
|
5
|
+
|
6
|
+
class TestRubyDebugCatchpoint < Test::Unit::TestCase
|
7
|
+
def test_catchpoints
|
8
|
+
assert_raise(RuntimeError) {Debugger.catchpoints}
|
9
|
+
Debugger.start_
|
10
|
+
assert_equal({}, Debugger.catchpoints)
|
11
|
+
Debugger.add_catchpoint('ZeroDivisionError')
|
12
|
+
assert_equal({'ZeroDivisionError' => 0}, Debugger.catchpoints)
|
13
|
+
Debugger.add_catchpoint('RuntimeError')
|
14
|
+
assert_equal(['RuntimeError', 'ZeroDivisionError'],
|
15
|
+
Debugger.catchpoints.keys.sort)
|
16
|
+
ensure
|
17
|
+
Debugger.stop
|
18
|
+
end
|
19
|
+
end
|