Debugging in CLion

Posted on by

One of the key advantages to having an IDE instead of a plain-text editor is the debugging experience. Debugging involves being able to pause program execution at an arbitrary point and having the ability to inspect the content of variables.

CLion supports the debugging experience using the GDB debugger (and LLDB on OS X since version 1.1 and on Linux since version 2016.2). Here’s a look at some of the core debugging features that are supported.

Upd. (changes since CLion 2016.1 and 2016.2)

Learn how to attach for debug to local process started not from the CLion (from CLion v2016.1).

Check major changes (since v2016.2) in GDB and LLDB drivers and addresses such problems as:

Command timeouts.

Stepping problems.

Debugger performance issues.

Please, find more details in our blog post by the link.

Try remote GDB debug (since v2016.2).

Breakpoints

In order to inspect the state of the program at a particular point, you need to pause the program. Breakpoints are used for exactly this purpose.

A simple breakpoint stops the execution of a program at a particular line. To make one, simply press Ctrl+F8 (Windows/Linux)/ ⌘F8 (OS X) or, alternatively, click the mouse in the grey gutter area to the left of the code. The line with the breakpoint will be highlighted, and the breakpoint itself will appear as a red circle:

Now, when you run the program in debug mode (by choosing the menu item Run|Debug or pressing Shift+F9 (Windows/Linux)/ ^D (OS X)), program execution will stop at the line you selected.

A conditional breakpoint will only stop at a particular line if some condition holds. To edit the condition, you can right-click the breakpoint and type in the condition in the window that pops up. You even get code completion right in the editor!

With this pop-up window open, you can press Ctrl+Shift+F8 / ⇧⌘F8 to open up the full breakpoint editing window:

Some of the options available here include:

Suspend — this check box determines whether the execution pauses at a particular point or not. Leaving this unchecked means program execution will continue, but any breakpoint rules (e.g., logging) will still be executed.

— this check box determines whether the execution pauses at a particular point or not. Leaving this unchecked means program execution will continue, but any breakpoint rules (e.g., logging) will still be executed. Condition — determines the condition on which this breakpoint triggers. Leaving this out ensures that the breakpoint is always hit.

— determines the condition on which this breakpoint triggers. Leaving this out ensures that the breakpoint is always hit. Log message to console writes to the console information about the breakpoint being hit.

writes to the console information about the breakpoint being hit. Log evaluated expression lets you log the result of specific evaluation.

lets you log the result of specific evaluation. Remove once hit ensures that after you hit the breakpoint once, the breakpoint is removed. This can be useful in cases where you only want to log the first occurence of a particular point being hit.

ensures that after you hit the breakpoint once, the breakpoint is removed. This can be useful in cases where you only want to log the first occurence of a particular point being hit. Disabled until selected breakpoint is hit does exactly what it says: it disables the current breakpoint until some other breakpoint is encountered. This is useful in situations where, for example, you only want to investigate a point in code when it is called from a specific function of your choosing. There are two options here: Disable again disables the breakpoint after it is hit until the dependant breakpoint is hit again (in which case it is re-enabled). Leave enabled leaves the breakpoint forever enabled and thus no longer dependant on any other breakpoint being hit first.

does exactly what it says: it disables the current breakpoint until some other breakpoint is encountered. This is useful in situations where, for example, you only want to investigate a point in code when it is called from a specific function of your choosing. There are two options here:

Exception Breakpoints

But that’s not all! In addition to ordinary breakpoints, CLion also supports exception breakpoints which, as the name suggests, trigger when the program throws an exception.

The set of options related to exception breakpoints is similar to line breakpoints: you can specify whether you want to suspend execution, log message to the console, remove the exception once it’s hit, or only enable it when some other breakpoint is hit first:

Debugger User Interface

So, what exactly happens when a debugger hits a breakpoint? Apart from the execution pausing, you get to see the following Debug tool window:

There’s a lot going on here, so let’s start by discussing the two primary tabs (the top-level tabs, so to speak). They are:

Debugger — this actually shows the various debugging options that we are going to discuss in just a moment.

