C++出现exception异常的位置如何定位?

 

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

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值