Three productivity features in the Visual C++ 2017 debugger

Visual Studio 2017 has had a larger number of updates throughout its lifetime. At the time of writing this article, there have been ten major updates and countless minor ones. You can check the release notes history for details. Part of the changes was in the debugger. In this article, I will mention three features for C++ development that were introduced at different stages in Visual Studio 2017.

Run to Click (Available since 2017 15.0.)
When you are in the debugger and you hover the cursor over a statement in the editor (or the Disassembly window) a green button appears. By clicking this button you resume the execution until that point. This functionality was already available either through a (temporary) breakpoint or by the Run to Cursor command. But with this contextual button, it is made much simpler.

See more details: Navigating through code with the Visual Studio debugger

Just my code (Available since 2017 15.8.)
This is a feature that avoids stepping into frameworks, system, and other non-user code. This is available for other languages too, but for C++ it requires the /JMC compiler switch (which is enabled by default for new projects).

Here is an example. Suppose you are in the debugger at this line:

Stepping into the function call, you expect to get here:

This is exactly what you get with this feature enabled. Without it, however, the debugger used to step into standard library code, as shown below:

This feature can be enabled from Tools > Options > Debugging > General by selecting Enable Just My Code. In Visual Studio 2019, this feature is enabled by default.

When using this feature, in order to have the code classified as user-code, the PDB for the image containing it must be available to the debugger. When debugging:

  • Step Into (or F11) on non-user code steps over the code to the next line of user code and Step Out (or Shift+F11) on non-user code runs to the next line of user code.
  • when there’s no more user code, debugging continues until it ends, hits another breakpoint, or throws an error.
  • when breaking in non-user code stepping continues in the non-user code.
  • when hitting an exception, it stops on the exception, whether it is in user or non-user code. User-unhandled options in the Exception Settings dialog box are ignored.

You can customize what code should be considered non-user (it’s an opt-out feature) by creating a *.natjmc file (in the %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers folder if you want to change the behavior for all users, or in the %USERPROFILE%\My Documents\Visualizers folder for a particular user). Here is an example, from Microsoft Docs, on how such a file may look like (for details on the format, you should read the documentation):

<?xml version="1.0" encoding="utf-8"?>
<NonUserCode xmlns="http://schemas.microsoft.com/vstudio/debugger/jmc/2015">

  <!-- Modules -->
  <Module Name="ModuleSpec" />
  <Module Name="ModuleSpec" Company="CompanyName" />

  <!-- Files -->
  <File Name="FileSpec"/>

  <!-- Functions -->
  <Function Name="FunctionSpec" />
  <Function Name="FunctionSpec" Module ="ModuleSpec" />
  <Function Name="FunctionSpec" Module ="ModuleSpec" ExceptionImplementation="true" />

</NonUserCode>

See more details: Debug only user code with Just My Code

Step back (Available since 2017 15.9.)
This latest feature enables us to debug by returning to a previous point in time during the debugging without restarting the process. How is this done? Behind the scenes, the debugger uses PssCaptureSnapshot, a Windows API, to basically span a child process and take a snapshot of its memory. This is all hidden to the user, but when you step back, the debugging of the current process is actually stopped and the debugger is attached to one of these snapshot processes with access to its snapshot state (its entire virtual memory). When you return to live debugging, the debugger is reattached to the debugged process and proceeds in a normal manner.

Snapshots are taken each time a breakpoint is hit and at each step event, but not sooner than 300ms since the last one. This is done to ensure performance remains reasonable.

To make this work, you must first enable IntelliTrace Snapshots, from Tools > Options > IntelliTrace > General. (Notice that the following screenshots are taken in Visual Studio 2019 Preview, but they are basically the same in Visual Studio 2017.)

With this enabled, the Diagnostics Tool window changes to enable you to take snapshots. You will also see the snapshots that are taken automatically and you will be able to go through them and see the values of your variables in the Auto, Local, or Watch window.

You can also move back and forth through the snapshot history with the Step Backward and Step Forward commands from the debugging toolbar.

See more details: Step Back – Going Back in C++ Time

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.