byebug 11.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +897 -0
- data/CONTRIBUTING.md +58 -0
- data/GUIDE.md +1806 -0
- data/LICENSE +23 -0
- data/README.md +199 -0
- data/exe/byebug +6 -0
- data/ext/byebug/breakpoint.c +517 -0
- data/ext/byebug/byebug.c +905 -0
- data/ext/byebug/byebug.h +143 -0
- data/ext/byebug/context.c +673 -0
- data/ext/byebug/extconf.rb +12 -0
- data/ext/byebug/locker.c +96 -0
- data/ext/byebug/threads.c +230 -0
- data/lib/byebug.rb +3 -0
- data/lib/byebug/attacher.rb +48 -0
- data/lib/byebug/breakpoint.rb +111 -0
- data/lib/byebug/command.rb +111 -0
- data/lib/byebug/command_list.rb +34 -0
- data/lib/byebug/commands.rb +40 -0
- data/lib/byebug/commands/break.rb +112 -0
- data/lib/byebug/commands/catch.rb +78 -0
- data/lib/byebug/commands/condition.rb +55 -0
- data/lib/byebug/commands/continue.rb +68 -0
- data/lib/byebug/commands/debug.rb +38 -0
- data/lib/byebug/commands/delete.rb +55 -0
- data/lib/byebug/commands/disable.rb +33 -0
- data/lib/byebug/commands/disable/breakpoints.rb +42 -0
- data/lib/byebug/commands/disable/display.rb +43 -0
- data/lib/byebug/commands/display.rb +66 -0
- data/lib/byebug/commands/down.rb +45 -0
- data/lib/byebug/commands/edit.rb +69 -0
- data/lib/byebug/commands/enable.rb +33 -0
- data/lib/byebug/commands/enable/breakpoints.rb +42 -0
- data/lib/byebug/commands/enable/display.rb +43 -0
- data/lib/byebug/commands/finish.rb +57 -0
- data/lib/byebug/commands/frame.rb +57 -0
- data/lib/byebug/commands/help.rb +64 -0
- data/lib/byebug/commands/history.rb +39 -0
- data/lib/byebug/commands/info.rb +37 -0
- data/lib/byebug/commands/info/breakpoints.rb +65 -0
- data/lib/byebug/commands/info/display.rb +49 -0
- data/lib/byebug/commands/info/file.rb +80 -0
- data/lib/byebug/commands/info/line.rb +35 -0
- data/lib/byebug/commands/info/program.rb +49 -0
- data/lib/byebug/commands/interrupt.rb +34 -0
- data/lib/byebug/commands/irb.rb +50 -0
- data/lib/byebug/commands/kill.rb +45 -0
- data/lib/byebug/commands/list.rb +159 -0
- data/lib/byebug/commands/method.rb +53 -0
- data/lib/byebug/commands/next.rb +40 -0
- data/lib/byebug/commands/pry.rb +41 -0
- data/lib/byebug/commands/quit.rb +42 -0
- data/lib/byebug/commands/restart.rb +64 -0
- data/lib/byebug/commands/save.rb +72 -0
- data/lib/byebug/commands/set.rb +79 -0
- data/lib/byebug/commands/show.rb +45 -0
- data/lib/byebug/commands/skip.rb +85 -0
- data/lib/byebug/commands/source.rb +40 -0
- data/lib/byebug/commands/step.rb +40 -0
- data/lib/byebug/commands/thread.rb +34 -0
- data/lib/byebug/commands/thread/current.rb +37 -0
- data/lib/byebug/commands/thread/list.rb +43 -0
- data/lib/byebug/commands/thread/resume.rb +45 -0
- data/lib/byebug/commands/thread/stop.rb +43 -0
- data/lib/byebug/commands/thread/switch.rb +46 -0
- data/lib/byebug/commands/tracevar.rb +54 -0
- data/lib/byebug/commands/undisplay.rb +51 -0
- data/lib/byebug/commands/untracevar.rb +36 -0
- data/lib/byebug/commands/up.rb +45 -0
- data/lib/byebug/commands/var.rb +37 -0
- data/lib/byebug/commands/var/all.rb +41 -0
- data/lib/byebug/commands/var/args.rb +39 -0
- data/lib/byebug/commands/var/const.rb +49 -0
- data/lib/byebug/commands/var/global.rb +37 -0
- data/lib/byebug/commands/var/instance.rb +39 -0
- data/lib/byebug/commands/var/local.rb +39 -0
- data/lib/byebug/commands/where.rb +53 -0
- data/lib/byebug/context.rb +157 -0
- data/lib/byebug/core.rb +115 -0
- data/lib/byebug/errors.rb +29 -0
- data/lib/byebug/frame.rb +185 -0
- data/lib/byebug/helpers/bin.rb +47 -0
- data/lib/byebug/helpers/eval.rb +126 -0
- data/lib/byebug/helpers/file.rb +63 -0
- data/lib/byebug/helpers/frame.rb +75 -0
- data/lib/byebug/helpers/parse.rb +75 -0
- data/lib/byebug/helpers/path.rb +40 -0
- data/lib/byebug/helpers/reflection.rb +19 -0
- data/lib/byebug/helpers/string.rb +33 -0
- data/lib/byebug/helpers/thread.rb +67 -0
- data/lib/byebug/helpers/toggle.rb +62 -0
- data/lib/byebug/helpers/var.rb +54 -0
- data/lib/byebug/history.rb +130 -0
- data/lib/byebug/interface.rb +146 -0
- data/lib/byebug/interfaces/local_interface.rb +44 -0
- data/lib/byebug/interfaces/remote_interface.rb +50 -0
- data/lib/byebug/interfaces/script_interface.rb +33 -0
- data/lib/byebug/interfaces/test_interface.rb +67 -0
- data/lib/byebug/option_setter.rb +95 -0
- data/lib/byebug/printers/base.rb +68 -0
- data/lib/byebug/printers/plain.rb +44 -0
- data/lib/byebug/printers/texts/base.yml +115 -0
- data/lib/byebug/printers/texts/plain.yml +33 -0
- data/lib/byebug/processors/command_processor.rb +173 -0
- data/lib/byebug/processors/control_processor.rb +24 -0
- data/lib/byebug/processors/post_mortem_processor.rb +18 -0
- data/lib/byebug/processors/script_processor.rb +49 -0
- data/lib/byebug/remote.rb +85 -0
- data/lib/byebug/remote/client.rb +57 -0
- data/lib/byebug/remote/server.rb +47 -0
- data/lib/byebug/runner.rb +198 -0
- data/lib/byebug/setting.rb +79 -0
- data/lib/byebug/settings/autoirb.rb +29 -0
- data/lib/byebug/settings/autolist.rb +29 -0
- data/lib/byebug/settings/autopry.rb +29 -0
- data/lib/byebug/settings/autosave.rb +17 -0
- data/lib/byebug/settings/basename.rb +16 -0
- data/lib/byebug/settings/callstyle.rb +20 -0
- data/lib/byebug/settings/fullpath.rb +16 -0
- data/lib/byebug/settings/histfile.rb +20 -0
- data/lib/byebug/settings/histsize.rb +20 -0
- data/lib/byebug/settings/linetrace.rb +22 -0
- data/lib/byebug/settings/listsize.rb +21 -0
- data/lib/byebug/settings/post_mortem.rb +27 -0
- data/lib/byebug/settings/savefile.rb +20 -0
- data/lib/byebug/settings/stack_on_error.rb +15 -0
- data/lib/byebug/settings/width.rb +20 -0
- data/lib/byebug/source_file_formatter.rb +71 -0
- data/lib/byebug/subcommands.rb +54 -0
- data/lib/byebug/version.rb +8 -0
- metadata +199 -0
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2018 David Rodríguez <deivid.rodriguez@riseup.net>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
# Byebug
|
2
|
+
|
3
|
+
[![Version][gem]][gem_url]
|
4
|
+
[![Tidelift][tid]][tid_url]
|
5
|
+
[![Coverage][cov]][cov_url]
|
6
|
+
[![Gitter][irc]][irc_url]
|
7
|
+
|
8
|
+
[gem]: https://img.shields.io/gem/v/byebug.svg
|
9
|
+
[tid]: https://tidelift.com/badges/github/deivid-rodriguez/byebug
|
10
|
+
[cov]: https://api.codeclimate.com/v1/badges/f1a1bec582752c22da80/test_coverage
|
11
|
+
[irc]: https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg
|
12
|
+
|
13
|
+
[gem_url]: https://rubygems.org/gems/byebug
|
14
|
+
[tid_url]: https://tidelift.com/subscription/pkg/rubygems-byebug?utm_source=rubygems-byebug&utm_medium=readme_badge
|
15
|
+
[cov_url]: https://codeclimate.com/github/deivid-rodriguez/byebug/test_coverage
|
16
|
+
[irc_url]: https://gitter.im/deivid-rodriguez/byebug
|
17
|
+
|
18
|
+
Byebug is a simple to use and feature rich debugger for Ruby. It uses the
|
19
|
+
TracePoint API for execution control and the Debug Inspector API for call stack
|
20
|
+
navigation. Therefore, Byebug doesn't depend on internal core sources. Byebug is also
|
21
|
+
fast because it is developed as a C extension and reliable because it is supported
|
22
|
+
by a full test suite.
|
23
|
+
|
24
|
+
The debugger permits the ability to understand what is going on _inside_ a Ruby program
|
25
|
+
while it executes and offers many of the traditional debugging features such as:
|
26
|
+
|
27
|
+
* Stepping: Running your program one line at a time.
|
28
|
+
* Breaking: Pausing the program at some event or specified instruction, to
|
29
|
+
examine the current state.
|
30
|
+
* Evaluating: Basic REPL functionality, although [pry] does a better job at
|
31
|
+
that.
|
32
|
+
* Tracking: Keeping track of the different values of your variables or the
|
33
|
+
different lines executed by your program.
|
34
|
+
|
35
|
+
## Build Status
|
36
|
+
|
37
|
+
Linux [![Cir][cir]][cir_url]
|
38
|
+
Windows [![Vey][vey]][vey_url]
|
39
|
+
|
40
|
+
[cir]: https://circleci.com/gh/deivid-rodriguez/byebug/tree/master.svg?style=svg
|
41
|
+
[tra]: https://api.travis-ci.org/deivid-rodriguez/byebug.svg?branch=master
|
42
|
+
[vey]: https://ci.appveyor.com/api/projects/status/github/deivid-rodriguez/byebug?svg=true
|
43
|
+
|
44
|
+
[cir_url]: https://circleci.com/gh/deivid-rodriguez/byebug/tree/master
|
45
|
+
[tra_url]: https://travis-ci.org/deivid-rodriguez/byebug
|
46
|
+
[vey_url]: https://ci.appveyor.com/project/deivid-rodriguez/byebug
|
47
|
+
|
48
|
+
## Requirements
|
49
|
+
|
50
|
+
MRI 2.3.0 or higher.
|
51
|
+
|
52
|
+
## Install
|
53
|
+
|
54
|
+
```shell
|
55
|
+
gem install byebug
|
56
|
+
```
|
57
|
+
|
58
|
+
Alternatively, if you use `bundler`:
|
59
|
+
|
60
|
+
```shell
|
61
|
+
bundle add byebug --group "development, test"
|
62
|
+
```
|
63
|
+
|
64
|
+
## Usage
|
65
|
+
|
66
|
+
### From within the Ruby code
|
67
|
+
|
68
|
+
Simply include `byebug` wherever you want to start debugging and the execution will
|
69
|
+
stop there. For example, if you were debugging Rails, you would add `byebug` to
|
70
|
+
your code:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
def index
|
74
|
+
byebug
|
75
|
+
@articles = Article.find_recent
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
And then start a Rails server:
|
80
|
+
|
81
|
+
```shell
|
82
|
+
bin/rails s
|
83
|
+
```
|
84
|
+
|
85
|
+
Once the execution gets to your `byebug` command, you will receive a debugging prompt.
|
86
|
+
|
87
|
+
### From the command line
|
88
|
+
|
89
|
+
If you want to debug a Ruby script without editing it, you can invoke byebug from the command line.
|
90
|
+
|
91
|
+
```shell
|
92
|
+
byebug myscript.rb
|
93
|
+
```
|
94
|
+
|
95
|
+
## Byebug's commands
|
96
|
+
|
97
|
+
Command | Aliases | Subcommands
|
98
|
+
------- | ------- | -----------
|
99
|
+
`backtrace` | `bt` `w` `where`|
|
100
|
+
`break` | `b` |
|
101
|
+
`catch` | `cat` |
|
102
|
+
`condition` | `cond` |
|
103
|
+
`continue` | `c` `cont` |
|
104
|
+
`debug` | |
|
105
|
+
`delete` | `del` |
|
106
|
+
`disable` | `dis` | `breakpoints` `display`
|
107
|
+
`display` | `disp` |
|
108
|
+
`down` | |
|
109
|
+
`edit` | `ed` |
|
110
|
+
`enable` | `en` | `breakpoints` `display`
|
111
|
+
`finish` | `fin` |
|
112
|
+
`frame` | `f` |
|
113
|
+
`help` | `h` |
|
114
|
+
`history` | `hist` |
|
115
|
+
`info` | `i` | `args` `breakpoints` `catch` `display` `file` `line` `program`
|
116
|
+
`interrupt` | `int` |
|
117
|
+
`irb` | |
|
118
|
+
`kill` | |
|
119
|
+
`list` | `l` |
|
120
|
+
`method` | `m` | `instance`
|
121
|
+
`next` | `n` |
|
122
|
+
`pry` | |
|
123
|
+
`quit` | `q` |
|
124
|
+
`restart` | |
|
125
|
+
`save` | `sa` |
|
126
|
+
`set` | | `autoirb` `autolist` `autopry` `autosave` `basename` `callstyle` `fullpath` `histfile` `histsize` `linetrace` `listsize` `post_mortem` `savefile` `stack_on_error` `width`
|
127
|
+
`show` | | `autoirb` `autolist` `autopry` `autosave` `basename` `callstyle` `fullpath` `histfile` `histsize` `linetrace` `listsize` `post_mortem` `savefile` `stack_on_error` `width`
|
128
|
+
`skip` | `sk` |
|
129
|
+
`source` | `so` |
|
130
|
+
`step` | `s` |
|
131
|
+
`thread` | `th` | `current` `list` `resume` `stop` `switch`
|
132
|
+
`tracevar` | `tr` |
|
133
|
+
`undisplay` | `undisp` |
|
134
|
+
`untracevar`| `untr` |
|
135
|
+
`up` | |
|
136
|
+
`var` | `v` | `all` `constant` `global` `instance` `local`
|
137
|
+
|
138
|
+
## Semantic Versioning
|
139
|
+
|
140
|
+
Byebug attempts to follow [semantic versioning](https://semver.org) and
|
141
|
+
bump major version only when backwards incompatible changes are released.
|
142
|
+
Backwards compatibility is targeted to [pry-byebug] and any other plugins
|
143
|
+
relying on `byebug`.
|
144
|
+
|
145
|
+
## Getting Started
|
146
|
+
|
147
|
+
Read [byebug's markdown
|
148
|
+
guide](https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md) to get
|
149
|
+
started. Proper documentation will be eventually written.
|
150
|
+
|
151
|
+
## Related projects
|
152
|
+
|
153
|
+
* [pry-byebug] adds `next`, `step`, `finish`, `continue` and `break` commands
|
154
|
+
to `pry` using `byebug`.
|
155
|
+
* [ruby-debug-passenger] adds a rake task that restarts Passenger with Byebug
|
156
|
+
connected.
|
157
|
+
* [minitest-byebug] starts a byebug session on minitest failures.
|
158
|
+
* [sublime_debugger] provides a plugin for ruby debugging on Sublime Text.
|
159
|
+
* [atom-byebug] provides integration with the Atom editor [EXPERIMENTAL].
|
160
|
+
|
161
|
+
## Contribute
|
162
|
+
|
163
|
+
See [Getting Started with Development](CONTRIBUTING.md).
|
164
|
+
|
165
|
+
## Funding
|
166
|
+
|
167
|
+
Subscribe to [Tidelift] to ensure byebug stays actively maintained, and at the
|
168
|
+
same time get licensing assurances and timely security notifications for your
|
169
|
+
open source dependencies.
|
170
|
+
|
171
|
+
You can also help `byebug` by leaving a small (or big) tip through [Liberapay].
|
172
|
+
|
173
|
+
## Security contact information
|
174
|
+
|
175
|
+
Please use the Tidelift security contact to [report a security vulnerability].
|
176
|
+
Tidelift will coordinate the fix and disclosure.
|
177
|
+
|
178
|
+
## Credits
|
179
|
+
|
180
|
+
Everybody who has ever contributed to this forked and reforked piece of
|
181
|
+
software, especially:
|
182
|
+
|
183
|
+
* @ko1, author of the awesome TracePoint API for Ruby.
|
184
|
+
* @cldwalker, [debugger]'s maintainer.
|
185
|
+
* @denofevil, author of [debase], the starting point of this.
|
186
|
+
* @kevjames3 for testing, bug reports and the interest in the project.
|
187
|
+
* @FooBarWidget for working and helping with remote debugging.
|
188
|
+
|
189
|
+
[debugger]: https://github.com/cldwalker/debugger
|
190
|
+
[pry]: https://github.com/pry/pry
|
191
|
+
[debase]: https://github.com/denofevil/debase
|
192
|
+
[pry-byebug]: https://github.com/deivid-rodriguez/pry-byebug
|
193
|
+
[ruby-debug-passenger]: https://github.com/davejamesmiller/ruby-debug-passenger
|
194
|
+
[minitest-byebug]: https://github.com/kaspth/minitest-byebug
|
195
|
+
[sublime_debugger]: https://github.com/shuky19/sublime_debugger
|
196
|
+
[atom-byebug]: https://github.com/izaera/atom-byebug
|
197
|
+
[Liberapay]: https://liberapay.com/byebug/donate
|
198
|
+
[Tidelift]: https://tidelift.com/subscription/pkg/rubygems-byebug?utm_source=rubygems-byebug&utm_medium=readme_text
|
199
|
+
[report a security vulnerability]: https://tidelift.com/security
|
data/exe/byebug
ADDED
@@ -0,0 +1,517 @@
|
|
1
|
+
#include "byebug.h"
|
2
|
+
|
3
|
+
#ifdef _WIN32
|
4
|
+
#include <ctype.h>
|
5
|
+
#endif
|
6
|
+
|
7
|
+
#if defined DOSISH
|
8
|
+
#define isdirsep(x) ((x) == '/' || (x) == '\\')
|
9
|
+
#else
|
10
|
+
#define isdirsep(x) ((x) == '/')
|
11
|
+
#endif
|
12
|
+
|
13
|
+
static VALUE cBreakpoint;
|
14
|
+
static int breakpoint_max;
|
15
|
+
|
16
|
+
static ID idEval;
|
17
|
+
|
18
|
+
static VALUE
|
19
|
+
eval_expression(VALUE args)
|
20
|
+
{
|
21
|
+
return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
|
22
|
+
}
|
23
|
+
|
24
|
+
/*
|
25
|
+
* call-seq:
|
26
|
+
* breakpoint.enabled? -> bool
|
27
|
+
*
|
28
|
+
* Returns +true+ if breakpoint is enabled, false otherwise.
|
29
|
+
*/
|
30
|
+
static VALUE
|
31
|
+
brkpt_enabled(VALUE self)
|
32
|
+
{
|
33
|
+
breakpoint_t *breakpoint;
|
34
|
+
|
35
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
36
|
+
return breakpoint->enabled;
|
37
|
+
}
|
38
|
+
|
39
|
+
/*
|
40
|
+
* call-seq:
|
41
|
+
* breakpoint.enabled = true | false
|
42
|
+
*
|
43
|
+
* Enables or disables breakpoint.
|
44
|
+
*/
|
45
|
+
static VALUE
|
46
|
+
brkpt_set_enabled(VALUE self, VALUE enabled)
|
47
|
+
{
|
48
|
+
breakpoint_t *breakpoint;
|
49
|
+
|
50
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
51
|
+
return breakpoint->enabled = enabled;
|
52
|
+
}
|
53
|
+
|
54
|
+
/*
|
55
|
+
* call-seq:
|
56
|
+
* breakpoint.expr -> string
|
57
|
+
*
|
58
|
+
* Returns a conditional expression which indicates when this breakpoint should
|
59
|
+
* be activated.
|
60
|
+
*/
|
61
|
+
static VALUE
|
62
|
+
brkpt_expr(VALUE self)
|
63
|
+
{
|
64
|
+
breakpoint_t *breakpoint;
|
65
|
+
|
66
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
67
|
+
return breakpoint->expr;
|
68
|
+
}
|
69
|
+
|
70
|
+
/*
|
71
|
+
* call-seq:
|
72
|
+
* breakpoint.expr = string | nil
|
73
|
+
*
|
74
|
+
* Sets or unsets the conditional expression which indicates when this
|
75
|
+
* breakpoint should be activated.
|
76
|
+
*/
|
77
|
+
static VALUE
|
78
|
+
brkpt_set_expr(VALUE self, VALUE expr)
|
79
|
+
{
|
80
|
+
breakpoint_t *breakpoint;
|
81
|
+
|
82
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
83
|
+
breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
|
84
|
+
return expr;
|
85
|
+
}
|
86
|
+
|
87
|
+
/*
|
88
|
+
* call-seq:
|
89
|
+
* breakpoint.hit_condition -> symbol
|
90
|
+
*
|
91
|
+
* Returns the hit condition of the breakpoint: +nil+ if it is an
|
92
|
+
* unconditional breakpoint, or :greater_or_equal, :equal or :modulo otherwise
|
93
|
+
*/
|
94
|
+
static VALUE
|
95
|
+
brkpt_hit_condition(VALUE self)
|
96
|
+
{
|
97
|
+
breakpoint_t *breakpoint;
|
98
|
+
|
99
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
100
|
+
switch (breakpoint->hit_condition)
|
101
|
+
{
|
102
|
+
case HIT_COND_GE:
|
103
|
+
return ID2SYM(rb_intern("greater_or_equal"));
|
104
|
+
case HIT_COND_EQ:
|
105
|
+
return ID2SYM(rb_intern("equal"));
|
106
|
+
case HIT_COND_MOD:
|
107
|
+
return ID2SYM(rb_intern("modulo"));
|
108
|
+
case HIT_COND_NONE:
|
109
|
+
default:
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
/*
|
115
|
+
* call-seq:
|
116
|
+
* breakpoint.hit_condition = symbol
|
117
|
+
*
|
118
|
+
* Sets the hit condition of the breakpoint which must be one of the following
|
119
|
+
* values:
|
120
|
+
*
|
121
|
+
* +nil+ if it is an unconditional breakpoint, or
|
122
|
+
* :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
|
123
|
+
*/
|
124
|
+
static VALUE
|
125
|
+
brkpt_set_hit_condition(VALUE self, VALUE value)
|
126
|
+
{
|
127
|
+
breakpoint_t *breakpoint;
|
128
|
+
ID id_value;
|
129
|
+
|
130
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
131
|
+
id_value = rb_to_id(value);
|
132
|
+
|
133
|
+
if (rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
|
134
|
+
breakpoint->hit_condition = HIT_COND_GE;
|
135
|
+
else if (rb_intern("equal") == id_value || rb_intern("eq") == id_value)
|
136
|
+
breakpoint->hit_condition = HIT_COND_EQ;
|
137
|
+
else if (rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
|
138
|
+
breakpoint->hit_condition = HIT_COND_MOD;
|
139
|
+
else
|
140
|
+
rb_raise(rb_eArgError, "Invalid condition parameter");
|
141
|
+
return value;
|
142
|
+
}
|
143
|
+
|
144
|
+
/*
|
145
|
+
* call-seq:
|
146
|
+
* breakpoint.hit_count -> int
|
147
|
+
*
|
148
|
+
* Returns the number of times this breakpoint has been hit.
|
149
|
+
*/
|
150
|
+
static VALUE
|
151
|
+
brkpt_hit_count(VALUE self)
|
152
|
+
{
|
153
|
+
breakpoint_t *breakpoint;
|
154
|
+
|
155
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
156
|
+
return INT2FIX(breakpoint->hit_count);
|
157
|
+
}
|
158
|
+
|
159
|
+
/*
|
160
|
+
* call-seq:
|
161
|
+
* breakpoint.hit_value -> int
|
162
|
+
*
|
163
|
+
* Returns the hit value of the breakpoint, namely, a value to build a
|
164
|
+
* condition on the number of hits of the breakpoint.
|
165
|
+
*/
|
166
|
+
static VALUE
|
167
|
+
brkpt_hit_value(VALUE self)
|
168
|
+
{
|
169
|
+
breakpoint_t *breakpoint;
|
170
|
+
|
171
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
172
|
+
return INT2FIX(breakpoint->hit_value);
|
173
|
+
}
|
174
|
+
|
175
|
+
/*
|
176
|
+
* call-seq:
|
177
|
+
* breakpoint.hit_value = int
|
178
|
+
*
|
179
|
+
* Sets the hit value of the breakpoint. This allows the user to set conditions
|
180
|
+
* on the number of hits to enable/disable the breakpoint.
|
181
|
+
*/
|
182
|
+
static VALUE
|
183
|
+
brkpt_set_hit_value(VALUE self, VALUE value)
|
184
|
+
{
|
185
|
+
breakpoint_t *breakpoint;
|
186
|
+
|
187
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
188
|
+
breakpoint->hit_value = FIX2INT(value);
|
189
|
+
return value;
|
190
|
+
}
|
191
|
+
|
192
|
+
/*
|
193
|
+
* call-seq:
|
194
|
+
* breakpoint.id -> int
|
195
|
+
*
|
196
|
+
* Returns the id of the breakpoint.
|
197
|
+
*/
|
198
|
+
static VALUE
|
199
|
+
brkpt_id(VALUE self)
|
200
|
+
{
|
201
|
+
breakpoint_t *breakpoint;
|
202
|
+
|
203
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
204
|
+
return INT2FIX(breakpoint->id);
|
205
|
+
}
|
206
|
+
|
207
|
+
/*
|
208
|
+
* call-seq:
|
209
|
+
* breakpoint.pos -> string or int
|
210
|
+
*
|
211
|
+
* Returns the position of this breakpoint, either a method name or a line
|
212
|
+
* number.
|
213
|
+
*/
|
214
|
+
static VALUE
|
215
|
+
brkpt_pos(VALUE self)
|
216
|
+
{
|
217
|
+
breakpoint_t *breakpoint;
|
218
|
+
|
219
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
220
|
+
if (breakpoint->type == BP_METHOD_TYPE)
|
221
|
+
return rb_str_new2(rb_id2name(breakpoint->pos.mid));
|
222
|
+
else
|
223
|
+
return INT2FIX(breakpoint->pos.line);
|
224
|
+
}
|
225
|
+
|
226
|
+
/*
|
227
|
+
* call-seq:
|
228
|
+
* breakpoint.source -> string
|
229
|
+
*
|
230
|
+
* Returns the source file of the breakpoint.
|
231
|
+
*/
|
232
|
+
static VALUE
|
233
|
+
brkpt_source(VALUE self)
|
234
|
+
{
|
235
|
+
breakpoint_t *breakpoint;
|
236
|
+
|
237
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
238
|
+
return breakpoint->source;
|
239
|
+
}
|
240
|
+
|
241
|
+
static void
|
242
|
+
mark_breakpoint(breakpoint_t *breakpoint)
|
243
|
+
{
|
244
|
+
rb_gc_mark(breakpoint->source);
|
245
|
+
rb_gc_mark(breakpoint->expr);
|
246
|
+
}
|
247
|
+
|
248
|
+
static VALUE
|
249
|
+
brkpt_create(VALUE klass)
|
250
|
+
{
|
251
|
+
breakpoint_t *breakpoint = ALLOC(breakpoint_t);
|
252
|
+
|
253
|
+
return Data_Wrap_Struct(klass, mark_breakpoint, xfree, breakpoint);
|
254
|
+
}
|
255
|
+
|
256
|
+
static VALUE
|
257
|
+
brkpt_initialize(VALUE self, VALUE source, VALUE pos, VALUE expr)
|
258
|
+
{
|
259
|
+
breakpoint_t *breakpoint;
|
260
|
+
|
261
|
+
Data_Get_Struct(self, breakpoint_t, breakpoint);
|
262
|
+
|
263
|
+
breakpoint->type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
|
264
|
+
if (breakpoint->type == BP_POS_TYPE)
|
265
|
+
breakpoint->pos.line = FIX2INT(pos);
|
266
|
+
else
|
267
|
+
breakpoint->pos.mid = SYM2ID(pos);
|
268
|
+
|
269
|
+
breakpoint->id = ++breakpoint_max;
|
270
|
+
breakpoint->source = StringValue(source);
|
271
|
+
breakpoint->enabled = Qtrue;
|
272
|
+
breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
|
273
|
+
breakpoint->hit_count = 0;
|
274
|
+
breakpoint->hit_value = 0;
|
275
|
+
breakpoint->hit_condition = HIT_COND_NONE;
|
276
|
+
|
277
|
+
return Qnil;
|
278
|
+
}
|
279
|
+
|
280
|
+
static int
|
281
|
+
filename_cmp_impl(VALUE source, char *file)
|
282
|
+
{
|
283
|
+
char *source_ptr, *file_ptr;
|
284
|
+
long s_len, f_len, min_len;
|
285
|
+
long s, f;
|
286
|
+
int dirsep_flag = 0;
|
287
|
+
|
288
|
+
s_len = RSTRING_LEN(source);
|
289
|
+
f_len = strlen(file);
|
290
|
+
min_len = s_len < f_len ? s_len : f_len;
|
291
|
+
|
292
|
+
source_ptr = RSTRING_PTR(source);
|
293
|
+
file_ptr = file;
|
294
|
+
|
295
|
+
for (s = s_len - 1, f = f_len - 1;
|
296
|
+
s >= s_len - min_len && f >= f_len - min_len; s--, f--)
|
297
|
+
{
|
298
|
+
if ((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
|
299
|
+
return 1;
|
300
|
+
if (isdirsep(source_ptr[s]) && isdirsep(file_ptr[f]))
|
301
|
+
dirsep_flag = 1;
|
302
|
+
#ifdef DOSISH_DRIVE_LETTER
|
303
|
+
else if (s == 0)
|
304
|
+
return (toupper(source_ptr[s]) == toupper(file_ptr[f]));
|
305
|
+
#endif
|
306
|
+
else if (source_ptr[s] != file_ptr[f])
|
307
|
+
return 0;
|
308
|
+
}
|
309
|
+
return 1;
|
310
|
+
}
|
311
|
+
|
312
|
+
static int
|
313
|
+
filename_cmp(VALUE source, char *file)
|
314
|
+
{
|
315
|
+
#ifdef _WIN32
|
316
|
+
return filename_cmp_impl(source, file);
|
317
|
+
#else
|
318
|
+
#ifdef PATH_MAX
|
319
|
+
char path[PATH_MAX + 1];
|
320
|
+
|
321
|
+
path[PATH_MAX] = 0;
|
322
|
+
return filename_cmp_impl(source, realpath(file, path) != NULL ? path : file);
|
323
|
+
#else
|
324
|
+
char *path;
|
325
|
+
int result;
|
326
|
+
|
327
|
+
path = realpath(file, NULL);
|
328
|
+
result = filename_cmp_impl(source, path == NULL ? file : path);
|
329
|
+
free(path);
|
330
|
+
return result;
|
331
|
+
#endif
|
332
|
+
#endif
|
333
|
+
}
|
334
|
+
|
335
|
+
static int
|
336
|
+
classname_cmp(VALUE name, VALUE klass)
|
337
|
+
{
|
338
|
+
VALUE mod_name;
|
339
|
+
VALUE class_name = NIL_P(name) ? rb_str_new2("main") : name;
|
340
|
+
|
341
|
+
if (NIL_P(klass))
|
342
|
+
return 0;
|
343
|
+
|
344
|
+
mod_name = rb_mod_name(klass);
|
345
|
+
return (!NIL_P(mod_name) && rb_str_cmp(class_name, mod_name) == 0);
|
346
|
+
}
|
347
|
+
|
348
|
+
static int
|
349
|
+
check_breakpoint_by_hit_condition(VALUE rb_breakpoint)
|
350
|
+
{
|
351
|
+
breakpoint_t *breakpoint;
|
352
|
+
|
353
|
+
if (NIL_P(rb_breakpoint))
|
354
|
+
return 0;
|
355
|
+
|
356
|
+
Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
|
357
|
+
breakpoint->hit_count++;
|
358
|
+
|
359
|
+
if (Qtrue != breakpoint->enabled)
|
360
|
+
return 0;
|
361
|
+
|
362
|
+
switch (breakpoint->hit_condition)
|
363
|
+
{
|
364
|
+
case HIT_COND_NONE:
|
365
|
+
return 1;
|
366
|
+
case HIT_COND_GE:
|
367
|
+
{
|
368
|
+
if (breakpoint->hit_count >= breakpoint->hit_value)
|
369
|
+
return 1;
|
370
|
+
break;
|
371
|
+
}
|
372
|
+
case HIT_COND_EQ:
|
373
|
+
{
|
374
|
+
if (breakpoint->hit_count == breakpoint->hit_value)
|
375
|
+
return 1;
|
376
|
+
break;
|
377
|
+
}
|
378
|
+
case HIT_COND_MOD:
|
379
|
+
{
|
380
|
+
if (breakpoint->hit_count % breakpoint->hit_value == 0)
|
381
|
+
return 1;
|
382
|
+
break;
|
383
|
+
}
|
384
|
+
}
|
385
|
+
return 0;
|
386
|
+
}
|
387
|
+
|
388
|
+
static int
|
389
|
+
check_breakpoint_by_pos(VALUE rb_breakpoint, char *file, int line)
|
390
|
+
{
|
391
|
+
breakpoint_t *breakpoint;
|
392
|
+
|
393
|
+
if (NIL_P(rb_breakpoint))
|
394
|
+
return 0;
|
395
|
+
|
396
|
+
Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
|
397
|
+
|
398
|
+
if (Qfalse == breakpoint->enabled || breakpoint->type != BP_POS_TYPE
|
399
|
+
|| breakpoint->pos.line != line)
|
400
|
+
return 0;
|
401
|
+
|
402
|
+
return filename_cmp(breakpoint->source, file);
|
403
|
+
}
|
404
|
+
|
405
|
+
static int
|
406
|
+
check_breakpoint_by_method(VALUE rb_breakpoint, VALUE klass, ID mid, VALUE self)
|
407
|
+
{
|
408
|
+
breakpoint_t *breakpoint;
|
409
|
+
|
410
|
+
if (NIL_P(rb_breakpoint))
|
411
|
+
return 0;
|
412
|
+
|
413
|
+
Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
|
414
|
+
|
415
|
+
if (Qfalse == breakpoint->enabled || breakpoint->type != BP_METHOD_TYPE
|
416
|
+
|| breakpoint->pos.mid != mid)
|
417
|
+
return 0;
|
418
|
+
|
419
|
+
if (classname_cmp(breakpoint->source, klass)
|
420
|
+
|| ((rb_type(self) == T_CLASS || rb_type(self) == T_MODULE)
|
421
|
+
&& classname_cmp(breakpoint->source, self)))
|
422
|
+
return 1;
|
423
|
+
|
424
|
+
return 0;
|
425
|
+
}
|
426
|
+
|
427
|
+
static int
|
428
|
+
check_breakpoint_by_expr(VALUE rb_breakpoint, VALUE bind)
|
429
|
+
{
|
430
|
+
breakpoint_t *breakpoint;
|
431
|
+
VALUE args, expr_result;
|
432
|
+
|
433
|
+
if (NIL_P(rb_breakpoint))
|
434
|
+
return 0;
|
435
|
+
|
436
|
+
Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
|
437
|
+
|
438
|
+
if (Qfalse == breakpoint->enabled)
|
439
|
+
return 0;
|
440
|
+
|
441
|
+
if (NIL_P(breakpoint->expr))
|
442
|
+
return 1;
|
443
|
+
|
444
|
+
args = rb_ary_new3(2, breakpoint->expr, bind);
|
445
|
+
expr_result = rb_protect(eval_expression, args, 0);
|
446
|
+
|
447
|
+
return RTEST(expr_result);
|
448
|
+
}
|
449
|
+
|
450
|
+
extern VALUE
|
451
|
+
find_breakpoint_by_pos(VALUE breakpoints, VALUE source, VALUE pos, VALUE bind)
|
452
|
+
{
|
453
|
+
VALUE breakpoint;
|
454
|
+
char *file;
|
455
|
+
int line;
|
456
|
+
int i;
|
457
|
+
|
458
|
+
file = RSTRING_PTR(source);
|
459
|
+
line = FIX2INT(pos);
|
460
|
+
for (i = 0; i < RARRAY_LENINT(breakpoints); i++)
|
461
|
+
{
|
462
|
+
breakpoint = rb_ary_entry(breakpoints, i);
|
463
|
+
if (check_breakpoint_by_pos(breakpoint, file, line)
|
464
|
+
&& check_breakpoint_by_expr(breakpoint, bind)
|
465
|
+
&& check_breakpoint_by_hit_condition(breakpoint))
|
466
|
+
{
|
467
|
+
return breakpoint;
|
468
|
+
}
|
469
|
+
}
|
470
|
+
return Qnil;
|
471
|
+
}
|
472
|
+
|
473
|
+
extern VALUE
|
474
|
+
find_breakpoint_by_method(VALUE breakpoints, VALUE klass, ID mid, VALUE bind,
|
475
|
+
VALUE self)
|
476
|
+
{
|
477
|
+
VALUE breakpoint;
|
478
|
+
int i;
|
479
|
+
|
480
|
+
for (i = 0; i < RARRAY_LENINT(breakpoints); i++)
|
481
|
+
{
|
482
|
+
breakpoint = rb_ary_entry(breakpoints, i);
|
483
|
+
if (check_breakpoint_by_method(breakpoint, klass, mid, self)
|
484
|
+
&& check_breakpoint_by_expr(breakpoint, bind)
|
485
|
+
&& check_breakpoint_by_hit_condition(breakpoint))
|
486
|
+
{
|
487
|
+
return breakpoint;
|
488
|
+
}
|
489
|
+
}
|
490
|
+
return Qnil;
|
491
|
+
}
|
492
|
+
|
493
|
+
void
|
494
|
+
Init_byebug_breakpoint(VALUE mByebug)
|
495
|
+
{
|
496
|
+
breakpoint_max = 0;
|
497
|
+
|
498
|
+
cBreakpoint = rb_define_class_under(mByebug, "Breakpoint", rb_cObject);
|
499
|
+
|
500
|
+
rb_define_alloc_func(cBreakpoint, brkpt_create);
|
501
|
+
rb_define_method(cBreakpoint, "initialize", brkpt_initialize, 3);
|
502
|
+
|
503
|
+
rb_define_method(cBreakpoint, "enabled?", brkpt_enabled, 0);
|
504
|
+
rb_define_method(cBreakpoint, "enabled=", brkpt_set_enabled, 1);
|
505
|
+
rb_define_method(cBreakpoint, "expr", brkpt_expr, 0);
|
506
|
+
rb_define_method(cBreakpoint, "expr=", brkpt_set_expr, 1);
|
507
|
+
rb_define_method(cBreakpoint, "hit_count", brkpt_hit_count, 0);
|
508
|
+
rb_define_method(cBreakpoint, "hit_condition", brkpt_hit_condition, 0);
|
509
|
+
rb_define_method(cBreakpoint, "hit_condition=", brkpt_set_hit_condition, 1);
|
510
|
+
rb_define_method(cBreakpoint, "hit_value", brkpt_hit_value, 0);
|
511
|
+
rb_define_method(cBreakpoint, "hit_value=", brkpt_set_hit_value, 1);
|
512
|
+
rb_define_method(cBreakpoint, "id", brkpt_id, 0);
|
513
|
+
rb_define_method(cBreakpoint, "pos", brkpt_pos, 0);
|
514
|
+
rb_define_method(cBreakpoint, "source", brkpt_source, 0);
|
515
|
+
|
516
|
+
idEval = rb_intern("eval");
|
517
|
+
}
|