C++出现exception异常的位置如何定位?
2010-10-26 09:09
926 查看
有人问过我,在windows系统,如果C++的new产生异常exception,怎么才能知道出错的位置。
最简单的 方法是用 _set_new_handler。
如果不是 new 产生的, 或者程序非法访问内存了。
经过试验,可以先用__try __except捕获它,
在处理函数里面输出callstack调用堆栈,以及exe、dll的名字、地址、范围等信息。
处理完了返回EXCEPTION_CONTINUE_SEARCH,交给C++的try catch来继续处理。
#include <windows.h>
#include <stdio.h>
class win32_tool_help
{
public:
win32_tool_help();
virtual ~win32_tool_help();
static int show_module_list();
};
#include <tlhelp32.h>
#include <tchar.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
win32_tool_help::win32_tool_help()
{
}
win32_tool_help::~win32_tool_help()
{
}
int win32_tool_help::show_module_list()
{
HANDLE hSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE,
GetCurrentProcessId( )
);
MODULEENTRY32 me;
me.dwSize = sizeof(me);
BOOL ret = Module32First( hSnap, &me );
while (TRUE == ret)
{
_tprintf(
TEXT("hModule = %p, modBaseAddr = %p, modBaseSize = %08X, ")
TEXT("szExePath = %s, szModule = %s /n"),
me.hModule,
me.modBaseAddr,
me.modBaseSize,
me.szExePath, me.szModule
);
ret = Module32Next( hSnap, &me );
}
CloseHandle( hSnap );
return 0;
}
class win32_stack_walk
{
public:
win32_stack_walk();
virtual ~win32_stack_walk();
static int start( LPEXCEPTION_POINTERS ep );
};
#include <imagehlp.h>
#pragma comment( lib, "imagehlp.lib" )
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
win32_stack_walk::win32_stack_walk()
{
}
win32_stack_walk::~win32_stack_walk()
{
}
int win32_stack_walk::start( LPEXCEPTION_POINTERS ep )
{
const DWORD machine_type = IMAGE_FILE_MACHINE_I386;
HANDLE hProcess, hThread;
hProcess = GetCurrentProcess();
hThread = GetCurrentThread();
STACKFRAME frame = {0};
LPVOID ContextRecord = NULL;
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine = NULL; // &ReadProcessMemory;
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine = &SymFunctionTableAccess;
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine = &SymGetModuleBase;
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress = NULL;
BOOL ret = FALSE;
struct handle_frame_addr {
static
void set( ADDRESS& addr_s, DWORD addr )
{
addr_s.Mode = AddrModeFlat;
addr_s.Segment = 0;
addr_s.Offset = addr;
}
static
DWORD get( const ADDRESS& addr_s )
{
return addr_s.Offset;
}
};
handle_frame_addr::set( frame.AddrStack , ep->ContextRecord->Esp );
handle_frame_addr::set( frame.AddrFrame , ep->ContextRecord->Ebp );
handle_frame_addr::set( frame.AddrPC , ep->ContextRecord->Eip );
handle_frame_addr::set( frame.AddrReturn, 0 );
do
{
printf( "Stack = %08X Frame = %08X PC = %08X Return = %08X /n",
handle_frame_addr::get( frame.AddrStack ),
handle_frame_addr::get( frame.AddrFrame ),
handle_frame_addr::get( frame.AddrPC ),
handle_frame_addr::get( frame.AddrReturn )
);
ret = StackWalk( machine_type, hProcess, hThread,
&frame,
ContextRecord,
ReadMemoryRoutine,
FunctionTableAccessRoutine,
GetModuleBaseRoutine,
TranslateAddress );
} while( ret == TRUE );
return 0;
}
#define SHOW_ESP() /
do { /
DWORD reg_esp = 0; /
__asm { /
mov reg_esp, esp /
} /
printf("esp = %08X/n", reg_esp); /
printf("ep->Esp = %08X/n", ep->ContextRecord->Esp); /
}while(0);
void show_diag_info( LPEXCEPTION_POINTERS ep )
{
win32_stack_walk::start( ep );
win32_tool_help::show_module_list();
}
void raise01( )
{
printf("%s/n", "raise");
CONTEXT ctx_s = {0};
EXCEPTION_POINTERS ep_s;
LPEXCEPTION_POINTERS ep = &ep_s;
ep_s.ContextRecord = &ctx_s;
SHOW_ESP();
memset( 0, 1, 1 );
}
void raise02( )
{
printf("%s/n", "raise");
CONTEXT ctx_s = {0};
EXCEPTION_POINTERS ep_s;
LPEXCEPTION_POINTERS ep = &ep_s;
ep_s.ContextRecord = &ctx_s;
SHOW_ESP();
throw -1;
}
int seh_filter01( DWORD ec, LPEXCEPTION_POINTERS ep )
{
printf("%s/n", "seh_filter");
SHOW_ESP();
show_diag_info( ep );
return EXCEPTION_EXECUTE_HANDLER;
}
int seh_filter02( DWORD ec, LPEXCEPTION_POINTERS ep )
{
printf("%s/n", "seh_filter");
SHOW_ESP();
show_diag_info( ep );
return EXCEPTION_CONTINUE_SEARCH;
}
void test01()
{
DWORD ec = 0;
LPEXCEPTION_POINTERS ep = NULL;
__try
{
raise01();
}
__except( ec = GetExceptionCode(), ep = GetExceptionInformation(), seh_filter01( ec, ep ) )
{
printf("%s/n", "test01->__except");
SHOW_ESP();
}
}
void test02_inner()
{
DWORD ec = 0;
LPEXCEPTION_POINTERS ep = NULL;
__try
{
raise02();
}
__except( ec = GetExceptionCode(), ep = GetExceptionInformation(), seh_filter02( ec, ep ) )
{
printf("%s/n", "test01->__except");
SHOW_ESP();
}
}
void test02()
{
try
{
test02_inner();
}
catch(...)
{
printf("%s/n", "C++ catch(...)");
}
}
int main(int argc, char* argv[])
{
test01();
test02();
return 0;
}
最简单的 方法是用 _set_new_handler。
如果不是 new 产生的, 或者程序非法访问内存了。
经过试验,可以先用__try __except捕获它,
在处理函数里面输出callstack调用堆栈,以及exe、dll的名字、地址、范围等信息。
处理完了返回EXCEPTION_CONTINUE_SEARCH,交给C++的try catch来继续处理。
#include <windows.h>
#include <stdio.h>
class win32_tool_help
{
public:
win32_tool_help();
virtual ~win32_tool_help();
static int show_module_list();
};
#include <tlhelp32.h>
#include <tchar.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
win32_tool_help::win32_tool_help()
{
}
win32_tool_help::~win32_tool_help()
{
}
int win32_tool_help::show_module_list()
{
HANDLE hSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE,
GetCurrentProcessId( )
);
MODULEENTRY32 me;
me.dwSize = sizeof(me);
BOOL ret = Module32First( hSnap, &me );
while (TRUE == ret)
{
_tprintf(
TEXT("hModule = %p, modBaseAddr = %p, modBaseSize = %08X, ")
TEXT("szExePath = %s, szModule = %s /n"),
me.hModule,
me.modBaseAddr,
me.modBaseSize,
me.szExePath, me.szModule
);
ret = Module32Next( hSnap, &me );
}
CloseHandle( hSnap );
return 0;
}
class win32_stack_walk
{
public:
win32_stack_walk();
virtual ~win32_stack_walk();
static int start( LPEXCEPTION_POINTERS ep );
};
#include <imagehlp.h>
#pragma comment( lib, "imagehlp.lib" )
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
win32_stack_walk::win32_stack_walk()
{
}
win32_stack_walk::~win32_stack_walk()
{
}
int win32_stack_walk::start( LPEXCEPTION_POINTERS ep )
{
const DWORD machine_type = IMAGE_FILE_MACHINE_I386;
HANDLE hProcess, hThread;
hProcess = GetCurrentProcess();
hThread = GetCurrentThread();
STACKFRAME frame = {0};
LPVOID ContextRecord = NULL;
PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine = NULL; // &ReadProcessMemory;
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine = &SymFunctionTableAccess;
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine = &SymGetModuleBase;
PTRANSLATE_ADDRESS_ROUTINE TranslateAddress = NULL;
BOOL ret = FALSE;
struct handle_frame_addr {
static
void set( ADDRESS& addr_s, DWORD addr )
{
addr_s.Mode = AddrModeFlat;
addr_s.Segment = 0;
addr_s.Offset = addr;
}
static
DWORD get( const ADDRESS& addr_s )
{
return addr_s.Offset;
}
};
handle_frame_addr::set( frame.AddrStack , ep->ContextRecord->Esp );
handle_frame_addr::set( frame.AddrFrame , ep->ContextRecord->Ebp );
handle_frame_addr::set( frame.AddrPC , ep->ContextRecord->Eip );
handle_frame_addr::set( frame.AddrReturn, 0 );
do
{
printf( "Stack = %08X Frame = %08X PC = %08X Return = %08X /n",
handle_frame_addr::get( frame.AddrStack ),
handle_frame_addr::get( frame.AddrFrame ),
handle_frame_addr::get( frame.AddrPC ),
handle_frame_addr::get( frame.AddrReturn )
);
ret = StackWalk( machine_type, hProcess, hThread,
&frame,
ContextRecord,
ReadMemoryRoutine,
FunctionTableAccessRoutine,
GetModuleBaseRoutine,
TranslateAddress );
} while( ret == TRUE );
return 0;
}
#define SHOW_ESP() /
do { /
DWORD reg_esp = 0; /
__asm { /
mov reg_esp, esp /
} /
printf("esp = %08X/n", reg_esp); /
printf("ep->Esp = %08X/n", ep->ContextRecord->Esp); /
}while(0);
void show_diag_info( LPEXCEPTION_POINTERS ep )
{
win32_stack_walk::start( ep );
win32_tool_help::show_module_list();
}
void raise01( )
{
printf("%s/n", "raise");
CONTEXT ctx_s = {0};
EXCEPTION_POINTERS ep_s;
LPEXCEPTION_POINTERS ep = &ep_s;
ep_s.ContextRecord = &ctx_s;
SHOW_ESP();
memset( 0, 1, 1 );
}
void raise02( )
{
printf("%s/n", "raise");
CONTEXT ctx_s = {0};
EXCEPTION_POINTERS ep_s;
LPEXCEPTION_POINTERS ep = &ep_s;
ep_s.ContextRecord = &ctx_s;
SHOW_ESP();
throw -1;
}
int seh_filter01( DWORD ec, LPEXCEPTION_POINTERS ep )
{
printf("%s/n", "seh_filter");
SHOW_ESP();
show_diag_info( ep );
return EXCEPTION_EXECUTE_HANDLER;
}
int seh_filter02( DWORD ec, LPEXCEPTION_POINTERS ep )
{
printf("%s/n", "seh_filter");
SHOW_ESP();
show_diag_info( ep );
return EXCEPTION_CONTINUE_SEARCH;
}
void test01()
{
DWORD ec = 0;
LPEXCEPTION_POINTERS ep = NULL;
__try
{
raise01();
}
__except( ec = GetExceptionCode(), ep = GetExceptionInformation(), seh_filter01( ec, ep ) )
{
printf("%s/n", "test01->__except");
SHOW_ESP();
}
}
void test02_inner()
{
DWORD ec = 0;
LPEXCEPTION_POINTERS ep = NULL;
__try
{
raise02();
}
__except( ec = GetExceptionCode(), ep = GetExceptionInformation(), seh_filter02( ec, ep ) )
{
printf("%s/n", "test01->__except");
SHOW_ESP();
}
}
void test02()
{
try
{
test02_inner();
}
catch(...)
{
printf("%s/n", "C++ catch(...)");
}
}
int main(int argc, char* argv[])
{
test01();
test02();
return 0;
}
相关文章推荐
- VS2017出现: Microsoft C++ 异常: cv::Exception,位于内存位置 0x000000D99016F6B0 处。
- SURF角点检测出现错误:SURF.exe 中的 0x756ad36f 处未处理的异常: Microsoft C++ 异常: 内存位置 0x003fcaf0 处的 cv::Exception。
- 程序异常立刻退出,如何定位关键代码位置
- 当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈
- 解决C++/CLI中关于“MissingManifestResourceException类型的未经处理的异常出现在mscorlib.dll”问题一例
- Opencv:Microsoft C++ 异常: 内存位置 0x002af444 处的 cv::Exception
- 确切定位c++代码中异常抛出位置的两个方法 (以VS2010调试为例)
- 确切定位c++代码中异常抛出位置的两个方法 (以VS2010调试为例)
- Xcode崩溃定位:异常位置Exception的断点
- Locating the postion of exception 定位异常的位置
- 解答:出现0x7c812aeb处最可能的异常: Microsoft C++ 异常: 内存位置 0x0012feb4 处的 cudaError_enum
- 在 System.FormatException 中第一次偶然出现的“mscorlib.dll”类型的异常,如何调试呢。
- 如何解决maven工程在调试的时候出现classnotfoundexception异常
- .exe 中的 0x759fc54f 处最可能的异常: Microsoft C++ 异常: 内存位置 0x0040f548 处的 cv::Exception
- 操作XmlDocument时,出现"System.OutOfMemoryException"异常,如何解决加载大数据的情况?
- 孙鑫C++教程留下来的作业--如何让工具栏在原来隐藏的位置出现
- 当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈
- 中的 0x74b4c54f 处有未经处理的异常: Microsoft C++ 异常: 内存位置 0x0019dbc0 处的 cv::Exception。
- 在用c++读取xml文件时,运行时出现以下错误:出现未处理的“System.Xml.XmlException”类型的异常出现在 system.xml.dll 中
- opencv error assertion failed,imread读到的总是空数据,Microsoft C++ 异常: 内存位置 0x0043f888 处的 cv::Exception。