Also talk about release version of the wrong line

Source: Internet
Author: User
Tags assert

Usually release errors are the first to catch the exception through SetUnhandledExceptionFilter, and then generate a report file, and finally locate the line of code, mainly in the following two ways:

(i) Output the call stack information to a file by traversing the call stack. Then look for an error address.

There are two ways to find:

(1) Locate the error location through the compiler generated map file containing line information.

Generate a map file containing row information by manually entering/mapinfo:lines in the project properties-〉 "link"-〉 "Project Options." Find the obj filename based on the error address range First, view the line information for the obj file, and locate the line of code according to the error address range.

(2) Locate the error location through the compiler generated PDB file.

The debug version automatically generates PDB files, release versions need to check the option "Generate Debug Info" in the project properties-〉 "link" panel, and then select the "Debug Info" list box in the project Properties-〉 "C + +" panel Program Database. "

Find the line of code in the PDB file where the error address is located, through the Dbghelp library (contained in the WinDbg directory), through the SYMFROMADDR function to obtain symbolic information SymGetLineFromAddr64 get the line of code.

There are two ways to traverse the call stack method:

(1) Traverse the call stack itself

The flaw with this approach is that release versions typically use FPO (Frame-pointer omisstion) Optimizations, (note: In the VC compiler, you can-> "C/s + +"-> "Project Options" in "Engineering properties" To remove the option oy-turn off PFO optimization), PFO optimization is to improve the code efficiency by omitting the save recovery of the stack pointer during the call. The following methods of traversing the call stack themselves may traverse incomplete and omit some functions from the module using FPO optimization. Therefore, even if its own module shuts down the FPO, but the Third-party module uses FPO, if the address of the error is in a Third-party DLL (for example, Mfc42.dll), it is possible to backtrack from the problematic function within its own module, making it difficult to locate the bug.

The traversal itself is based on the following principles (this principle applies only to functions that do not use FPO optimizations):

1 function calls, the call instruction presses the return address (usually the address of the next instruction) into the stack.

The 2 function runs the first line and presses the EBP onto the stack, saving it so that the proper function return can restore the EBP.

3 Copy current stack position esp to EBP.

4. Then esp self reduction to empty out stack space to accommodate functions of local variables

So the EBP in the current function is the top position of the stack after the 2nd step is pressed into the EBP, from this, we can deduce that the EBP of the previous function is [EBP], and the previous function return address is the value of the previous indentation stack, that is, [ebp+4], from which you can backtrack the call stack step by step.

(2) traversing the stack through the DBGHELP library function StackWalk64.

This way you can choose whether to load the PDB, and for those functions that have been FPO optimized, the PDB holds the relevant data to help traverse the call stack, and if you cannot load the correct pdb,stackwalk64, you will traverse the call stack using the Ebp method described earlier. Thereby omitting the functions that are FPO optimized.

(b) Locating bugs by generating a mini dump file.

Through the DBGHELP library function MiniDumpWriteDump will error information to write to the file, and then open the dump file with WinDbg, configuration good symbols path, exe file path, source code path, Enter the. ECXR command to view the detailed call stack, and to automatically open the source file to the line of code. So this method is the simplest and most reliable method.

The following is a simple Dume class that automatically generates dum files if an error is added to the project.

#include <windows.h>
#include <tchar.h>
#include <assert.h>

For VC6
#ifndef __in_bcount_opt
#define __IN_BCOUNT_OPT (x)
#endif
#ifndef __out_bcount_opt
#define __OUT_BCOUNT_OPT (x)
#endif

End (for VC6)
#include "Dbghelp.h"

typedef BOOL (WINAPI *minidumpwritedump)
(
In HANDLE hprocess,
In DWORD ProcessID,
In HANDLE hfile,
In Minidump_type Dumptype,
In CONST pminidump_exception_information Exceptionparam,
OPTIONAL in CONST pminidump_user_stream_information Userstreamparam,
OPTIONAL in CONST pminidump_callback_information callbackparam OPTIONAL
);

Class Cminidumper
{
Public
Cminidumper ();
Private
Static Lptop_level_exception_filter S_pprevfilter;
Static long WinAPI UnhandledExceptionFilter (struct _exception_pointers *pexceptioninfo);
};

Cminidumper G_minobject;
Lptop_level_exception_filter cminidumper:: s_pprevfilter = 0;

Cminidumper::cminidumper ()
{
ASSERT (!s_pprevfilter);
S_pprevfilter =:: SetUnhandledExceptionFilter (UnhandledExceptionFilter);
}

Long Cminidumper::unhandledexceptionfilter (struct _exception_pointers *pexceptioninfo)
{
LONG ret = Exception_continue_search;
TCHAR Szdbghelppath[_max_path] = {0};
TCHAR Szdumppath[_max_path] = {0};
TCHAR Szpath[_max_path] = {0};

 if (GetModuleFileName (NULL, szpath, _max_path))
 {
  tchar szdrive[_max_drive] = {0};
  tchar szdir[_max_dir] = {0};
  tchar szfilename[_max_fname] = {0};
  _tsplitpath (szpath, szdrive, Szdir, szFileName, 0);
  _tcsncat (Szdbghelppath, szdrive, _max_path);
  _tcsncat (Szdbghelppath, Szdir, _max_path-_tcslen (Szdbghelppath)-1);
  _tcsncat (Szdbghelppath, _t ("Dbghelp.dll"), _max_path-_tcslen (Szdbghelppath)-1);
  _tcsncat (Szdumppath, szdrive, _max_path);
  _tcsncat (Szdumppath, Szdir, _max_path-_tcslen (Szdumppath)-1);
  _tcsncat (Szdumppath, szFileName, _max_path-_tcslen (Szdumppath)-1);
  _tcsncat (Szdumppath, _t (". DMP"), _max_path-_tcslen (Szdumppath)-1);
 }

Hmodule hDLL =:: LoadLibrary (Szdbghelppath);
if (hDLL = = NULL) hDLL =:: LoadLibrary (_t ("Dbghelp.dll"));
ASSERT (hDLL);

if (hdll)
{
MiniDumpWriteDump Pwritedumpfun = (minidumpwritedump):: GetProcAddress (hDLL, "minidumpwritedump");
if (Pwritedumpfun)
{
Create the file
HANDLE hfile =:: CreateFile
(
Szdumppath,
Generic_write,
File_share_write,
Null
Create_always,
File_attribute_normal,
Null
);

if (hfile!= invalid_handle_value)
{
_minidump_exception_information Exinfo;
Exinfo.threadid =:: GetCurrentThreadID ();
Exinfo.exceptionpointers = Pexceptioninfo;
Exinfo.clientpointers = FALSE;
Write the Dump
if (Pwritedumpfun getcurrentprocess (), GetCurrentProcessId (), hfile, Minidumpnormal, pexceptioninfo!= 0? &ExInfo: 0, NULL, NULL)
ret = Exception_execute_handler;

:: CloseHandle (hfile);
}
}
}
if (s_pprevfilter) ret = S_pprevfilter (pexceptioninfo);
return ret;
}

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.