I recently happened to read an article written by Ivan Shcherbakov, the 11 powerful Visual Studio debugging tips. This article only introduces some basic debugging tips for Visual Studio, but there are some other equally useful techniques. I've collated some of the debugging tips for native development of visual Studio (at least under VS 2008). (If you are working under managed code, the debugger will have more features, articles to introduce them in CodeProject), here are some tips for my collation:
Abnormal Interrupt | Break on Exception
Pseudo variables in the Watch Window | Pseudo-variables in Watch Windows
View heap objects after a symbol is crossed |
To view the values of an array
Avoid going to unnecessary functions
Start Debugger from Code | Launch the debugger from code
Print in Output window
Isolating memory leaks
Debug Release | Debug the Release build
Remote debugging
Tip 1: Abnormal interrupts
You can start the debugger to interrupt when an exception occurs before processing is invoked, allowing you to debug the program immediately after the exception occurs. The operation call stack makes it easy for you to find the root cause of the anomaly.
Vistual Studio allows you to specify the type of exception or special exception that you want to break. Select Menu debug>exceptions Pop-up dialog box, you can specify the native (or managed) exception, in addition to some of the debugger's own default exceptions, you can also add your own custom exception.
The following is an example of a debugger interrupt when a Std::exception exception is thrown.
Read MORE:
- 1. How to break when an exception is thrown
- 2. How to add a new exception
trick 2:watch a pseudo variable in a window
The Watch window or QuickWatch dialog box provides some specific (debugger-identifiable) variables, known as pseudo variables. The document contains the following:
$tid-– the thread ID of the current thread
$pid--Process ID
$cmdline ———-the command line string to start the program
$user ———-account information that is running the program
$registername-– Display the contents of the Register Registername
In any case, a pseudo variable about the last error is useful:
$err--– to display the error code for the last error
$err, hr-displays the error message for the last error
Read MORE: Pseudo variable
Tip 3: View heap objects after crossing line
Sometimes, after the debug symbol crosses the line, you want to see the value of the object, at which point the variable in the Watch window is disabled and cannot be viewed (or updated), although the object still exists. If you know the address of the object, you can continue to observe it fully. You can translate the address into a pointer to the object type and place it in the Watch window.
In the following example, when stepping out of Do_foo (), _foo can no longer be accessed. However, after converting its address to foo*, you can continue to observe the object.
Tip 4: View the value of an array
If you're working on a large array (we're assuming there are at least hundreds of elements, but maybe less), it's cumbersome to expand the array in the Watch window, looking for elements within a certain range, because you're going to keep scrolling. If the array is allocated on the heap, You can't even expand an array element in the Watch window. There is a solution to this. You can use (array+ <offset>),<count> to see a specific range of <count> elements starting at <offset> (of course, the array here is your actual object). If you want to view the entire array, you can simply use Array,<count>.
If your array is on the heap, you can expand it in the Watch window, but to see a specific range of values, the usage is slightly different: ((t*) array + <offset>),<count> (note that this usage is also valid for multidimensional arrays on the heap). But in this case, T is the type of exponential group element.
If you are using MFC, and use one of the ' array ' containers, like CArray, Cdwordarray,cstringarray, and so on. Of course you can use the same filtering method. In addition, you must look at the M_pdata member of the array, which is the real cache of the data saved.
Tip 5: Avoid entering unnecessary functions
Most of the time, when you're debugging code, you might get into functions that you want to skip, like constructors, assignment operations, or whatever. One of the things that bothers me most is the CString constructor. Here's an example, when you're ready to step into the take_a_string () function, you first go to the CString constructor.
void take_a_string (CString const &text) {}void test_string () {take_a_string (_t ("sample"));}
Fortunately, you can tell the debugger which methods to skip, the class, or the entire namespace. The way to implement it has also changed, returning to the days of using VS6, usually by autoexp.dat files. Vistual Studio 2002 was changed to use registry settings. To skip some functions, you need to add some values to the registry (details below):
The
actual location depends on the Vistual studio version you use and the operating system platform (x86 or x64, because the registry can only be browsed under 64-bit Windows). The name of the value is a number, which represents the precedence of the rule; the larger the number, the higher the priority. The value data is the REG_SZ value of a regular expression that specifies how to filter and execute.
To avoid entering any of the CString methods, I added the following rule:
With this, the debugger skips the CString constructor even if you force it into the take_a_string () in the example above.
Read MORE:
- How to avoid entering functions using the Visual C + + debugger
- To adjust the debugger using AutoExp.dat
Tip 6: Start the debugger from code Launch the debugger
You may have little need to attach the debugger to your program, but you can't do it in the Attach window (probably because the interrupts are too fast to catch) and you can't start the program in the debugger from the start. You can generate interrupts in the program to give the debugger an opportunity to attach by invoking the internal _degbugbreak ().
Copy Code code as follows:
void Break_for_debugging () {
__debugbreak ();
}
There are actually other ways to do this, such as triggering interrupt 3, but this only applies to the x86 platform (the C++64 bit no longer supports ASM). There is also the DebugBreak () function, but it is not easy to use, so it is recommended to use the internal method.
Copy Code code as follows:
When a program runs an internal method, it stops running, and you have the opportunity to attach the debugger to the process.
Read MORE:
- Internal Method _debugbreak
- No time to leave. Set breakpoints and assertions
- Debugging of Visual Studio 20005/2008, part four: setting code for the debugger
Tip 7: Print in Output window
You can display a specific text in the Output window of the debugger by calling Debugoutputstring. If there is no additional debugger, the function does nothing.
Read MORE:
- function OutputDebugString
- The calling mechanism of function outputdebugstring
Tip 8: Isolate memory leaks
Memory leaks are an important issue in native development, and it is a serious challenge to detect memory leaks, especially in large projects. Vistual Studio can provide a report that detects memory leaks, and other applications (free or commercial) can also help you detect memory leaks. In some cases, you can use the debugger to interrupt when some memory allocations end up causing a leak. But you have to find a reproducible distribution number (though it's not that easy). If you can do this, the debugger will break when you execute the program.
Let's look at the code below, allocating 8 bytes, but not releasing the allocated memory. Visual Studio provides reports of objects that cause memory leaks, runs several times, and finds the same allocation number (341).
Copy Code code as follows:
void Leak_some_memory ()
{
char* buffer = new CHAR[8];
}
Dumping Objects->
D:\marius\vc++\debuggingdemos\debuggingdemos.cpp: {341} normal block at 0x00f71f38, 8 bytes long.
Data: < > CDs CD CDS CD CD CD CD
The steps to break in a specific (reproducible) location are as follows:
Make sure you have enough reporting mode on memory leaks (refer to using CRT Library to detect memory leaks)
Run the program multiple times until you can find a reproducible allocation number in the memory leak report after the program is run, such as in the previous example (341)
Set a breakpoint at the beginning of the program so that you can interrupt as early as possible.
When the initial interrupt occurs, the name bar of the Watch window displays: {,, Msvcr90d.dll}_crtbreakalloc, write the location number you want to find in the Value column
Continue Debugging (F5)
The program execution stops at the specified location, and you can use the call stack to navigate to the code that is triggered by that location.
Following these steps, in the last example, you can identify the cause of the memory leak by using the assigned number (341).
Tip 9: Debug a Release
Debugging and publishing are two different purposes. The Debug configuration is for development, and the release configuration, as the name suggests, is used as the final version of the program because it must strictly follow the quality requirements for the release, which contains settings for the tuning and debug versions of interrupt debugging. And, sometimes, debug a release like a debug version. To do this, you need to make some changes in the configuration. But in this case, you are no longer debugging a release, but a mixed version of debugging and distribution.
There are some things you should do, and here's what you have to do:
Configure the C + + >general>debug information Format should be "program Database (/zi)"
Configure C + + >optimization>optimization should be "disabld (/od)"
Configure Linker>debugging>generate Debug Info should be "yes/(Debug)"
As shown in the figure:
Read more: How to debug a release
Tip 10: Remote Debugging
Another important debugging is remote debugging, which is a bigger topic that has been mentioned many times, here I just do a simple summary:
You need to install remote debugging monitoring on the remote machine.
Remote debugging monitoring must be run as an administrator and the user must belong to the Administrators group
When you run the monitor, a new service opens, and the name of the service must be the value of the qualifier combo box in Visual Studio's attach to progress window.
- Firewalls on remote and local machines must allow communication between Visual Studio and remote debugging monitoring
- PDB files are key to debugging, and the following conditions must be met in order for Visual Studio to automatically load them:
1 The local PDB file must be available (a corresponding module is placed under the same path as the remote machine).
2 The managed PDB culture on the remote machine must be available.
Remote Debugging monitoring download:
- Visual Studio 2008 Service Pack 1 Remote Debugger
- Microsoft Visual Studio Remote Debugger
Read MORE:
- Setting up Remote debugging
- How to run remote debugging monitoring
- To load debug symbols while remote debugging: local to Managed
- PDB files: Tips for Developers
- Visual Studio Remote debugging and PDB files
- How to specify symbol position and load behavior
concluding remarks
The debugging techniques mentioned by Ivan Shcherbakov in that article and in my article are essential in most debugging problems. To learn more about debugging techniques, it is advisable to read the additional readings provided in the article.
Original link: Marius Bancila translation: Bole online-bole online readers
Translation Links: http://blog.jobbole.com/45249/