记录下callstack信息

本文介绍了如何在自动测试内存泄露程序中记录callstack信息,通过调用特定API并结合__FILE__和__LINE__,可以获取详细的调用堆栈。文章提及了一篇参考文章,并对原始方法进行了简化和封装。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

本人曾做过自动测试内存泄露的程序。记录内存泄露位置时用__FILE__, 和__LINE__来记录位置。

但重要的callstack信息没有记录下来。

无意中看到一篇文章http://blog.youkuaiyun.com/starlee/article/details/6618849 

通过该文,找到了记录callstack信息的方法:调用下面的API。

BOOL WINAPI StackWalk64(
  __in      DWORD MachineType,
  __in      HANDLE hProcess,
  __in      HANDLE hThread,
  __inout   LPSTACKFRAME64 StackFrame,
  __inout   PVOID ContextRecord,
  __in_opt  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  __in_opt  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  __in_opt  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
  __in_opt  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);


 

 

而后将原文中的的方法简单做了修改和封装。

调用方法: vector<CallStackInfo> CallStack::GetCallStack();

 

#include <Windows.h>   
#include <iostream>   
#include <vector>   
#include <DbgHelp.h>   

#define MAX_ADDRESS_LENGTH 32
#define MAX_NAME_LENGTH 1024
using namespace std;  

struct CrashInfo 
{
	char ErrorCode[MAX_ADDRESS_LENGTH];
	char Address[MAX_ADDRESS_LENGTH];  
	char Flags[MAX_ADDRESS_LENGTH];  
};  

// CallStack信息   
//    
struct CallStackInfo  
{  
	char ModuleName[MAX_NAME_LENGTH];  
	char MethodName[MAX_NAME_LENGTH];  
	char FileName[MAX_NAME_LENGTH];  
	char LineNumber[MAX_NAME_LENGTH];  
};  


class CallStack
{
public:
	CallStack(void);
	~CallStack(void);
	static vector<CallStackInfo> GetCallStack();

protected:
	static void SafeStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc);
	static vector<CallStackInfo> GetCallStack(const CONTEXT *pContext);
	static CrashInfo GetCrashInfo(const EXCEPTION_RECORD *pRecord);
};


 

#include "StdAfx.h"
#include "CallStackInfo.h"



// 添加对dbghelp.lib的编译依赖   
//   
#pragma comment(lib, "dbghelp.lib")   
#pragma once



CallStack::CallStack(void)
{
}

CallStack::~CallStack(void)
{
}

// 安全拷贝字符串函数   
//   
void CallStack::SafeStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)  
{  
	if (nMaxDestSize <= 0) return;  
	if (strlen(szSrc) < nMaxDestSize)  
	{  
		strcpy_s(szDest, nMaxDestSize, szSrc);  
	}  
	else  
	{  
		strncpy_s(szDest, nMaxDestSize, szSrc, nMaxDestSize);  
		szDest[nMaxDestSize-1] = '\0';  
	}  
}    

// 得到程序崩溃信息   
//   
CrashInfo CallStack::GetCrashInfo(const EXCEPTION_RECORD *pRecord)  
{  
	CrashInfo crashinfo;  
	SafeStrCpy(crashinfo.Address, MAX_ADDRESS_LENGTH, "N/A");  
	SafeStrCpy(crashinfo.ErrorCode, MAX_ADDRESS_LENGTH, "N/A");  
	SafeStrCpy(crashinfo.Flags, MAX_ADDRESS_LENGTH, "N/A");  

	sprintf_s(crashinfo.Address, "%08X", pRecord->ExceptionAddress);  
	sprintf_s(crashinfo.ErrorCode, "%08X", pRecord->ExceptionCode);  
	sprintf_s(crashinfo.Flags, "%08X", pRecord->ExceptionFlags);  

	return crashinfo;  
}  


vector<CallStackInfo> CallStack::GetCallStack()  
{
	CONTEXT context;
	HANDLE hThread = GetCurrentThread(); 

	// get context 
	context.ContextFlags = (CONTEXT_FULL);
	if(GetThreadContext(hThread, &context))
	{
		return GetCallStack(&context);
	}else{
		vector<CallStackInfo> arrCallStackInfo; 
		return arrCallStackInfo;
	}
	
}

