DOCUMENT:Q121556 11-FEB-2002 [visualc] TITLE :PRB: Breakpoints Won't Work - 12 Reasons Why PRODUCT :Microsoft C Compiler PROD/VER::1.0,1.5,1.51,1.52,2.0,4.0,5.0,6.0 OPER/SYS: KEYWORDS:kb3rdparty kbtshoot kbCodeView kbDebug kbide kbVC100 kbVC150 kbVC151 kbVC152 kbVC200 kb ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5, 1.51, 1.52 - Microsoft Visual C++, 32-bit Editions, versions 1.0, 2.0, 4.0, 5.0, 6.0 ------------------------------------------------------------------------------- SYMPTOMS ======== This article describes 12 possible reasons why you may be having trouble getting breakpoints to work. It covers each of the following 12 situations where breakpoints do not work as expected: - Can't set breakpoint in a Windows Exit Procedure (WEP). - Problems when using Program Manager replacements. - Can't set breakpoint on expression that uses out-of-scope variables. - Breakpoints fail when multiple source files have the same name. - Can't set breakpoint in the WndProc of a child window in a DLL. - Can't set breakpoint in source file when corresponding symbolic information isn't loaded into memory by debugger. - Breakpoints missed when DLL unloaded and reloaded in same debug session. - Breakpoints missed when DLL loaded into memory before debug session starts. - Missed breakpoints when more than one copy of DLL on your hard disk. - Can't Set "Break When Expression Has Changed" Breakpoint on a variable local to a DLL. - Visual C++ Version 1.0 and 1.5 IDE debuggers won't stop on a breakpoint in an MFC message handler for the WM_QUERYENDSESSION Message. - Can't set breakpoints on desired lines if program is built without /Od option. MORE INFORMATION ================ Can't Set Breakpoint in a Windows Exit Procedure (WEP) ------------------------------------------------------ This is by design. Instead, you can call DebugBreak() or hard code an int 3 interrupt in your WEP using code like this: #ifdef _DEBUG DebugBreak(); // _asm int 3; /* alternate */ #endif Note: These two suggestions will only work if you explicitly load and free the DLL in question using LoadLibrary() and FreeLibrary(), respectively. Problems When Using Program Manager Replacements ------------------------------------------------ Customers have reported problems with breakpoints when using Program Manager replacements such as Norton Desktop for Windows or PC Tools for Windows. Reported problems include: - Missed breakpoints. - A general protection (GP) fault after pressing the F8, F10, or F5 key to continue when you reach the first breakpoint. - Loss of breakpoints once set. Switching the Visual C++ integrated debugger to Hard mode may solve these problems, but Microsoft recommends that you not use Program Manager replacements while debugging. Can't Set Breakpoint on Expression that Uses Out-of-Scope Variables ------------------------------------------------------------------- Attempting to set a breakpoint on an expression before the variables in the expression have come into scope will not work unless specific steps are taken. For example, you can't set a breakpoint when an expression has changed (or is true) and that expression contains a variable local to a function that has not yet been executed. The debugger can't evaluate the expression because the variable has not yet been allocated on the stack. To work around this problem, you can use the context operator to specify the scope in which the expression should be evaluated. In the Expression field of either CodeView or the IDE debugger, type in the expression using this form: {function_name,source_file.cpp,appdll.exe} expression This tells the debugger to evaluate the expression within the scope of function_name. This is precisely what is needed if one or more of the variables in the expression do not exist outside of function_name. NOTE: "Break at Location if Expression has Changed [or is True]" also needs the same qualification for the same reasons. For more detailed information on the syntax and use of the context operator, please refer to Chapter 4 of the "Visual C++ CodeView Debugger User's Guide," or search for "context operator" in CodeView's Help menu. Breakpoints Fail When Multiple Source Files Have the Same Name -------------------------------------------------------------- If two or more source files in the project have the same name, breakpoint problems are likely to occur. This often occurs in cases where the user-named module has the same name as one of the components of a library (debug version) they are linking with. NOTE: This is always the case when an MFC application makes calls to a _USRDLL because the MFC code is statically linked into both the .EXE and the .DLL file. It is also the case for MFC OLE servers and containers that statically link with the MFC libraries. In these cases, the debugger may associate the debug information for a source file with the wrong copy of its binary code in memory, and the breakpoint subsequently fails. To work around this problem, try using the context operator described above. In most cases, you can use the full paths to the source file and corresponding executable module. CodeView is also able to handle these cases with the "File.Open Module" menu option. Selecting this option will display a module list that includes all copies of the same module. You can then select the one you want. Can't Set Breakpoint in the WndProc of a Child Window in a DLL -------------------------------------------------------------- You cannot set a breakpoint in the WndProc of a child window in a DLL when the calling program is not the parent. If the calling program creates a child window that's defined in a DLL, you should have no problem setting a breakpoint in the child window's WndProc because the calling program contains its parent window. However, if the calling program didn't create the child window directly, you won't be able to set a breakpoint in it. This is actually an IDE debugger issue because it is a limitation for Windows debuggers that are themselves Windows-based applications. Therefore, the only workaround is to use CodeView for Windows, which is a character-based application, not a true Windows-based application. Can't Set Breakpoint in Source File When Corresponding Symbolic Info Isn't Loaded into Memory by Debugger --------------------------------------------------------------------------------------------------------- You cannot set a breakpoint in any source file when the corresponding symbolic information will not be loaded into memory by the debugger. Symptoms include messages such as "the breakpoint cannot be set" or a simple, non-informational beep. When setting breakpoints before the debuggee has been started, the debugger uses a breakpoint list to keep track of how and where to set breakpoints. When you actually begin the debugging session, the debugger loads the symbolic information for all designated debuggees and then walks through its breakpoint list, attempting to set the breakpoints. However, if one or more of the debuggees have not been designated to the debugger, there will be no symbolic information for the debugger to use when walking through its breakpoint list. Situations where this is likely to occur include: - Attempts to set breakpoints in a DLL before the call to LoadLibrary. - Setting a breakpoint in an OLE server before the container has started the server. - Other similar cases. NOTE: After you receive notification that these breakpoints cannot be set, the breakpoints will usually continue to show up in the breakpoint list, but they will have a dash (-) to their left, indicating that they are disabled (have not been set). To prevent this behavior in Visual C++, specify all additional DLLs and OLE servers in the Additional DLLs field in the Options.Debug... dialog box. To prevent this behavior in in CodeView, use the /L command line switch to notify CodeView that you want it to Load symbolic debug information for additional .EXE and .DLL files. When this has been done, breakpoints set in code that has not yet been loaded into memory will be "virtual" breakpoints. When the code is actually loaded into memory by the loader, these become physical breakpoints. Ensure that these additional debuggees are not already running when you start your debugging session. Failure to follow this rule will likely cause breakpoints to be missed. Breakpoints Missed When DLL Unloaded and Reloaded in Same Debug Session ----------------------------------------------------------------------- Neither CodeView for Windows or the IDE debugger will hit breakpoints once a DLL has been unloaded and loaded again in the same debugging session. This is because the DLL will probably have moved in memory, and neither debugger handles the address fix-ups that would be required to reinsert the int 3's at the new locations. Unfortunately the bottom line here is that you can't debug a DLL once it has been unloaded; you have to exit the debug session, and start over clean. Breakpoints Missed When DLL Loaded into Memory Before Debug Session Starts -------------------------------------------------------------------------- The debugger will sometimes get confused when a DLL has already been loaded into memory before the debugging session is started. Although the DLL is the same, the debugger sees the second (or more) instance as a separate copy. If you're using CodeView, you can easily check to see if this is happening. After setting the breakpoints in the DLL and running the calling program until the DLL has been loaded, choose the Breakpoints menu option under the Data menu. If the breakpoints have VE (virtual; Enabled) before the brace, CodeView for Windows is using the wrong instance -- these breakpoints should no longer be virtual because the DLL has been loaded into memory, thus allowing virtual breakpoints to become physical breakpoints. Unfortunately, the IDE debugger does not provide a way to find out if a breakpoint is virtual. The solution is to make sure none of your DLLs are in memory before the debugging session starts. Missed Breakpoints When More than One Copy of DLL on Your Hard Disk ------------------------------------------------------------------- Having more than one copy of a DLL on your hard drive, especially if its in your Windows directory, can also cause debugger confusion. What can happen is that the debugger will load the symbolic information for the DLL specified to it at run time (with the /L command line option for CodeView for Windows, or in the "Additional DLLs" field in the IDE debugger), but Windows has actually loaded a different copy of the DLL itself into memory. Again, if you're using CodeView you can check for this by looking to see if the breakpoints have VE before them. Because there is no way to force the debugger to load a specific DLL (as opposed to loading symbolic information for one with the /L switch), it is a good idea to keep only one version of a DLL at a time in your path, current directory, and Windows directory. If you have already done this step and are still having breakpoint problems, be sure you have also followed the other steps listed above. Often breakpoint problems are the result of several key steps being missed. Can't Set "Break When Expression Has Changed" Breakpoint on DLL Local Var ------------------------------------------------------------------------- Using virtual breakpoints involving expressions poses a special problem. For example, setting a "Break When Expression Has Changed" breakpoint on a variable local to a DLL function before the call to LoadLibrary would cause the breakpoint to be virtual (there are no physical addresses for the DLL in memory yet). In these cases, not only must the DLL have been specified to the debugger at startup (thus causing its symbolic information to be loaded, as discussed above), but the DLL's executable code must also be loaded into memory before this kind of breakpoint can be set. This means that the calling application's code must be executed to the point after its call to LoadLibrary before the debugger will allow this type of breakpoint to be set. Visual C++ Version 1.0 and 1.5 IDE Debuggers Won't Stop on a Breakpoint in an MFC Message Handler for the WM_QUERYENDSESSION Message ------------------------------------------------------------------------------------------------------------------------------------ Even hard-coding an interrupt 3 (_asm int 3) has no effect. The 32-bit version of Visual C++ works as expected, as does CodeView. Therefore, use CodeView instead; it will stop as expected. Can't Set Breakpoints on desired lines if program is built without /Od option ----------------------------------------------------------------------------- This is by design. Some compiler optimizations concatenate code in the executable file. The compiler switch /Od can be used to disable all optimizations. To make sure breakpoints can be set, both the /Od and /Zi option switches should be specified. For more information, please see the following article in the Microsoft Knowledge Base: Q60338 Unable to Set CodeView Breakpoint on Desired Line REFERENCES ========== For additional information, please see the following articles in the Microsoft Knowledge Base: Q150936 FIX: VC41 Debugger Fails to Stop on Breakpoints w/ Long Names Additional query words: eleven causes codeview code view ====================================================================== Keywords : kb3rdparty kbtshoot kbCodeView kbDebug kbide kbVC100 kbVC150 kbVC151 kbVC152 kbVC200 kbVC400 kbVC500 kbVC600 Technology : kbVCsearch kbVC400 kbAudDeveloper kbvc150 kbvc100 kbVC500 kbVC600 kbVC151 kbVC200 kbVC32bitSearch kbVC16bitSearch kbVC152 kbVC500Search Version : :1.0,1.5,1.51,1.52,2.0,4.0,5.0,6.0 Issue type : kbprb ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2002.