Using the byebug gem gives me the ability to continue until the next breakpoint:
(byebug) help
break -- Sets breakpoints in the source code
catch -- Handles exception catchpoints
condition -- Sets conditions on breakpoints
continue -- Runs until program ends, hits a breakpoint or reaches a line
delete -- Deletes breakpoints
disable -- Disables breakpoints or displays
display -- Evaluates expressions every time the debugger stops
down -- Moves to a lower frame in the stack trace
edit -- Edits source files
enable -- Enables breakpoints or displays
finish -- Runs the program until frame returns
frame -- Moves to a frame in the call stack
help -- Helps you using byebug
history -- Shows byebug's history of commands
info -- Shows several informations about the program being debugged
interrupt -- Interrupts the program
irb -- Starts an IRB session
kill -- Sends a signal to the current process
list -- Lists lines of source code
method -- Shows methods of an object, class or module
next -- Runs one or more lines of code
pry -- Starts a Pry session
ps -- Evaluates an expression and prettyprints & sort the result
quit -- Exits byebug
restart -- Restarts the debugged program
save -- Saves current byebug session to a file
set -- Modifies byebug settings
show -- Shows byebug settings
source -- Restores a previously saved byebug session
step -- Steps into blocks or methods one or more times
thread -- Commands to manipulate threads
tracevar -- Enables tracing of a global variable
undisplay -- Stops displaying all or some expressions when program stops
untracevar -- Stops tracing a global variable
up -- Moves to a higher frame in the stack trace
var -- Shows variables and its values
where -- Displays the backtrace
I looked all over and I cannot find a way to "continue without breakpoints". The only way I can think of is to remove or comment the byebug statements, quit with q! and restart the test.
How can I continue without stopping at other byebug statements in Ruby?
You can use continue! or alias c! since byebug 11.0.0, released on February 15, 2019.
See this PR https://github.com/deivid-rodriguez/byebug/pull/524
If you are working with Rails, you may wanna reset it back on new request, than you can add a filter:
# application_controller.rb
before_action do
if defined?(Byebug) && Byebug.mode == :off && Rails.env.development?
Byebug.mode = nil
end
end
I just found out in the code, that you can stop byebug altogether using:
Byebug.mode = :off
You can't turn it back on, since it won't attach on itself any more, but this is handy, e.g. when just debugging a script that you want to finish running.
A byebug method call in your code is not a 'breakpoint' (thinking of the references to breakpoint in the help output).
As per the help output, breakpoints can be disabled with the disable command. But that does not solve your problem because the next byebug will pause execution again.
Since byebug is just a method call, you can make it conditional:
byebug if SomeModule.byebug?
Then, in SomeModule, you could use a global variable to toggle it on/off. You'd either have to do that on all your calls to byebug, or you could monkey-patch the byebug method to do the same, alias_method_chain or something similar.
"Make Byebug finish executing without exiting Pry" is a similar answer.
Related
I was working on trying to implement some kind of shell job control for a custom event loop handler with the GLib2 API in Ruby-GNOME. Ideally, this would be able to handle SIGTSTP and SIGCONT signals, to background the process at a TTY when running under a shell and to resume the background process on 'fg' from the shell.
I've not been able to figure out how to completely approach this with the API available in Ruby.
For a simpler usage case, I thought that I'd try adding a similar job support for IRB. I've added the following to my ~/.irbrc. The SIGTSTP handler seems to work, but the process remains suspended even after SIGCONT from fg in BASH.
## conditional section for ~/.irbrc
## can be activated with `IRB_JOBS_TEST=Defined irb`
if ENV['IRB_JOBS_TEST']
module Jobs
TSTP_HDLR_ORIG ||= Signal.trap("TSTP") do
STDERR.puts "\nJobs: backgrounding #{Process.pid} (#{TSTP_HDLR_ORIG.inspect}, #{CONT_HDLR_ORIG.inspect})"
Process.setpgid(0, Process.ppid)
TSTP_HDLR_ORIG.call if TSTP_HDLR_ORIG.respond_to?(:call)
end
CONT_HDLR_ORIG ||= Signal.trap("CONT") do
Process.setpgid(0, Process.pid)
STDERR.puts "Continuing in #{Process.pid}" ## not reached, not shown
IRB.CurrentContext.thread.wakeup ## no effect
CONT_HDLR_ORIG.call if CONT_HDLR_ORIG.respond_to?(:call)
end
end
end
I'm testing this on FreeBSD 13.1. I've read the FreeBSD termios(4), tcsetpgrp(3), and fcntl(2) manual pages. I'm not sure how much of the terminal-related API is available in Ruby.
The TSTP handler here seems to work, but the CONT handler is apparently not ever reached. I'm not sure if the TSTP handler is actually doing enough for - in effect - backgrounding the process in the shell's process group and relinquishing the controlling terminal.
With that TSTP handler, I can then background the IRB process in the shell with Ctrl-z. I can also foreground the process with 'fg' or BASH '%', but then the process is unresponsive. FreeBSD's Ctl-t handler shows the process as suspended. Apparently nothing in my CONT handler is reached.
I'm really stumped about what's failing in this approach - what my TSTP/CONT handlers are missing, what's available in Ruby, and why the process stays suspended after 'fg' in the shell.
In a more complex example, with the code I've written for glib2 it was apparently not enough to just call
Process.setpgid(0, Process.ppid)
as the process was not being backgrounded then. This would probably need another question though, as the example code for it isn't quite so short. So, I thought I'd try starting with IRB ...
After trying to foreground the process, then with Ctrl-t at the TTY on FreeBSD, I'm seeing the following
$ %
IRB_JOBS_TEST=Defined irb
load: 0.16 cmd: ruby31 4076 [suspended] 2.36r 0.19u 0.03s 1% 23828k
mi_switch+0xc2 thread_suspend_check+0x260 sleepq_catch_signals+0x113 sleepq_wait_sig+0x9 _cv_wait_sig+0xec tty_wait_background+0x30d ttydev_ioctl+0x14b devfs_ioctl+0xc6 vn_ioctl+0x1a4 devfs_ioctl_f+0x1e kern_ioctl+0x25b sys_ioctl+0xf1 amd64_syscall+0x10c fast_syscall_common+0xf8
So, it's blocking in an ioctl on resume?
Update
After a few hours of ineffectual hacking about this, I've removed the SIGTSTP and SIGCONT signal handlers from my GLib example code and now it "Just Works". I can background the example app at the console ... at least when it's not running under IRB ... and I can bring it back to the process group foreground with the shell. It resumes running on SIGCONT and everything looks alright in the logging from its main event loop.
I'm still not certain what the missing parts may have been, in may handlers/hacks for SIGTSTP and SIGCONT with IRB. Of course, with the input history recording in IRB it's typically simple enough to just restart the process..
Looking at how other applications have approached job control at the console, I think Emacs wraps its TTY I/O streams in some kind of an encapsulated struct? looking at Emacs' terminal.c mainly.
Glad to see if there's job control available in Ruby though, and it does not even need a custom signal handler for some applications?
Normally if you set a gdb breakpoint and the the program hits that point, gdb stops execution entirely and lets the user examine and poke around before continuing.
I want the option to be notified of the breakpoint traversal, but not halt execution.
I know I could simply go to the code and add a print statement, but this is annoying especially debugging libraries outside my code which I am not building myself.
Again, I'm already using GDB and want to use 'breakpoints' but just get some sort of notification of when and how many times a line is traversed without halting the whole program's execution. Is this possible?
I want the option to be notified of the breakpoint traversal, but not halt execution.
(gdb) break foo.c:123
(gdb) commands $bpnum
continue
end
This attaches a command to the breakpoint. GDB will print that a breakpoint is hit, then run the attached command, which will continue execution.
You could also print some variables before continuing, or even continue only if some condition is true, and stop otherwise. E.g. "continue if x > 100, but stop if it's not".
When putting a debugger; statement in my code and opening the isolate in the Observatory vm, I can see the code being stopped at the breakpoint's frame, and the variables shown next to the frame, as well as a shell to execute command lines.
I'd like to play with the variables, see what methods do objects hold, test operations in the observatory before writing the code, but variables are unavailable from the command line.
here is the help text:
$ h
List of commands:
break - Add a breakpoint by source location or function name (hotkey: [F8])
clear - Remove a breakpoint by source location or function name (hotkey: [F8])
cls - Clear the console
continue, c - Resume execution of the isolate (hotkey: [F7])
delete - Remove a breakpoint by breakpoint id
down - Move down one or more frames (hotkey: [Page Down])
finish - Continue running the isolate until the current function exits
frame, f - Set the current frame
help - List commands or provide details about a specific command
info - Show information on a variety of topics
isolate, i - Switch, list, rename, or reload isolates
log - Control which log messages are displayed
next, n - Continue running the isolate until it reaches the next source location in the current function (hotkey: [F9])
next-async - Step over await or yield
next-sync - Run until return/unwind to current activation.
pause - Pause the isolate (hotkey: [Ctrl ;])
print, p - Evaluate and print an expression in the current frame
refresh - Refresh debugging information of various sorts
reload - Reload the sources for the current isolate
rewind - Rewind the stack to a previous frame
set - Set a debugger option
step, s - Continue running the isolate until it reaches the next source location (hotkey: [F10]
up - Move up one or more frames (hotkey: [Page Up])
vm - Manage a Dart virtual machine
For more information on a specific command type 'help <command>'
For a list of hotkeys type 'help hotkeys'
Command prefixes are accepted (e.g. 'h' for 'help')
Hit [TAB] to complete a command (try 'is[TAB][TAB]')
Hit [ENTER] to repeat the last command
Use up/down arrow for command history
It looks like there is no way to enter the function and execute dart commands. Did I miss something ? How would I go about investigating objects and their methods ?
In this example, I wanted to investigate the DatabaseReference object reference from FirebaseDatabase, to figure out how to remove an existing entry. Not sure how to get this done without access to an interpreter.
Maybe I'm surprised as coming from Python, which debugger includes an interpreter ? But this doesn't sound impossible to do in Dart, with tools like DartPad or projects like dart-console
I've implemented this code in my .gdbinit file to make stop-requiring gdb commands work(such as x, set etc)
define hook-x
if $pince_debugging_mode == 0
interrupt
end
end
define hook-stop
if $pince_debugging_mode == 0
c &
end
end
The purpose of $pince_debugging_mode variable is to inform gdb if the program is interrupting the target for debugging purposes or not.
I have a concern about signal concurrency with this design: Lets say we put a breakpoint on an address and while waiting it to get triggered we wanted to check some addresses with the x command. After x command gets executed, hook-stop will get executed because we have stopped the thread with the x command. And lets say breakpoint has been reached while hook-post is executing but hook-stop isn't aware of that and the $pince_debugging_mode still equals to 0 so it'll execute the c & command and the target will continue. So the stop at breakpoint won't mean anything because of this concurrency problem.
This problem never occurred yet but I'm afraid of the odds of occurring, even if it's very low, I don't want to take the risk. What can I do to avoid this possible problem?
Note: defining a hookpost-x is problematic because whenever x command throws an exception hookpost won't get executed, so it'll be impossible to continue after a exception-throwing x command
Say I'm debugging a function like this
def foo {
byebug
x = 1+1
}
Running this, we hit the breakpoint. If I now hit "n", it runs the next line and exits the function. How can I instead remain in the function and inspect x?
Try finish 0.
The finish command should step out the number of frames you specify as an argument. If you specify 0, it has special behavior and just finishes the current frame without stepping out of it.