Понадобилось самое простое решение данной задачи.
class StackTraceEngine
{
public:
HMODULE m_hDbhHelp;
HANDLE m_hProcess;
// SymGetLineFromAddr64()
typedef BOOL (__stdcall *tfnSymGetLineFromAddr64)( IN HANDLE hProcess, IN DWORD64 dwAddr,
OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
tfnSymGetLineFromAddr64 pfnSymGetLineFromAddr64;
// SymGetSymFromAddr64()
typedef BOOL (__stdcall *tfnSymGetSymFromAddr64)( IN HANDLE hProcess, IN DWORD64 dwAddr,
OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
tfnSymGetSymFromAddr64 pfnSymGetSymFromAddr64;
// SymInitialize()
typedef BOOL (__stdcall *tfnSymInitialize)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
tfnSymInitialize pfnSymInitialize;
// SymSetOptions()
typedef DWORD (__stdcall *tfnSymSetOptions)( IN DWORD SymOptions );
tfnSymSetOptions pfnSymSetOptions;
// StackWalk64()
typedef BOOL (__stdcall *tfnStackWalk64)(
DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
tfnStackWalk64 pfnStackWalk64;
// UnDecorateSymbolName()
typedef DWORD (__stdcall WINAPI *tfnUnDecorateSymbolName)( PCSTR DecoratedName, PSTR UnDecoratedName,
DWORD UndecoratedLength, DWORD Flags );
tfnUnDecorateSymbolName pfnUnDecorateSymbolName;
// SymFunctionTableAccess64()
typedef PVOID (__stdcall *tfnSymFunctionTableAccess64)( HANDLE hProcess, DWORD64 AddrBase );
tfnSymFunctionTableAccess64 pfnSymFunctionTableAccess64;
// SymGetModuleBase64()
typedef DWORD64 (__stdcall *tfnSymGetModuleBase64)( IN HANDLE hProcess, IN DWORD64 dwAddr );
tfnSymGetModuleBase64 pfnSymGetModuleBase64;
StackTraceEngine(HANDLE hProcess) :
m_hDbhHelp(0),
m_hProcess(hProcess),
pfnSymGetLineFromAddr64(0),
pfnSymGetSymFromAddr64(0),
pfnSymInitialize(0),
pfnSymSetOptions(0),
pfnStackWalk64(0),
pfnUnDecorateSymbolName(0),
pfnSymFunctionTableAccess64(0),
pfnSymGetModuleBase64(0)
{
}
HRESULT Init()
{
BOOL Ret;
//
// Load dbghelp.dll dynamically.
//
if ((m_hDbhHelp = LoadLibrary(L"dbghelp.dll")) == 0)
{
return HRESULT_FROM_WIN32(GetLastError());
}
//
// Load procedures.
//
pfnSymInitialize = (tfnSymInitialize) GetProcAddress(m_hDbhHelp, "SymInitialize" );
pfnStackWalk64 = (tfnStackWalk64) GetProcAddress(m_hDbhHelp, "StackWalk64" );
pfnSymGetLineFromAddr64 = (tfnSymGetLineFromAddr64) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
pfnSymGetSymFromAddr64 = (tfnSymGetSymFromAddr64) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
pfnUnDecorateSymbolName = (tfnUnDecorateSymbolName) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
pfnSymFunctionTableAccess64 = (tfnSymFunctionTableAccess64) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
pfnSymGetModuleBase64 = (tfnSymGetModuleBase64) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
pfnSymSetOptions = (tfnSymSetOptions) GetProcAddress(m_hDbhHelp, "SymSetOptions" );
if ((pfnSymInitialize == 0) ||
(pfnStackWalk64 == 0) ||
(pfnSymGetLineFromAddr64 == 0) ||
(pfnSymGetSymFromAddr64 == 0) ||
(pfnUnDecorateSymbolName == 0) ||
(pfnSymFunctionTableAccess64 == 0) ||
(pfnSymGetModuleBase64 == 0) ||
(pfnSymSetOptions == 0))
{
FreeLibrary(m_hDbhHelp);
m_hDbhHelp = 0;
return E_UNEXPECTED;
}
//
// Initialize symbols engine.
//
if ((Ret = pfnSymSetOptions(SYMOPT_LOAD_LINES)) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
if ((Ret = pfnSymInitialize(
m_hProcess,
0,
TRUE)) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
HRESULT WalkStack(
char* StackTrace,
DWORD StackTraceSize)
{
if ((StackTrace == 0) ||
(IsBadWritePtr(StackTrace, StackTraceSize)))
{
return E_INVALIDARG;
}
//
// Init out parameters.
//
StackTrace[0] = '\0';
//
// The following should be enough for walking the call stack...
//
CONTEXT ctx = {0};
__asm call x;
__asm x: pop eax;
__asm mov ctx.Eip, eax;
__asm mov ctx.Ebp, ebp;
__asm mov ctx.Esp, esp;
//
// Init STACKFRAME for the first call
//
STACKFRAME64 stfrm = {0}; // in/out stackframe
stfrm.AddrPC.Offset = ctx.Eip;
stfrm.AddrPC.Mode = AddrModeFlat;
stfrm.AddrFrame.Offset = ctx.Ebp;
stfrm.AddrFrame.Mode = AddrModeFlat;
stfrm.AddrStack.Offset = ctx.Esp;
stfrm.AddrStack.Mode = AddrModeFlat;
//
// Symbol info memory buffer.
//
char SymbolBuffer[65535] = {0};
IMAGEHLP_SYMBOL64 *pSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&SymbolBuffer);
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD SymbolNameSize = (DWORD)sizeof(SymbolBuffer) - offsetof(IMAGEHLP_SYMBOL64, Name);
pSymbol->MaxNameLength = SymbolNameSize;
HANDLE hCurrentThread = GetCurrentThread();
//
// Line info.
//
IMAGEHLP_LINE64 Line = {0};
Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
while(true)
{
//
// IMAGE_FILE_MACHINE_I386 is only supported now.
// I have no other platforms to check this code :(
//
pfnStackWalk64(
IMAGE_FILE_MACHINE_I386,
m_hProcess,
hCurrentThread,
&stfrm,
&ctx,
0,
pfnSymFunctionTableAccess64,
pfnSymGetModuleBase64,
0);
if (stfrm.AddrPC.Offset == 0)
break;
//
// Get procedure info.
//
DWORD64 SymbolDisplacement = 0;
pfnSymGetSymFromAddr64(
m_hProcess,
stfrm.AddrPC.Offset,
&SymbolDisplacement,
pSymbol);
//
// Get line info.
//
DWORD LineDisplacement = 0;
pfnSymGetLineFromAddr64(
m_hProcess,
stfrm.AddrPC.Offset,
&LineDisplacement,
&Line);
//
// Format and store current frame.
//
size_t SymbolNameRealSize = 0;
StringCchLengthA(
pSymbol->Name,
SymbolNameSize,
&SymbolNameRealSize);
//
// Append symbol name.
//
if (SymbolNameRealSize == 0)
{
StringCchCatA(
StackTrace,
StackTraceSize,
"Procedure: <unknown>");
}
else
{
char buff[16384];
StringCchPrintfA(
buff,
sizeof(buff),
"Procedure: %s",
pSymbol->Name);
StringCchCatA(
StackTrace,
StackTraceSize,
buff);
}
//
// Append symbol location
//
if (Line.FileName[0] == 0)
{
StringCchCatA(
StackTrace,
StackTraceSize,
", File: <unknown>, Line: <unknown>\n");
}
else
{
char buff[16384];
StringCchPrintfA(
buff,
sizeof(buff),
" , File: %s, Line: %d\n",
Line.FileName,
Line.LineNumber);
StringCchCatA(
StackTrace,
StackTraceSize,
buff);
}
}
return S_OK;
}
};
Применять примерно так:
void DoStackTrace(void)
{
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
GetCurrentProcessId());
StackTraceEngine se(hProcess);
se.Init();
char buff[65535];
se.WalkStack(
buff,
sizeof(buff));
printf("%s", buff);
}
как альтернативу смотреть:
http://www.codeproject.com/threads/StackWalker.asp
Мне он не подошёл обьёмом. ~1200 строк.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>