VC debugger advanced application-advanced breakpoint
I. Advanced breakpoint syntax
The advanced breakpoint syntax consists of two parts: 1. context section. 2. Location, expression, variable, or Windows message condition.
Use functions, source files, and binary modules to specify the context. The context representation method is as follows:
{[Function], [source file], [binary module]}
You must specify a unique and sufficient context information to obtain the breakpoint location. for example, in test. the 20 rows of CPP have a breakpoint with the Syntax: {, test. CPP ,}. 20, such as. DLL or B. DLL uses this line, and only wants. to call the DLL, you must use: {, test. CPP, B. DLL }. 20.
You can directly enter the context syntax in the VC Debugger: Location tab breakat edit box in the breakpoints dialog box. the easier way is to use the right arrow of the breatat box to open the menu, select the advanced item, and enter the breakpoint information in the Context box.
If you want to interrupt an absolute address, simply enter the address in the breakat box.
Ii. Fast interruption of any function
Enter the function name in the breadat box. if it is C ++ code, a class qualifier is also required. the debugger lists all functions that meet the conditions for selection. If you enter sufficient information, you can skip the selection process. for example, enter "cstring: Operator = (const char *)" to uniquely identify the function to be interrupted.
3. Set breakpoints in functions output by the system or DLL
Setting a breakpoint from the DLL Input Function in the program may be useless. The debugger needs to know where the context information of the function can be found. At the same time, the function name depends on whether the DLL symbol is loaded. the breakpoint can be set in system DLL only in w2k and later versions. The reason is that other systems do not provide the copy and write protection function. If this method is enabled, coff (Common Object File Format) is required, and the started loading is output in the debugger ---- select load coff & exports on the debug page of the Options dialog box.
The VC debugger uses the hierarchical symbol information method, and the complete symbol level is higher than incomplete. the PDB (Program database) file has all possible source code lines, functions, variables, and types. The priority is higher than the COFF/dbg file, and the latter only has the public function symbol, the COFF/dbg file is higher than the output name. The input name is a pseudo symbol.
During debugging, such as the debug window output: indicates that the DLL is loaded; otherwise, it indicates that the DLL is not loaded.
When no symbols are loaded, the position string used is the DLL output name. You may use the dumpbin program to view the name: dumpbin/exports dllname. for example, in loadlibrarya, set the interrupt: "{, kernel32.dll} loadlibrarya ".
If a symbol is loaded, calculate the function name based on the output function and call protocol. in the preceding example, loadlibrarya uses the _ stdcall call protocol. According to this Protocol, the following name of the function is prefixed, and the number of bytes followed by the stack is the suffix. in general, the number of parameters * 4 is the total number of bytes that the parameter occupies the stack space. The loadlibary name is: _ loadlibrarya @ 4, so the final syntax is: Or "{,, kernel32.dll} _ loadlibrarya @ 4"
Appendix: common call protocols
1. The _ stdcall call convention is equivalent to the Pascal call convention that is frequently used in 16-bit dynamic libraries. In 32-bit VC ++ 5.0, Pascal's call Convention is no longer supported (in fact, it has been defined as _ stdcall. In addition to _ Pascal, __fortran and _ syscall are not supported). Instead, they are replaced by the _ stdcall call convention. The two are essentially the same, that is, the function parameter is passed from right to left through the stack. The called function clears the memory stack of the transfer parameter before returning, but the difference is the function name modifier section (the modification section of the function name will be described in detail later ).
_ Stdcall is the default calling method of the PASCAL program. It is usually used in Win32 API. The function uses the stack pressure method from right to left and clears the stack when it exits. After compiling a function, VC adds an underline prefix to the function name, and adds "@" and the number of bytes of the parameter to the function name.
2. c call conventions (which are described by the _ cdecl keyword) are pushed to the stack in sequence from right to left. The caller pushes the parameters to the stack. The memory stack of the transfer parameter is maintained by the caller (because of this, the function that implements the variable parameter can only use this call Convention ). In addition, the function name modification conventions are also different.
_ Cdecl is the default call Method for C and C ++ programs. Every function that calls it contains the code to clear the stack. Therefore, the size of the executable file generated is larger than that of the call to the _ stdcall function. The function uses the stack pressure mode from right to left. After compiling a function, VC adds an underline prefix to the function name. Is the default MFC call convention.
3. The _ fastcall call convention is "person" as its name. Its main feature is fast because it transmits parameters through registers (in fact, it uses ECx and EDX to transmit the first two DWORD or smaller parameters, and the remaining parameters are still transmitted from the right to the left pressure stack, the called function clears the memory stack of the transfer parameter before returning). In terms of the function name modification conventions, it is different from the previous two.
_ Fastcall functions use registers to pass parameters. After compiling a function, VC adds the "@" prefix to the function name, and adds "@" and the number of parameters after the function name.
4. thiscall is only applied to "C ++" member functions. This pointer is stored in the Cx register and the parameter is pressed from right to left. Thiscall is not a keyword and cannot be specified by programmers.
5. Naked call uses 1-4 call timing. If necessary, the compiler will generate code to save the ESI, EDI, EBX, and EBP registers when entering the function, when you exit the function, the code is generated to restore the content of these registers. Naked call does not generate such code. The naked call is not a type modifier, so it must be used together with _ declspec.
The keywords _ stdcall, _ cdecl, and _ fastcall can be directly added before the function to be output, or in the setting environment... select/C ++/code generation. When the keywords added before the output function are different from those selected in the compiling environment, the keywords directly added before the output function are valid. Their corresponding command line parameters are/GZ,/GD, And/GR. The default status is/GD, Which is _ cdecl.
To fully imitate Pascal's call convention, you must first use the _ stdcall call Convention. As for the function name Modification Convention, you can use other methods to imitate it. Another thing worth mentioning is winapi macro, windows. h supports this macro. It can translate the function into an appropriate call convention. In Win32, it is defined as _ stdcall. You can use the winapi macro to create your own APIs.
4. Location breakpoint Modifier
1. Skip count.
This function is used to execute a breakpoint, but does not stop at the breakpoint until a specific number of times has been executed.
In usage, first set a standard position breakpoint, open the breadpoint dialog box, select the breakpoint, click condition, and then enter the number of times in the edit control at the bottom of the pop-up dialog box.
The Skip count is not updated when the program runs at full speed.
For example, if we know that the loop may crash, but we do not know which loop the input is much greater than the hop count modifier of the total number of cycles, we can open the breakpoint box during crash, the number of cycles that have not been executed will be listed, and the number of executed cycles can be obtained by subtracting from the total number of times.
2. conditional expressions.
The condition button in the. breakpoint box is triggered only when the expression is true. Select the first edit box and enter the expression. Rule:
. Only comparison operators of the C type can be used.
. The expression cannot call any function.
The. expression cannot contain any macro value.
If the expression is @ Tib = thread infomation block linear address, the program will be interrupted only in this specific thread. for example, if the thread @ Tib address is set to 0e000, enter "@ Tib = 0xe000" to interrupt the thread. for w98, @ FS = thread specific value is available.
If it is interrupted after a specific error, @ err is available. For example, "@ err = 2" indicates that the final error is error_file_not_found. all pseudo registers except @ CLK can be used in the watch window for conditional expressions.
Conditional expressions can be used in combination with Skip breakpoints.
3. variable changes
The program is interrupted when the variable is changed. The variable can be checked only when the position breakpoint is executed. errors are often found in the function at the top of the Call Stack. You need to call the stack in depth and compress the scope to find the root cause.
Enter the variable name in the first edit box of the breakpoint box (which can be a pointer to the listener object: * P) and the number of items to be viewed in the second edit box.
5. Global expressions and conditional breakpoints.
The debugger can monitor 1, 2, or 4 bytes of content on an address and the address. if the hardware debugging register is available, the speed is not affected; otherwise, the program will execute the ASM command in one step and check the conditions in each step, which will seriously affect the running speed.
There are 4 debugging registers in total. the hardware debugging register cannot process references with more than one double-character length. the best way to use the hardware debug register is to use expressions and data to change the actual address value of the location. for example, g_szglobal is a global array pointer with the address 0x5000. In the breakpoint dialog box, set the expression breakpoint to "* (char *) on the Data tab *)) 0x5000 = 'G' ", but if it is written as" Wo (0x5000) = 'G', the hardware debugging register is not used, each Command is executed in one step.
Similar to the global expression breakpoint, if you use the hex address of the variable to give the long pointer computing address and set the number of units to be viewed to 1, the global variable breakpoint can play the best effect. in the preceding example, if you want to interrupt a variable change, enter: "* (long *) 0x5000 ".
6. Windows message breakpoint.
The message page of the breakpoint box. You need to specify a window process. Note: In the MFC world, afxwndproc is a window process for most windows, so it will always be interrupted at the breakpoint.
A better way is to set a condition position breakpoint in cwnd: windowproc. first, find the required class's this pointer, and then in winuser. h to find the actual value of the message. Finally, you can set the condition breakpoint as follows:
{, Wincore. cpp,}. 1500 when (this = 0x12345678) & (Message = oxf) // interrupts the wm_paint message in the 0x12345678 window.
This pointer may change due to the class allocation method and code changes. Generally, you can add a processor method using the Class Wizard, and you only need to set a simple position breakpoint.
7. Tips.
1. you can set the position breakpoint in the source line and Disassembly window, and you can set ---- right-click the function to be interrupted in the call stack publicity item, Select Insert/remove breakpoint, this function is interrupted once it is returned.
2. after debugging, you do not need to delete breakpoints, but set them to invalid. the method is to right-click the breakpoint to select an invalid item or close the selected tag in the breakpoint dialog box. in this way, you can breakpoint the status at any time when necessary.
3. to easily set all breakpoints, click step into to obtain the program to be debugged before setting any advanced breakpoint. only when the program to be debugged is active can the debugger verify the preset breakpoint and display the resolve ambiguity dialog box. the debugger helps you set breakpoints faster and confirm that they are correct.
VC debugger advanced application ---- Watch window
1. format the data and expression assignment statement.
Common variable formatting characters (the expression value is followed by a comma, followed by a formatting character, for example, "(INT) 0 xFFFF, D "):
D, I: signed decimal number.
U: Unsigned decimal number.
O: Unsigned 8
X, X: hexadecimal number.
L, H: D, I, U, O, X, X long prefix or short prefix.
F: signed floating point number.
E: signed scientific notation.
G: signed floating point or signed scientific notation, which is a shorter one.
C: single character.
S: string.
Su: double-byte string.
St: double-byte string or ANSI string, depending on the Unicode string settings in autoexp. dat.
HR: Windows class tag.
WM: Windows message code.
Common memory dump object formatting characters (usage is the same as the variable formatting character ):
MA: 64 ASCII characters.
M: 16 bytes written in hexadecimal notation, followed by 16 ASCII characters.
MB: 16 bytes written in hexadecimal notation, followed by 16 ASCII characters.
MW: 8 characters long.
MD: 4 double-precision words.
MQ: 4 words with four-fold characters in length.
Mu: 2-byte character (UNICODE standard ).
#: Extend the pointer to a specified number of memory storage units (# Representing a number)
The Watch window allows you to reset the data variable format,
For example, the by and DW expressions can be used to locate the pointer offset;
Available & and * operators, and both operators can directly operate on the memory address;
You can even specify the context of a variable using the up/down specifiers.
In short, all formatting methods and specified methods are valid in the watch window.
The Watch window is a complete expression evaluation program, where you can view any conditional statements.
The pseudo register available in the expression (which can be viewed as a common variable ):
@ Err: The last error value. The getlasterror API returns the same value.
@ Tib: the thread information block of the current thread. (The debugger cannot process the "FS: 0" format ).
@ CLK: clock register.
@ Eax, @ EBX, @ ECx, @ edX, @ ESI, @ EDI, @ dip, @ ESP, @ EBP, @ EFL
: Intel CPU register.
@ CS, @ ds, @ es, @ SS, @ FS, @ GS
: Intel CPU segment register.
@ St0, @ ST1, @ st2, @ st3, @ st4, @ ST5, @ st6, @ st7
: Intel CPU floating point register.
Ii. Timely Coding
In many cases, I only want to have a general impression on the execution time between two breakpoints. @ CLK can be used to get the execution time (including the time occupied by the debugger) between the two breakpoints ).
You need to enter two @ CLK observers. The first one is @ CLK, and the second one is @ CLK = 0. The second one is to clear the timer 0 when you re-run it.
The time is in microseconds and needs to be formatted as milliseconds in most cases: "@ CLK/1000, D ".
3. Call the function in the watch window
In most cases, it is a function used to verify the data structure specially written to ensure data relevance. in releasing a component, functions that have never been called are not linked, so you don't have to worry about the impact of such functions on the release component.
If a function does not have any parameters, brackets () are also required. when calling the function, the parameters are transmitted as normal functions. The function return value is displayed on the right side of watch.
There are some restrictions:
1. function execution can only be performed in a single-threaded context. if a multi-threaded program is used, immediately clear the result from the watch window after entering the function in the watch window. Otherwise, if the debugging function is executed in the context of the second thread, the second thread is terminated immediately.
2. the debugging function must be executed within 20 seconds. If an exception occurs during execution, the program will be aborted in the debugger.
3. (common sense) only reads data from the memory for data verification. In case of any problem, call the outputdebugstring function. for example, you can change the memory or call an API function. Although this is possible, you cannot predict what may happen.
As long as you re-calculate the expression in the watch window, the debug function of the input Watch window will be executed:
When the program is running and a breakpoint is triggered.
. When you debug a code line or command in one step.
. Edit the debugging function text on the left of the Watch window and press Enter.
. Exceptions occur when running the program, and you are asked to return to the debugger.
Suggestion for using the debug function: after entering the debug function and viewing the value, immediately clear it from the watch window; write the debug function only for the most critical data structure; do not change the dump image of individual structures.
4. automatically expand your own types
Common automatic scaling is rect. after entering a rect-type variable, the values of some data members are directly displayed.
For custom type extension, you only need to add your type entry to the autoexp. dat file in the <vs common>/msdev98/bin directory.
Example:
Extends the process_information structure used by CreateProcess ().
1. Check why the debugger identifies this type. Enter the process_information variable in the watch window, right-click the variable, and select Properties. Here it is marked as _ process_information.
2. Open the autoexp. dat text file and add the extension entry. The syntax is as follows:
Type = [text] <member [format]>
In this example, to view the hprocess and hthread values, enter:
_ Process_information = hprocess = X indicates viewing in hexadecimal format. A special formatting character <, T> is used to notify the debugger to enter the type name of the easiest derived type. for example, if B is derived from a and only B has an auto-scaling rule, the auto-scaling of B will be followed by the type name B of the auto-scaling rule with Class.
V. set next statement command
You can run the program from the menu during debugging, but you can also directly set the EIP register in the watch window-be careful, it may be easy to destroy the program. in the most optimized release component, the safest way is to use this command in the Disassembly window. if the Code creates a temporary variable on the stack, you must be careful.
The most common situation is: Set a breakpoint before the function that has a problem, check the input parameters, and debug the entire function in one step. If the problem is not repeated, use set next statement to set the execution point returned to the breakpoint and change the parameters. in this way, you can test multiple assumptions in a debugging session to save test time, but it cannot be used in all scenarios because function execution will destroy its State.
Another common location is to fill in the data structure during testing, such as tables and arrays. It can be used to input additional data and view how the code is processed-it is more convenient when some data conditions are difficult to copy.