Use Microsoft Visual Studio and rational purify for runtime debugging (1)

Source: Internet
Author: User
Tags microsoft c microsoft outlook
This article is divided into two parts. Here we will first learn some basic usage Visual Studio Debugging Win32 Basic application knowledge. By Goran begic, technical marketing engineer, development solutions, IBM Rational Translation: wyingquan # hotmail.com 2006-02-09Figure 1: Visual Studio debugger window
Every time we mention how much we have done to improve the quality of software, developers will always be assured that there is no problem. However, you must always remember the fact that there will always be bugs in the program. After all, the program is designed by humans, so of course there will be no bugs. Therefore, debugging-the most time-consuming and expensive process of fixing defects-always occupies a place in large-scale software development. Broadly speaking, debugging also involves a variety of programming technologies that allow developers to anticipate potential problems in the program. Due to the high complexity of the development process, debugging becomes more complicated. In fact, to fully control the entire debugging activity, you must pay attention to the entire development process. As some "debugs" will tell you, locating the cause of the defect is the most difficult in all work; fixing the code defect is the simplest step in the debugging process. The first part of this article will introduce you to the Microsoft Visual Studio program development environment and discuss the most basic program debugging methods using the Microsoft Visual Studio compiler.

Various Bug

To be precise, what is a bug? If your application crashes on any machine, you will know that the program has a bug. But what about the following? I was proud to announce that the program runs well through my own tests. But soon after, some important customers reported some difficult "problems" that only appeared in some configuration on some machines. We also need to call this problem a bug. In fact, many different types of problems are called bugs. Data corruption is the highest among them, however, application design defects or even Interface Design chaos may make user operations inconvenient (that is, they do not conform to the user's habits or conventions ). For example, if you use the shortcut key Ctrl + F in Microsoft Outlook, the pop-up window is not the expected look-up window, but the forward window (in almost all applications, CTRL + F ).

  Debugging methods and techniques 

A popular slogan is "Defensive Programming ". This is a method composed of many technologies and policies used to write code, which helps to detect errors early. For example, writing clever code using symbols (variable names) that all developers understand and recognize helps reduce bugs. In addition, defensive programming techniques include a large number of very useful macro definitions and functions provided by programming languages, which help you check important events during program execution. You should debug the program even when measuring software quality. With excellent quality assurance, project management personnel can make decisions for later system development. To avoid release delays due to bugs in the code, you should start debugging as early as possible throughout the development cycle. For example, the ideal solution is to start at the project schedule-to sort Requirements for the first prototype. Adding too many features to an early prototype may lead to an increase in defects, which may lead to significant manpower and time spent on fixing these features. The time spent debugging a software with too many features is far more than the time spent on a simple and strong program. You should also maintain a consistent programming environment among all project teams, consistent documentation and code-use Version Control Software-and perform a "smoke test" on the modified program ". If you document all the changes to the source code, you will find that new bugs are commonly found in the recently modified code, focusing on these changes will greatly reduce the time spent on problem fixing. As I mentioned earlier, no matter how careful or maintained your code, or even your program looks to run correctly, the actual situation is that the program also contains bugs. Software development tools generally take these into consideration and include software defects that can be eliminated as much as possible. What are the basic tools required by developers? At least four: an editor, a compiler, and a debugger. An automated runtime debugger without these tools, you cannot develop a successful application. In fact, the debugger is added to the above list only recently during Automatic Running. Its main task is to locate the error while the program is running, these programs may be difficult to manually complete during running-even for some developers.

  Visual Studio Program Development Environment 

In this article, I will fully understand the runtime debugging of a piece of code built using the mocrosoft VISUAL C ++ compiler. Of course, there are many other types of compilers available on the market, some of which are provided for free, but the reason why I chose this tool is that it is most likely that you have installed it. It does not generate code quickly, nor does it have no bugs. It is not the compiler that best complies with the ansi c ++ standard, however, it is widely used in software development on the C ++ Win32 platform. I will start with some possible terms and tools. Although these are already quite familiar to Visual C ++ developers, they may be unfamiliar to those who are on Unix or Java. 

Visual Studio Integrated Development Environment (IDE)

Many applications use this environment for development. It consists of an editor and menus and toolbar to call compilers, connectors, and debuggers. You may also use code written in other editors to call the Visual C ++ compiler and connector through command lines.
VC ++ Engineering

A Visual C ++ Project is a folder that stores all the files used to build applications. It is automatically generated after you select the program type. You can also create an empty project and write the code separately. When you build an application, it is generated in the subfolders of the project folder by default. By default, there is a compilation type: Debug and release. The debug version contains additional information that helps Debug programs. The release version only contains the most basic information for release. The release version of the program is optimized in size and speed, and some program source code information is not exposed to the end user. The project definition file is saved in the file with the extension. DSP, and the workspace information is saved in the file with the extension. DSW. 

Debugger

It is used to control the program running, so that users can browse every execution step of the program, check all variables used by the program, all memory allocation, and the content in the registers of the processor. Because even a fairly simple application may contain thousands of machine commands. If you want to browse these commands, you must be familiar with these machine codes and always check the application through them. You can use the debugger (Visual Studio debugger) to set breakpoints in the source code to check the running status of the program at the breakpoint location. 

Debugger window

When running a program in Visual Studio debuger, it opens some default Windows. You can also open other debugging windows as needed. Figure 1 shows the windows that I often open when using Visual Studio debugger. The main window of Visual Studio debugger is the standard editing window. The arrow points to the position where the current application is executed. If the breakpoint set in the source file cannot be reached, the debugger displays the Assembly window as a raw machine code. On the right side of the visual studil debugger interface, you can see the register window and the stack call window: · "register" window displays the register content. It can be used to view the name and content of the CPU register. If the "register" window is always opened during the execution of the program, the register value changes during code execution. Recently changed values are displayed in red. · The "call stack" window allows you to view function names, parameter types, and parameter values on the call stack. The call stack information is displayed only when the program being debugged is interrupted. The "Memory" window is under the call Stack window. Displays the virtual memory content pointed to by the specified address. You can enter the address you want to view in the address bar of the window to view the content it points. You can also drag variables or addresses from the source code window or other debugging windows to view the corresponding content in the window. Last, we will introduce the Variable Window and monitoring window: · The Variable Window contains three tabs. Automatic: When you debug a local application and call a function (F10) by process, the "Automatic window" displays the return values of this function and all functions that may be called by this function. Local variable: contains the names, values, and types of all local variables in the current range. This (me): displays the name, value, and type of the object pointed to by this pointer. You can directly enter the variable name or drag the variable from the source code and debugging window to the window to display their values. · Monitoring window. You can use the monitoring window to calculate variables and expressions and retain the results. You can also use the monitoring window to edit the values of variables or registers. You can also directly enter the variable name or drag the variable from the source code and debugging window to the window to display their values. 

Use the compiler for debugging

The compiler is used to compile the source code into machine code. However, the compiler has more than just these functions. It can also be used to detect various errors found during compilation and some potential problems with static memory allocation. For example, if you have noticed the warning level of the compiler, you can also choose the correct warning level settings to avoid unnecessary troubles. Almost all compilers detect syntax errors, but even if there are no syntax errors in the code, it does not mean that there are no errors in the code. Let's take a look at the following example: Pleftedge = new char (strlen (pleft) + 1 ); Strcpy (pleftedge, pleft ); Pleftedge = new char (strlen (pright) + 1 ); Strcpy (prightedge, pright );If you do not check its parameters before using the strcpy () function-or use the copy/paste function in a large number-this bug may affect you in the future. The compiler will not think that such code is wrong because its syntax is correct. Running programs that contain such code will soon be exposed, because the root cause is that you use an uninitialized string as a parameter of the stecpy function (prightedge, pright. We will use this example later. Then we will debug a program with similar problems. However, the compiler may be quite useful in some cases. Next, we will introduce in detail the real-time debugging methods for code built using Microsoft C ++ compiler. Visual c ++ Debugging settingsVisual c ++ provides two default building settings: release (release) and debug (Debug ). The two build configurations use the same compiler, And you can set the parameters of the two configurations at will. For C ++, after some options are modified, they still belong to the release and debugging versions. So someone may ask, what is the difference between the release and DEBUG Versions? The debug configuration contains information that helps Debug programs, and the release configuration aims to improve program performance. Because most programmers prefer to test a program that is close to release, I will introduce some knowledge about debugging the release and explain the differences between the release and DEBUG Versions.

Symbol debugging information

The major difference between the release and DEBUG Versions is that by default, debugging information is created for debugging configurations. If you are debugging the release program, make sure that parameters related to creating the symbol debugging information are set in the compiler and connector options. The symbolic information file is stored in a separate file or code segment, which contains a series of information from assembly instructions to source code. Without this information, debugging can only be performed at the Assembly level. Although some people may understand the assembly code, this is obviously not convenient for debugging. There are multiple types of symbolic debugging information. The default Microsoft compiler type is the so-called PDB file, which is created using the parameter/Zi or/Zi (the information created using this parameter has the "edit and continue" feature ). By default, the PDB file is saved in the DEBUG directory, with the same name as the execution file name. The extension is. PDB. Note that by default, the visual C ++ 6 compiler creates a file named vc60.pdb generated during compilation, the compiler does not know the name of the executable file to be generated. The. OBJ file is not determined before the connector is activated, so the information is temporarily saved in this file. By default, the connector does not merge it into the projectname. PDB file unless you have set them to merge. The default option for generating PDB by connector in Visual Studio is/pdbtype: Sept. You can also change to/pdbtype: con in the release and debug configurations. Con indicates "unified ". If you change these settings in debug settings of Visual Studio, the connection settings will not change. I think using settings to generate a separate PDB file will have some advantages in performance, but you can ignore this because today's machine configurations are already quite high. If you want to debug your program on another machine, it is very important to include the symbolic debugging information. If you use other testing tools, you must also provide the required symbolic debugging information. To maintain integrity, the PDB file must match the execution file. It must be placed in the same directory and do not use the connection options I mentioned above. In addition, the optional debugging types for generating symbols are C7-compatible (use the compilation option/z7 to upload a .objfile and an .exe file with the line number used by the debugger and all the debugging information for the symbols) and "line numbers only" (use the compilation option/ZD to modify. OBJ file or executable file translation, so that it only contains global and external symbols and line number information, but does not contain symbol debugging information ). Debugging information generated when you select to be compatible with the C7 type is included in the execution file and contains debugging information for line numbers and all symbols. This is compatible with the codeview format in DOS. Line numbers only does not contain symbolic debugging information. 

Relocation Information

Location information, or "relocs", is a table information that is stored in a binary executable file that contains location information. This information serves all address information. When the execution module loads a base address to the memory, other addresses are set by the connector. If the execution module is loaded to a predefined base address, the relocation information is useless. Runtime debugging tools such as rational purify use this information to "plug in" modules ", purify often has to relocate the plug-in module in the memory (if the original position cannot be used again ). The project connection setting option/fixed: No provides the function of forcibly setting the information of the relocation module. This option is not set in release settings. You must manually add it in the connection Settings dialog box.

  Optimize Compilation

The purpose of optimization is to make the created target code smaller (with less memory) or to speed up execution. For this purpose, the compiler has made various Optimizations to the assembly code. For example, remove unnecessary code, remove redundant expressions, optimize loops, and use inline functions. For debugging purposes, disable all Optimization Options in the release and debug editions. Optimizing compiled code makes debugging more difficult. It also means that it is much more difficult to set a breakpoint when debugging a program with optimized compilation than to debug an unoptimized version.

  Used during connection Debug Version Runtime Library

By default, the build settings of the debug version include the debug version C Runtime Library in the connection phase. This will be helpful for finding bugs, because the dynamic memory allocation of the debug version is used. For example, the bitwise mode is added to identify the allocated memory, and the information helps to detect whether cross-border access has occurred. They also occupy a certain amount of memory and are located behind each newly allocated memory block. Therefore, they are called "daemon bytes" and used to check out-of-bounds access. The memory allocation functions of the debug version are malloc_dbg and heap_alloc_dbg. In this way, all the calls to malloc () and new () will be interpreted as debugging functions. Both the free () and delete () Functions of the memory release function are interpreted as the debug function free_dbg. The uninitialized memory content is 0xcd. The memory content on the boundary of the memory allocation structure is 0xfd and the idle memory content is 0xdd. Using the Runtime Library of the debug version in the build configuration of the release version will also make the build of the debug version. And if you have a commercial runtime debugging tool, you will not be able to use it. Therefore, it is very important to use dynamic connection to the Runtime Library when building the debugging program of the release version (the default compilation option is/MD ). 

Warning Level

The default warning level of Visual Studio is level 3 (compilation option/W3 ). This level will report information such as called before function prototype execution. For debugging purposes, you can modify the warning level to/W4 to help detect all uninitialized local variables and those that have been initialized but are not used. The lack of knowledge about the visual C ++ compiler is helpful. This is partly because/W4 also produces a large amount of false warning information (that is, it will report false positives), which makes it difficult to locate potential problems. However, if you treat all warning messages as errors, the code you write will certainly have fewer defects than the code written at the default level. Another advantage of/W4 level is that it can prevent assertion failure.

  In Debug Captured in version Release Version error

When the/GZ option is used, Visual C ++ automatically initializes all local variables (with a value of 0 xcccccccc), checks the validity of the function pointer call stack, and checks the validity of the call stack. This option is enabled by default in the default settings of the debug version. You can also set it manually in the configuration of the release version.

  Runtime debugging: all are memory-related

When you want to execute your program, it will first be loaded into the memory. In fact, because Windows uses the memory ing mechanism, only some of the execution files are swapped into the memory when needed. In addition, Windows uses portable Format documents, which are structured in the same way as their images in the memory. 

Stack and stack

When the program starts, the memory page is used to save all static and dynamic data used by the program. Each process uses at least two types of memory areas: Stack or static data block, which is the memory area that stores all automatic variables. On the Win32 platform, each thread has its own static memory area. The size of the heap used by the main program thread is determined during compilation. By default, the value is 1 MB. You can also specify the stack size using the connection option/Stack: Reserve [, commit. You can also overwrite this value using the stacksize statement in the module definition file, or use the editbin. Ext tool to directly modify the binary executable file. · Heap, or free storage zone, is an unrestricted area in the virtual memory, identified by a handle, and the use range is limited only by the available virtual memory. The dynamic structure and handle are allocated at runtime. Each process has at least one default heap, but some processes may have many dynamic heaps. During the program running, the heap API function is used to allocate memory blocks from the stack. The default heap created by a process is private and cannot be used by other processes. By default, the size of the memory reserved area and commit area of the heap has been determined during the connection. You can change the default heap size (1 MB) and use the connection option/heap: Reserve [, commit]. You can also use the editbin tool to modify the compiled binary execution file. There are three types of heap allocation functions: · globalalloc/globalfree and localalloc/localfree, which are used to allocate/recycle memory on the default heap · com imalloc Allocator (cotaskmemalloc/cotaskmenfree ), memory allocation on the default heap · C Runtime memory allocation API -- New ()/delete () and malloc ()/Free (), it is used to allocate/recycle the memory on the private stack during C runtime. In addition, the virtualalloc () and virtualfree () functions in Win32 API are used to allocate virtual memory pages. You can directly call these two functions in Win32 applications, but such functions are generally not needed unless you want to allocate a large block of memory at a time.

This is just the first step in debugging-controlling and debugging the Dynamic Allocation Structure. However, it is clear that the first step is to allow the program to run. I will explain this part in part 1 of this Article.

 

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.