Pause, Step, Continue

When your debug session initially starts (or after you attached to a running process) the application will be actively running. You can interact with the application itself, or view its console output in the Debug Console.

To do more in the debugger, you will typically need your application to break into a paused state. When breaking, the debugger freezes the app in its current state, and you can interact with and inspect it.

Breaking can happen in one of three ways:

  1. You can press the Pause button in the debug toolbar (or hit ^⌘Y/Alt+Ctrl+Break or choose "Debug|Pause from the menu).
  2. Your application can hit a Breakpoint you have set.
  3. Your application can raise an Exception, either explicitly from your own code, or in an API your code called.

In each of these cases, your application pauses, breaks into the debugger, and you will see a few things changing:

  • The Threads and Callstacks Pane will expand, showing you all the threads running in your application and the stack frames for each of them.
  • The current or most relevant frame will be highlighted in the Threads and Callstacks Pane, and also show in the main editor. The debugger will try to be smart and show the most relevant frame containing your own code, even if the actual break occurred depper into system or third party APIs.
  • The Debug Console activates and shows the (edb) prompt, indicating you can interact with it.

Working with the Debugger in Paused state

While the application is in paused state, you can interact with the debugger in various ways.

You can navigate between different stack frames (and different threads) by selecting them in the Threads and Callstacks Pane.

For stack frames that contain code from your project, you will automatically see the corresponding code in the editor, with the current line highlighted as Execution Point in orange.

For stack frames outside of your project, the debugger will still try to find the proper source code file to show, if the code was compiled with debug symbols. If no source file can be found, a generic view with details about the stack frame will be shown, potentially allowing you to Locate the Source File manually, if the frame has debug symbols that just did not match a file on your local disk.

You can inspect variables in scope at the local stack frame by putting the cursor on them (or selecting more complex expressions) in the editor, to see their value drawn on the right-hand side of the code. You can also see all local variables in the Debug Inspector, where you can also set up custom expressions to watch.

And of course you can interact with the textual Debug Console to perform more complex actions, as well.

Continuing

Once you are done inspecting the state of your app, you might want to resume it. You can do so by pressing the Continue (black-and-white Play button) in the debug toolbar, by pressing ^⌘Y/F5, or by choosing "Debug|Continue" from the menu.

You can also type the "c" or "continue" command in the Debug Console.

Execution of your application will resume, and continue until it is paused again or hits a new Breakpoint or Exception.

Note: In some other IDEs, the "Run" and "Continue" commands are overlaid, so that the same command or shortcut will start a new debug session when none is active, and resume the current session when it is paused.

Fire and Water separate the two commands; choosing "Run" (or ⌘R/Ctrl+R) will terminate the current debug session and start the project anew.

Stepping

Instead of having execution of your app continue, you might want to step through it slowly, line by line, to see what is going on. This can be done by the three Debug|Step commands:

  • "Step Into" will execute the next statement, and (where possible) try to step into the methods or properties that make up the statement. This allows you to follow the execution down into the individual methods that are being called next.
  • "Step Over" will execute the next statement as a whole, without stopping inside the methods or properties that make up the statement. Instead, execution will stop again once the statement is completed, before the next statement (i.e. the next line) of the current method is run.
  • "Step Out, finally, will continue to run the remainder of the current method until it's completed, and pause on the next statement following the call to the current method.

All three commands are available from the "Debug" menu, via keyboard shortcuts (F7, F6, F8 in Fire and F11, F10 and F12 in Water), and via the three "arrow" buttons in the debug toolbar.

After a Step action is complete, the debugger will be in paused state again. Note that depending on the complexity of the statement(s) being stepped over or out of, this might not happen immediately (since that code needs to run, first), and that a different Breakpoint or Exception might be encountered, before.

Setting the Next Statement

Sometimes, stepping through code might not be enough, and you need to take more drastic influence into the execution flow of your app.

Using the "Debug|Set Next Statement to Current Line" menu item, you can instruct the debugger to move the instruction pointer to a different location (within the current method). When you then Step or Continue, execution will resume from the new line – potentially skipping or re-executing statements that have already run.

Note that there are limits to how drastically the Next Statement can be changed. For example, you cannot move it to a different method, or into or out of a try/finally block. If the current line is not valid for "Set Next Statement to Current Line", the debugger will emit an error message, and the next line will remain unchanged.