Brief introduction debugging is a must-have technique for program developers. If you won't debug, once you write, once you have a problem, you often have no way. I have summarized 10 years using VC experience and make a shallow introduction to debugging skills. I hope to be helpful. Today's simple introduction introduces call stack. Call the stack in my column articles VC debugging entry http://www.vckbase.com/document/viewdoc/?id=924 mentioned, but there is no detailed introduction. First introduce what called calling stack: Suppose we have several functions, is Function1, Function2, Function3, Function4, and Function1 call function2, function2 call function3, function3 call function4. During the function of Function4, we can learn from the thread current stack to call his functions. From the order relationship of the function, Function4, Function3, Function2, Function1 present a "stack" feature, and finally called the function appears above. So this relationship is therefore called the Stack. When the fault occurs, if the program is interrupted, we can only see the final error function. With Call Stack, we can know that when the wrong function is called, it is wrong. It seems to be a reason why the error can be guessing. The discontinuation of the Assert macro caused by this interrupt. When the program is interrupted, the second button on the right side of the debug toolbar is generally the Call Stack button. After this button is pressed, you can see the current call stack. Example 1: Introduction We first demonstrate the calling stack. First we create a dialog project called Debug. After the engineering creation, double-click the OK button to create a message mapping function, and add the following code: void cdebugdlg :: onok () {// Todo: add extra validation here assert (false);} We press F5 to start debugging procedures. After the program runs, click the OK button, the program will be interrupted.
At this point, check the Call Stack window, you will find the following: cdebugdlg :: onok () line 176 34 bytes _afxdispatchcmdmsg (cdtarget * 0x0012fe74 {cdebugdlg}, unsigned int 1, int 0, void (void) * 0x5f402a00 `vcall ' void), void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO * 0x00000000) line 88 CCmdTarget :: OnCmdMsg (unsigned int 1, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 39 bytes CDialog :: OnCmdMsg (unsigned int 1 , int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 97 24 bytes CWnd :: OnCommand (unsigned int 1, long 656988) line 2088 CWnd :: OnWndMsg (unsigned int 273, unsigned int 1, long 656988, long * 0x0012f83c ) line 1597 28 bytes CWnd :: WindowProc (unsigned int 273, unsigned int 1, long 656988) line 1585 30 bytes AfxCallWndProc (CWnd * 0x0012fe74 {CDebugDlg hWnd = ???}, HWND__ * 0x001204b0, unsigned int 273, unsigned INT 1, long 656988) LINE 215 26 BYTES AFXWNDPROC (HWND__ * 0x001204B0, Unsigned Int 273, Unsigned Int 1, Long 656988) LINE 368 AFXWNDPROCBASE (HWND__ * 0x001204B0, UNS igned int 273, unsigned int 1, long 656988) line 220 21 bytes USER32! 77d48709 () USER32! 77d487eb () USER32! 77d4b368 (USER32)! 77d4b3b4 () NTDLL! 7c90eae3 () USER32! 77d4b7ab () USER32! 77d7fc9d ( ) USER32! 77d76530 () USER32! 77d58386 (USER32! 77d5887a () USER32)! 77d48709 (USER32! 77d487eb () USER32)! 77d489a5 (USER32)! 77d489e8 () USER32! 77d6e819 () USER32! 77d65ce2 () CWnd :: IsDialogMessageA (tagMSG * 0x004167d8 {msg = 0x00000202 wp = 0x00000000 lp = 0x000f001c}) line 182 CWnd :: PreTranslateInput (tagMSG * 0x004167d8 {msg = 0x00000202 wp = 0x00000000 lp = 0x000f001c}) line 3424 CDialog :: PreTranslateMessage (tagMSG * 0x004167d8 {msg = 0x00000202 WP = 0x00000000 lp =
0x000f001c}) line 92 CWnd :: WalkPreTranslateTree (HWND__ * 0x001204b0, tagMSG * 0x004167d8 {msg = 0x00000202 wp = 0x00000000 lp = 0x000f001c}) line 2667 18 bytes CWinThread :: PreTranslateMessage (tagMSG * 0x004167d8 {msg = 0x00000202 wp = 0x00000000 lp = 0x000f001c}) line 665 18 bytes CWinThread :: PumpMessage () line 841 30 bytes CWnd :: RunModalLoop (unsigned long 4) line 3478 19 bytes CDialog :: DoModal () line 536 12 bytes CDebugApp :: InitInstance ( ) line 59 8 bytes AfxWinMain (HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 39 11 bytes WinMain (HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 30 WinMainCRTStartup () LINE 330 54 BYTES KERNEL32! 7C816D4F () Here, CDEBUGDIALOG :: Onok As the last calling function in the entire call chain appears at the top of the Call Stack, the launch function of the routine in the kernel, KERNEL32! 7C816D4F () as the bottom The appearance is at the bottom. Example 2: Learning Processing Microsoft provides a suggested structure for the MDI / SDI model to provide document processing. Sometimes everyone wants to control a certain link. For example, we want to pop up your own open file dialog, but don't want yourself to implement the opening process of the entire document, and more willing to do other parts of the work. However, we don't know how the MFC handles documents, and you don't know how to insert custom code. Fortunately, we know that when a document is opened, the system will call the CDocument derived class Serialize function, we can use this to track the MFC's processing. We first create a default SDI project TEST1 and add a breakpoint, run the program, and open a file at the beginning of the ctest1doc :: serialize function.
At this time, we can see that the call stack is (I only intercepted a piece of interest): ctest1doc :: serialize (carchive & {...}) line 66 cdocument :: onopendocument (const char * 0x0012f54c) line 714 CSINGEDEMPLATE: : OpenDocumentFile (const char * 0x0012f54c, int 1) line 168 15 bytes CDocManager :: OpenDocumentFile (const char * 0x0042241c) line 953 CWinApp :: OpenDocumentFile (const char * 0x0042241c) line 93 CDocManager :: OnFileOpen () line 841 CWinApp: : OnFileOpen () line 37 _AfxDispatchCmdMsg (CCmdTarget * 0x004177f0 class CTest1App theApp, unsigned int 57601, int 0, void (void) * 0x00402898 CWinApp :: OnFileOpen, void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO * 0x00000000) line 88 CCmdTarget :: OnCmdMsg (unsigned int 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 39 bytes CFrameWnd :: OnCmdMsg (unsigned int 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 899 33 bytes CWnd :: Oncommand (Unsigned Int 57601, Long 132158) Line 2088 CFrameWnd :: OnCommand (unsigned Int 57601, long 132158) LINE 317 View from the above call stack, This process is triggered by a WM_COMMAND message (because we open the file with the menu), by cwinapp :: ONFileOpen first start the actual processing process, this function calls CDOCManager: ONFILEOpen to open the document.
We first double-click CWINAPP :: OnfileOpen () Line 37 Open CWINAPP :: OnfileOpen, its processing is: assert (m_pdocmanager! = Null); m_pdocmanager-> onfileOpen (); m_pdocmanager is an instance pointer for a CDOCManager class, we double click CDOCManager :: OnFileOpen line to see implementation of the function:! void CDocManager :: OnFileOpen () {// prompt the user (with all document templates) CString newName; if (DoPromptFileName (newName, AFX_IDS_OPENFILE, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL) ); // open cancelled AFXGetApp () -> OpenDocumentfile (NEWNAME); // if returns null, the user has already been alerted} is clear, the function first calls the DOPROMPTFILENAME function to get a file name, then continue follow-up Open the process. Shun this clue, we must find the location where our file opens the dialog box. Since this is not the focus of our research, I will not be detailed in the following analysis. Example 3: Memory Access Debutors In the DEBUG version of the VC program, the program will give each NEW, reserve several bytes as the use of crossed detection. When the memory is released, the system checks these bytes to determine if there is a possibility of memory access. We borrow the previous example programs, add the following lines of code at CTEST1APP :: InitInstance: char * p = new char [10]; MEMSET (P, 0, 100); delete [] p; return false; very clear, this paragraph The code applies for 10 bytes of memory, but uses 100 bytes. We are in MEMSET (P, 0, 100); this line adds a breakpoint, then executes the program, after the breakpoint arrives, we observe the value of the pointer (using the demug tool bar's Memory function), you can find that its value is: CD CD CD CD CD CD CD CD CD CD FD FD FD FD FD FD 00 00 00 00 00 00 00 00 ...... based on experience, P actually allocated 16 bytes, six bytes for the protection.
We press the F5 full-speed executive program, which will find the following error message being popped up: Debug Error! Program: C: /Temp/test1/debug/test1.exe Damage: After Normal Block (# 55) AT 0x00421ab0 Press Retry to debug the application This information prompts, in the normal memory block 0x00421AB0, the memory is broken (memory access), we click Retry to enter the debug state, discover the calling stack is: _free_dbg_lk (void * 0x00421ab0, int 1) Line 1033 60 Bytes _free_dbg (void * 0x00421AB0, INT 1) Line 970 13 Bytes Operator Delete (void * 0x00421ab0) line 351 12 Bytes Ctest1app :: InitInstance () Line 54 15 Bytes Obviously, this error is when calling Delete, appearing in ctest1App :: InitInstance () Line 54 15 Bytes. We can easily find this information. In the release of which block, there is a problem, after we only need to make an error based on the memory of this memory, which will greatly reduce the difficulty of debugging. Example 4: Subclassization is a common way to modify an existing control to implement new features, and we borrow an instance of the Debug dialog project to demonstrate a story that I have learned in the past.