struct StackFrame
{
DWORD64 address;
std::string name;
std::string module;
std::string filename;
int line_number;
};
std::vector<StackFrame> GetStackTrace(CONTEXT context)
{
DWORD machine = IMAGE_FILE_MACHINE_I386;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
STACKFRAME64 frame = {};
IMAGEHLP_LINE64* line = nullptr;
DWORD disp;
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
if (SymInitialize(process, NULL, TRUE) == FALSE)
{
return std::vector<StackFrame>();
}
#ifdef _M_IX86
machine = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = context.Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Esp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
machine = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = context.Rip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Rsp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Rsp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
machine = IMAGE_FILE_MACHINE_IA64;
frame.AddrPC.Offset = context.StIIP;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.IntSp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrBStore.Offset = context.RsBSP;
frame.AddrBStore.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.IntSp;
frame.AddrStack.Mode = AddrModeFlat;
#else
#error "This platform is not supported."
#endif
std::vector<StackFrame> frames;
while (StackWalk64(machine, process, thread, &frame, &context , NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
{
StackFrame f;
f.address = frame.AddrPC.Offset;
DWORD64 moduleBase = SymGetModuleBase64(process, frame.AddrPC.Offset);
char moduelBuff[MAX_PATH];
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduelBuff, MAX_PATH))
{
f.module = moduelBuff;
}
else
{
f.module = "Unknown Module";
}
DWORD64 offset = 0;
char symbolBuff[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbolBuff;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
if (SymFromAddr(process, frame.AddrPC.Offset, &offset, symbol))
{
f.name = symbol->Name;
SymSetOptions(SYMOPT_LOAD_LINES);
line = (IMAGEHLP_LINE64*)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &disp, line))
{
f.filename = line->FileName;
f.line_number = line->LineNumber;
}
else
{
std::cout << "Error occured in SymGetLineFromAddr64 : Reason :: " << std::system_category().message(GetLastError()) << " \n";
}
free(line);
}
else
{
DWORD error = GetLastError();
std::cout << "SymFromAddr Failed. Err Reason : " << std::system_category().message(error)<< " \n";
f.name = "Unknown Function";
}
frames.push_back(f);
}
SymCleanup(process);
return frames;
}
I need to get the callstack of the unhandled exception from the EXCEPTION_POINTER. It working properly on Windows Intel Machine x86 and x64 architectures but I encounter issues specifically on AMD machines with the error message "Attempt to access invalid address". Any Help in addressing this issue would be welcomed.
Intel or AMD processor is not the issue. For X86 architecture, StackWalk needs IMAGE_FILE_MACHINE_I386 and for X64 architecture, it needs IMAGE_FILE_MACHINE_AMD64. This is important and You have done that correctly.
You also need to have the .pdb file to retrieve the Call stack. Make sure You have it in the AMD machine in which you tested your application.