10 Debugging Tips for sharing Visual Studio native development (2) _ Practical Tips

Source: Internet
Author: User
Tags naming convention


The previous article on Visual Studio debugging techniques was so interesting that I decided to share more knowledge about debugging. The following list allows you to see the debugging Techniques for native development (followed by the previous article numbering). These techniques can be applied to VS2005 or newer versions (of course, some can be used for older versions). If you continue, you can know the details of each technique.






Tip 11: Data breakpoints



The debugger will break when the memory location of the data changes. However, this is the only data breakpoint that can create 4 of such hardware at one time. Data breakpoints can only be added during compilation, either through a menu (Compile > New Breakpoint > New data Breakpoint) or through a breakpoint window.






You can use a memory address or an address expression. Even if you can see the two values on the stack, I think this feature is usually useful when the values on the heap are changed. This is a great help for identifying memory corruption.



In the following example, the value of the pointer has changed to the value of the object being pointed to. In order to find out where to make the changes, I set a breakpoint at the location where the pointer value is stored, such as &ptr (note that this occurs after the pointer is initialized). When the data changes, the debugger terminates and then discovers which code is causing the change, thinking that someone has changed the value of the pointer.






Tip 12: Line Chenghong naming



When you debug a multithreaded application, the Threads window shows which threads were created and the current thread. The more threads you have, the harder it is to find the thread you're looking for (especially when the same program is executed by multiple threads at the same time, you don't know which thread instance is currently executing)






The debugger allows you to rename the thread. Right-click a thread and rename it.






You can also name a thread programmatically, although this is a bit tricky and must be done after the thread starts, or the debugger will reinitialize it with its default naming convention, and the following function shows how to define and use a thread.


typedef struct TAGTHREADNAME_INFO
{
  DWORD dwtype;    Must be a length of two bytes
  lpcstr szName;    The pointer points to a named (same address space)
  DWORD dwThreadID;  Thread ID (-1 call thread)
  DWORD dwflags;    Reserved for use, in most cases 0
} threadname_info;
 