— this actually shows the various debugging options that we are going to discuss in just a moment. Console — this area shows the command-line output, if your application has any.

Directly to the right of these tabs is a set of buttons that allow you to navigate around the code being debugged. They include letting you

Show Execution Point ( Alt+F10 ),

( ), Step Over ( F8 ),

( ), Step Into ( F7 ),

( ), Force Step Into ( Alt+Shift+F7 ),

( ), Step Out ( Shift+F8 ),

( ), and Run to Cursor ( Alt+F9 ).

There’s also a button that lets you Evaluate Arbitrary Expression ( Alt+F8 ) — we’ll talk about this later.

To the left of the tabs is a vertical column of buttons that contains higher-level controls for debugging, including buttons for resuming execution or stopping the application, an ability do display breakpoint settings, and other miscellaneous controls.

So let’s get back to the Debugger tab. This tab has lots of things going on. First of all, on the left, it lets you actually pick the threads that you want to inspect. Modern applications run on many threads, so you can pick one from a drop-down list:

Directly below that is the stack frame, i.e., a list of the nested functions that were invoked as you were going through the code. Each entry lists the full name of the function (or constructor), the file name and the line number. Clicking the line causes CLion to open the corresponding file at the specified line number:

To the right of the stack frame, we have two tabs: Variables and GDB (LLDB). We’ll talk about variables in just a moment; as far as GDB (LLDB) is concerned, this tab essentially shows the command-line output from GDB (LLDB) itself, since that’s the debugger that’s being used to debug our app.

Variables

The simplest way to view the state of a variable is, of course, in code. Simply hover the mouse over the variable in question and you should see something like the following:

If you press Ctrl+F1 (Windows/Linux)/ ⌘F1 (OS X) at this point, a window will pop up containing the inner states of the variable you are after:

Of course, you get a more comprehensive view of variables in the Debug tool window. For a chosen function in the stack frame, the Variables tab shows the state of all the variables. In a complicated application, it can get quite busy:

For any one variable we can expand the tree to see its contents:

If you want to cut out the noise a little bit, simply right-click the variable and choose Inspect: this opens up a separate window for inspecting this variable only:

It is entirely possible to actually alter the values of the variables in the debug session. Right-click the variable and choose Set Value. The editor will open in-place over the current value, letting you type in the new value:

GNU STL Renderers

As a special enhancement of the debugging experience, CLion treats STL containers with extra care, making sure you get the best possible representation during the debug process. For example, here’s a look at how an std::map can be presented in the debugger:

This feature works in GCC, and in the case of Clang it works for libstdc++ only. This requires the following setting to be added to CMakeLists.txt :

set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -stdlib=libstdc++”)

Watches

Capturing every single variable at every single point results in far too much information. Sometimes, you want to focus on a specific variable and the way it changes throughout program execution, including monitoring changes when the variable in question is not local to the code you are inspecting. This is what the Watch area of the Debug tool window is for.

To start watching a variable, simply press the Add button ( Alt+Insert (Windows/Linux)/ ⌘N (OS X)) and type in the name of the variable to watch. Code completion is available here too.

Alternatively, pick an existing variable, right-click it and choose Add to watches. Now the window will keep displaying the value of the variable even if you are in some nested part of the stack frame:

Evaluating Expressions

You can see variable states on a breakpoint, but what if you want to see the sum of two variables, or evaluate the result of a function call then and there? There’s functionality for that too. Simply press the Evaluate Expression button ( Alt+F8 ) on the Debug tool window and type in your expression. As always, you get code completion here, and after you press the Evaluate button, the result area below will display the result of the evaluation:

You can also use a shortcut ( Ctrl+Shift+Enter ) to add this expression to watches. That’s right – watches can contain arbitrary expressions, not just single variables!

Watch CLion debugging features in action:

https://www.youtube.com/watch?v=wUZyoAnPdCY

Conclusion

This post has shown what CLion can do for you when debugging. You can evaluate these features for free for 30 days, simply download the build from our site. Give it a go, and let us know what you think! ■