有人问过我,在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;
}