void SetThreadName (DWORD dwthreadid, lpcstr szthreadname)
{
  threadname_info INFO;
  Info.dwtype = 0x1000;
  Info.szname = Szthreadname;
  Info.dwthreadid = dwThreadID;
  info.dwflags = 0;
 
  __try
  {
    raiseexception (0x406d1388, 0, sizeof (info)/sizeof (DWORD), (dword*) &info);
  __except (exception_continue_execution)
  {
  }
}


Tip 13: Specify a thread to set a breakpoint



  Another useful technique for multithreaded applications is to set breakpoints on specified threads, processes, and even computers. You can use the breakpoint's filer command to implement this functionality.






The debugger allows you to use different combinations of thread name, thread ID, process name, process ID, and machine name (using and, or, not connecting). Mastering how to set the thread name also makes this filtering technology easier to operate.



Tip 14: (inaccurate) timed execution



In my previous article I mentioned the use of pseudo variables in the Watch window. One of the things that is not mentioned is @clk, which displays the value of a counter to get the approximate time required for code execution between two breakpoints, in milliseconds (ms). However, this method cannot be used to configure program execution. You should use Visual Studio Profiler or a performance timer to complete these configurations.



Reset the timer by adding @clk=0 to the Watch window or the Immediate window. Therefore, if you need to calculate the time required for the last code execution, do the following:


    • To set a breakpoint at the start of a code block
    • Set breakpoints at end of code block
    • Add @clk in the Watch window
    • When the first breakpoint is triggered, enter the @clk=0 in the intermediate window
    • Run the program until you encounter a breakpoint at the end of the code block and view the value of the @clk in the Watch window


Note that there are tricks on the web to add two expressions to the Watch window: @clk and @clk=0, which are said to reset the timer every time the breakpoint is executed. This technique can only be used in a lower version of Visual Studio, but not in a high version vs, such as VS2005 (the author has done tests, VS2005 does not support this technique), and later versions.



Tip 15: Format numbers



When you view variables using the watch or Quick Watch window, the values are displayed with the default predefined visual format. When a variable is a number, the display form is based on their type (int, float, double) and is displayed in decimal. However, you can set the debugger to use different types of display numbers, or use different systems.



Change the display type of a variable to add the following prefix before a variable:


    • by--unsigned char (unsigned byte)
    • wo--unsigned short (unsigned word)
    • dw--unsigned Long (unsigned double word)


Changing the way a variable displays can add the following prefix before a variable:


    • D or i--signed decimal digits
    • u--unsigned decimal digits
    • o--unsigned octal number
    • x--lowercase hexadecimal number
    • x--uppercase hexadecimal number





Tip 16: Format memory data



In addition to numbers, debugger can display formatted memory data in the Watch window for a maximum of 64 bytes. You can format the data by adding the following suffix after the expression (variable or memory address):


    • MB or m--hexadecimal 16-byte data followed by 16 ASCII characters
    • Mw--8 Word (Word, usually 1 word = 2 BYTE) data
    • Md--4 a double word (DWORD, usually 1 DWORD = 4 BYTE) data
    • Mq--2 Four words (Quad word) data
    • ma--64 ASCII characters
    • Mu--2 Byte Unicode character





Tip 17: Pause at the system DLL call



It is sometimes useful to pause when a function of a DLL is invoked, especially system DLLs (such as Kernel32.dll, User32.dll). The implementation of this pause requires the use of the context operator provided by the native debugger. You can set a breakpoint position, a variable name, or an expression:


    • {[function],[source code],[module]} breakpoint location
    • {[function],[source code],[module]} variable name
    • {[function],[source code],[module]} expression


The braces can be any combination of function names, source codes, and modules, but commas cannot be omitted.



For example, if we need to pause the CreateThread function call. This function is derived from kernel32.dll, so the context operator should be like this: {,, Kernel32.dll}createthread. However, this does not work because the operator requires a name that is CreateThread decorated. You can use DBH.exe to get the decorated name of a particular function (compiler compilation build).



Here's how to get CreateThread's decorated name:


C:\Program Files (x86)\Debugging Tools for Windows (x86)>dbh.exe -s:srv*C:\Symbo
ls*http://msdl.microsoft.com/Download/Symbols -d C:\Windows\SysWOW64\kernel32.dl
l enum *CreateThread*
Symbol Search Path: srv*C:\Symbols*http://msdl.microsoft.com/Download/Symbols
 
 index      address   name
   1      10b4f65 :  _BaseCreateThreadPoolThread@12
   2      102e6b7 :  _CreateThreadpoolWork@12
   3      103234c :  _CreateThreadpoolStub@4
   4      1011ea8 :  _CreateThreadStub@24
   5      1019d40 :  _NtWow64CsrBasepCreateThread@12
   6      1019464 :  ??_C@_0BC@PKLIFPAJ@SHCreateThreadRef?$AA@
   7      107309c :  ??_C@_0BD@CIEDBPNA@TF_CreateThreadMgr?$AA@
   8      102ce87 :  _CreateThreadpoolCleanupGroupStub@0
   9      1038fe3 :  _CreateThreadpoolIoStub@16
   a      102e6f0 :  _CreateThreadpoolTimer@12
   b      102e759 :  _CreateThreadpoolWaitStub@12
   c      102ce8e :  _CreateThreadpoolCleanupGroup@0
   d      102e6e3 :  _CreateThreadpoolTimerStub@12
   e      1038ff0 :  _CreateThreadpoolIo@16
   f      102e766 :  _CreateThreadpoolWait@12
  10      102e6aa :  _CreateThreadpoolWorkStub@12
  11      1032359 :  _CreateThreadpool@4


It looks like the real name is _createthreadstub@24. So we can create breakpoints, {,, kernel32.dll}_createthreadstub@24.






Run the program, and when you encounter a pause, ignore the message prompt for no related source code at the breakpoint location.






Use the Call Stack window to view the code that calls this function.






Tip 18: Loading symbols



When you debug a program, the Call Stack window may not display all of the call stacks, ignoring the information of the system DLL (such as Kernel32.dll, User32.dll).






By loading the symbolic information of these DLLs, you can get all call stack information and set this effect directly in the Call Stack window using the context menu (right-click menu). You can download these symbols from predefined symbol paths or from Microsoft's symbolic servers (for system DLLs). After these symbols are downloaded and imported into the debugger, the call stack is updated as follows:






These symbols can also be imported from the Module window.






Once loaded, the symbols are saved in the cache and can be configured in Tools>options>debugging>symbols.






Tip 19: Report A memory Leak in MFC



If you want to monitor memory leaks in an MFC application, you can use the macro debug_new to redefine the new operator, which is a modified version of the new operator, and can record the file name and number of rows for which it allocates memory. The debug_new built in the release version resolves to the original new operator.



MFC Wizard-generated source code in #include after Mina contains the following preprocessing directives:


#ifdef _DEBUG
#define NEW debug_new
#endif


The above code is the way to redefine the new operator.



Many STL header files are incompatible with the new operator defined here. If you include the <map><vector><list><string> header file after redefining the operator new, you will have the following error (in <vector> for example):


1>c:\program files (x86)\microsoft visual studio 9.0\vc\include\xmemory(43) : error C2665: 'operator new' : none of the 5 overloads could convert all the argument types
1>    c:\program files\microsoft visual studio 9.0\vc\include\new.h(85): could be 'void *operator new(size_t,const std::nothrow_t &) throw()'
1>    c:\program files\microsoft visual studio 9.0\vc\include\new.h(93): or    'void *operator new(size_t,void *)'
1>    while trying to match the argument list '(const char [70], int)'
1>    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xmemory(145) : see reference to function template instantiation '_Ty *std::_Allocate<char>(size_t,_Ty *)' being compiled
1>    with
1>    [
1>      _Ty=char
1>    ]
1>    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xmemory(144) : while compiling class template member function 'char *std::allocator<_Ty>::allocate(std::allocator<_Ty>::size_type)'
1>    with
1>    [
1>      _Ty=char
1>    ]
1>    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xstring(2216) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1>    with
1>    [
1>      _Ty=char
1>    ]


The workaround is to use Debug_new to redefine the new operator after you include the STL files.



Tip 20: Debugging ATL



When you develop an ATL COM component, you can view the invocation of the QueryInterface, AddRef, and release of the COM object you are developing in debugger. The production of these calls is not supported by default, and you need to define two macros in the preprocessing definition or precompiled header file. After these two macros are defined, calls to these functions are displayed in the Output window.



The two macros are:



_atl_debug_qi, displays the name of each queried interface. must be defined before the Atlcom.h header file is included.
_atl_debug_interfaces, whenever AddRef or release is invoked, displays the number of references to the current interface and information such as the class name, interface name, and so on. must be defined before atlbase.h is included.



The above is the entire content of this article, I hope that we have shared the previous articles to learn, proficient in Visual Studio debugging skills.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.