// 得到CallStack信息   
//   
vector<CallStackInfo> CallStack::GetCallStack(const CONTEXT *pContext)  
{  
	HANDLE hProcess = GetCurrentProcess();  

	SymInitialize(hProcess, NULL, TRUE);  

	vector<CallStackInfo> arrCallStackInfo;  

	CONTEXT c = *pContext;  

	STACKFRAME64 sf;  
	memset(&sf, 0, sizeof(STACKFRAME64));  
	DWORD dwImageType = IMAGE_FILE_MACHINE_I386;  

	// 不同的CPU类型,具体信息可查询MSDN   
	//   
#ifdef _M_IX86   
	sf.AddrPC.Offset = c.Eip;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.Esp;  
	sf.AddrStack.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.Ebp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
#elif _M_X64   
	dwImageType = IMAGE_FILE_MACHINE_AMD64;  
	sf.AddrPC.Offset = c.Rip;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.Rsp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.Rsp;  
	sf.AddrStack.Mode = AddrModeFlat;  
#elif _M_IA64   
	dwImageType = IMAGE_FILE_MACHINE_IA64;  
	sf.AddrPC.Offset = c.StIIP;  
	sf.AddrPC.Mode = AddrModeFlat;  
	sf.AddrFrame.Offset = c.IntSp;  
	sf.AddrFrame.Mode = AddrModeFlat;  
	sf.AddrBStore.Offset = c.RsBSP;  
	sf.AddrBStore.Mode = AddrModeFlat;  
	sf.AddrStack.Offset = c.IntSp;  
	sf.AddrStack.Mode = AddrModeFlat;  
#else   
#error "Platform not supported!"   
#endif   

	HANDLE hThread = GetCurrentThread();  

	while (true)  
	{  
		// 该函数是实现这个功能的最重要的一个函数   
		// 函数的用法以及参数和返回值的具体解释可以查询MSDN   
		//   
		if (!StackWalk64(dwImageType, hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))  
		{  
			break;  
		}  

		if (sf.AddrFrame.Offset == 0)  
		{  
			break;  
		}  

		CallStackInfo callstackinfo;  
		SafeStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, "N/A");  
		SafeStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, "N/A");  
		SafeStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, "N/A");  
		SafeStrCpy(callstackinfo.LineNumber, MAX_NAME_LENGTH, "N/A");  

		BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_NAME_LENGTH];  
		IMAGEHLP_SYMBOL64 *pSymbol = (IMAGEHLP_SYMBOL64*)symbolBuffer;  
		memset(pSymbol, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_NAME_LENGTH);  

		pSymbol->SizeOfStruct = sizeof(symbolBuffer);  
		pSymbol->MaxNameLength = MAX_NAME_LENGTH;  

		DWORD symDisplacement = 0;  

		BOOL bGetFileName = FALSE;
		// 得到函数名   
		//   
		if (SymGetSymFromAddr64(hProcess, sf.AddrPC.Offset, NULL, pSymbol))  
		{  
			SafeStrCpy(callstackinfo.MethodName, MAX_NAME_LENGTH, pSymbol->Name);  
		}  

		IMAGEHLP_LINE64 lineInfo;  
		memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64));  

		lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);  

		DWORD dwLineDisplacement;  

		// 得到文件名和所在的代码行   
		//   
		if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))  
		{  
			//该类本身不需要记载
			if(strcmp(lineInfo.FileName, __FILE__))
				bGetFileName = TRUE;

			SafeStrCpy(callstackinfo.FileName, MAX_NAME_LENGTH, lineInfo.FileName);  
			sprintf_s(callstackinfo.LineNumber, "%d", lineInfo.LineNumber);  
		}  

		IMAGEHLP_MODULE64 moduleInfo;  
		memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULE64));  

		moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);  

		// 得到模块名   
		//   
		if (SymGetModuleInfo64(hProcess, sf.AddrPC.Offset, &moduleInfo))  
		{  
			SafeStrCpy(callstackinfo.ModuleName, MAX_NAME_LENGTH, moduleInfo.ModuleName);  
		}  

		if(bGetFileName)
			arrCallStackInfo.push_back(callstackinfo);  
	}  

	SymCleanup(hProcess);  

	return arrCallStackInfo;  
}  


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值