static uchar *hlc_resolve_symbol( void *addr, uchar *out, int *outSize ) { #ifdef _WIN32 static HANDLE stack_process_handle = NULL; DWORD64 index; IMAGEHLP_LINEW64 line; struct { SYMBOL_INFOW sym; uchar buffer[256]; } data; data.sym.SizeOfStruct = sizeof(data.sym); data.sym.MaxNameLen = 255; if( !stack_process_handle ) { stack_process_handle = GetCurrentProcess(); SymSetOptions(SYMOPT_LOAD_LINES); SymInitialize(stack_process_handle,NULL,TRUE); } if( SymFromAddrW(stack_process_handle,(DWORD64)(int_val)addr,&index,&data.sym) ) { DWORD offset = 0; line.SizeOfStruct = sizeof(line); line.FileName = USTR("\\?"); line.LineNumber = 0; SymGetLineFromAddrW64(stack_process_handle, (DWORD64)(int_val)addr, &offset, &line); *outSize = usprintf(out,*outSize,USTR("%s(%s:%d)"),data.sym.Name,wcsrchr(line.FileName,'\\')+1,(int)line.LineNumber); return out; } #endif return NULL; }
const Symbol * const SymEngine::GetSymbol(DWORD64 dwAddress) { if (dwAddress == 0) return nullptr; Symbol& symbol = cache[dwAddress]; if (symbol.address != 0) return &symbol; if (!isInitialized) return nullptr; symbol.address = dwAddress; // Module Name IMAGEHLP_MODULEW64 moduleInfo; memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULEW64)); moduleInfo.SizeOfStruct = sizeof(moduleInfo); if (SymGetModuleInfoW64(hProcess, dwAddress, &moduleInfo)) { symbol.module = moduleInfo.ImageName; } // FileName and Line IMAGEHLP_LINEW64 lineInfo; memset(&lineInfo, 0, sizeof(IMAGEHLP_LINEW64)); lineInfo.SizeOfStruct = sizeof(lineInfo); DWORD dwDisp; if (SymGetLineFromAddrW64(hProcess, dwAddress, &dwDisp, &lineInfo)) { symbol.file = lineInfo.FileName; symbol.line = lineInfo.LineNumber; } const size_t length = (sizeof(SYMBOL_INFOW) + MAX_SYM_NAME*sizeof(WCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64) + 1; // Function Name ULONG64 buffer[length]; PSYMBOL_INFOW dbgSymbol = (PSYMBOL_INFOW)buffer; memset(dbgSymbol, 0, sizeof(buffer)); dbgSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); dbgSymbol->MaxNameLen = MAX_SYM_NAME; if (SymFromAddrW(hProcess, dwAddress, &symbol.offset, dbgSymbol)) { symbol.function.resize(dbgSymbol->NameLen); memcpy(&symbol.function[0], &dbgSymbol->Name[0], sizeof(WCHAR) * dbgSymbol->NameLen); } return &symbol; }
bool SymGetSourceLine(uint Cip, char* FileName, int* Line) { IMAGEHLP_LINEW64 lineInfo; memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64)); lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); // Perform a symbol lookup from a specific address DWORD displacement; if(!SymGetLineFromAddrW64(fdProcessInfo->hProcess, Cip, &displacement, &lineInfo)) return false; String NewFile = StringUtils::Utf16ToUtf8(lineInfo.FileName); // Copy line number if requested if(Line) *Line = lineInfo.LineNumber; // Copy file name if requested if(FileName) { // Check if it was a full path if(NewFile[1] == ':' && NewFile[2] == '\\') { // Success: no more parsing strcpy_s(FileName, MAX_STRING_SIZE, NewFile.c_str()); return true; } // Construct full path from pdb path IMAGEHLP_MODULE64 modInfo; memset(&modInfo, 0, sizeof(IMAGEHLP_MODULE64)); modInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); if(!SafeSymGetModuleInfo64(fdProcessInfo->hProcess, Cip, &modInfo)) return false; // Strip the name, leaving only the file directory char* pdbFileName = strrchr(modInfo.LoadedPdbName, '\\'); if(pdbFileName) pdbFileName[1] = '\0'; // Copy back to the caller's buffer strcpy_s(FileName, MAX_STRING_SIZE, modInfo.LoadedPdbName); strcat_s(FileName, MAX_STRING_SIZE, NewFile.c_str()); } return true; }
/* static */ BOOL wxDbgHelpDLL::CallSymGetLineFromAddr(HANDLE hProcess, DWORD64 dwAddr, wxString* fileName, size_t* line) { DWORD dwDisplacement; #ifdef UNICODE if ( SymGetLineFromAddrW64 ) { SizedStruct<IMAGEHLP_LINEW64> lineW64; if ( SymGetLineFromAddrW64(hProcess, dwAddr, &dwDisplacement, &lineW64) ) { *fileName = lineW64.FileName; *line = lineW64.LineNumber; return TRUE; } } #endif // UNICODE if ( SymGetLineFromAddr64 ) { SizedStruct<IMAGEHLP_LINE64> line64; if ( SymGetLineFromAddr64(hProcess, dwAddr, &dwDisplacement, &line64) ) { *fileName = line64.FileName; *line = line64.LineNumber; return TRUE; } } if ( SymGetLineFromAddr ) { SizedStruct<IMAGEHLP_LINE> line32; if ( SymGetLineFromAddr(hProcess, dwAddr, &dwDisplacement, &line32) ) { *fileName = line32.FileName; *line = line32.LineNumber; return TRUE; } } return FALSE; }
void __addr2sym(IN tt_uintptr_t addr, IN tt_char_t *buf, IN tt_u32_t len) { HANDLE proc; tt_u8_t tmp[sizeof(SYMBOL_INFO) + __SYM_SIZE + 1]; PSYMBOL_INFO sym = (PSYMBOL_INFO)tmp; IMAGEHLP_LINEW64 line; DWORD64 addr_disp; DWORD disp2; tt_char_t *fname; proc = GetCurrentProcess(); sym->SizeOfStruct = sizeof(SYMBOL_INFO); sym->MaxNameLen = __SYM_SIZE; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (!SymFromAddr(proc, addr, &addr_disp, sym)) { tt_snprintf(buf, len - 1, "%p", addr); } else if (!SymGetLineFromAddrW64(proc, addr, &disp2, &line) || ((fname = tt_utf8_create(line.FileName, 0, NULL)) == NULL)) { tt_snprintf(buf, len - 1, "%p in %s(+0x%x)", addr, sym->Name, addr_disp); } else { tt_snprintf(buf, len - 1, "%p in %s() at [%s:%d]", addr, sym->Name, fname, line.LineNumber); tt_free(fname); } }
// Resolve - Creates a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. and // saves it for later retrieval. This is almost identical to Callstack::dump above. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showInternalFrames (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::resolve(BOOL showInternalFrames) { if (m_resolved) { // already resolved, no need to do it again // resolving twice may report an incorrect module for the stack frames // if the memory was leaked in a dynamic library that was already unloaded. return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 }; WCHAR callingModuleName [MAX_PATH] = L""; WCHAR lowerCaseName [MAX_PATH]; const size_t max_line_length = MAXREPORTLENGTH + 1; m_resolvedCapacity = m_size * max_line_length; m_resolved = new WCHAR[m_resolvedCapacity]; const size_t allocedBytes = m_resolvedCapacity * sizeof(WCHAR); ZeroMemory(m_resolved, allocedBytes); // Iterate through each frame in the call stack. for (UINT32 frame = 0; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; g_symbolLock.Enter(); BOOL foundline = FALSE; DWORD displacement = 0; // It turns out that calls to SymGetLineFromAddrW64 may free the very memory we are scrutinizing here // in this method. If this is the case, m_Resolved will be null after SymGetLineFromAddrW64 returns. // When that happens there is nothing we can do except crash. DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo); assert(m_resolved != NULL); if (foundline && !showInternalFrames) { wcscpy_s(lowerCaseName, sourceInfo.FileName); _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1); if (isInternalModule(lowerCaseName)) { // Don't show frames in files internal to the heap. g_symbolLock.Leave(); continue; } } // Initialize structures passed to the symbol handler. SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer; functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO); functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH; // Try to get the name of the function containing this program // counter address. DWORD64 displacement64 = 0; LPWSTR functionName; DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId()); if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) { functionName = functionInfo->Name; } else { // GetFormattedMessage( GetLastError() ); functionName = L"(Function name unavailable)"; displacement64 = 0; } g_symbolLock.Leave(); HMODULE hCallingModule = GetCallingModule(programCounter); LPWSTR moduleName = L"(Module name unavailable)"; if (hCallingModule && GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0) { moduleName = wcsrchr(callingModuleName, L'\\'); if (moduleName == NULL) moduleName = wcsrchr(callingModuleName, L'/'); if (moduleName != NULL) moduleName++; else moduleName = callingModuleName; } // Use static here to increase performance, and avoid heap allocs. Hopefully this won't // prove to be an issue in thread safety. If it does, it will have to be simply non-static. static WCHAR stack_line[max_line_length] = L""; int NumChars = -1; // Display the current stack frame's information. if (foundline) { // Just truncate anything that is too long. if (displacement == 0) NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" %s (%d): %s!%s\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" %s (%d): %s!%s + 0x%X bytes\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement); } else { if (displacement64 == 0) NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", programCounter, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_line_length, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", programCounter, moduleName, functionName, (DWORD)displacement64); } if (NumChars >= 0) { assert(m_resolved != NULL); m_resolvedLength += NumChars; wcsncat_s(m_resolved, m_resolvedCapacity, stack_line, NumChars); } } // end for loop }
// dump - Dumps a nicely formatted rendition of the CallStack, including // symbolic information (function names and line numbers) if available. // // Note: The symbol handler must be initialized prior to calling this // function. // // - showinternalframes (IN): If true, then all frames in the CallStack will be // dumped. Otherwise, frames internal to the heap will not be dumped. // // Return Value: // // None. // void CallStack::dump(BOOL showInternalFrames, UINT start_frame) const { // The stack was dumped already if (m_resolved) { dumpResolved(); return; } if (m_status & CALLSTACK_STATUS_INCOMPLETE) { // This call stack appears to be incomplete. Using StackWalk64 may be // more reliable. Report(L" HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n" L" in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n" L" complete stack trace.\n"); } IMAGEHLP_LINE64 sourceInfo = { 0 }; sourceInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BYTE symbolBuffer [sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_SIZE] = { 0 }; WCHAR lowerCaseName [MAX_PATH]; WCHAR callingModuleName [MAX_PATH]; const size_t max_size = MAXREPORTLENGTH + 1; // Iterate through each frame in the call stack. for (UINT32 frame = start_frame; frame < m_size; frame++) { // Try to get the source file and line number associated with // this program counter address. SIZE_T programCounter = (*this)[frame]; g_symbolLock.Enter(); BOOL foundline = FALSE; DWORD displacement = 0; DbgTrace(L"dbghelp32.dll %i: SymGetLineFromAddrW64\n", GetCurrentThreadId()); foundline = SymGetLineFromAddrW64(g_currentProcess, programCounter, &displacement, &sourceInfo); if (foundline && !showInternalFrames) { wcscpy_s(lowerCaseName, sourceInfo.FileName); _wcslwr_s(lowerCaseName, wcslen(lowerCaseName) + 1); if (isInternalModule(lowerCaseName)) { // Don't show frames in files internal to the heap. g_symbolLock.Leave(); continue; } } // Initialize structures passed to the symbol handler. SYMBOL_INFO* functionInfo = (SYMBOL_INFO*)&symbolBuffer; functionInfo->SizeOfStruct = sizeof(SYMBOL_INFO); functionInfo->MaxNameLen = MAX_SYMBOL_NAME_LENGTH; // Try to get the name of the function containing this program // counter address. DWORD64 displacement64 = 0; LPWSTR functionName; DbgTrace(L"dbghelp32.dll %i: SymFromAddrW\n", GetCurrentThreadId()); if (SymFromAddrW(g_currentProcess, programCounter, &displacement64, functionInfo)) { functionName = functionInfo->Name; } else { // GetFormattedMessage( GetLastError() ); functionName = L"(Function name unavailable)"; displacement64 = 0; } g_symbolLock.Leave(); HMODULE hCallingModule = GetCallingModule(programCounter); LPWSTR moduleName = L"(Module name unavailable)"; if (hCallingModule && GetModuleFileName(hCallingModule, callingModuleName, _countof(callingModuleName)) > 0) { moduleName = wcsrchr(callingModuleName, L'\\'); if (moduleName == NULL) moduleName = wcsrchr(callingModuleName, L'/'); if (moduleName != NULL) moduleName++; else moduleName = callingModuleName; } // Use static here to increase performance, and avoid heap allocs. Hopefully this won't // prove to be an issue in thread safety. If it does, it will have to be simply non-static. static WCHAR stack_line[MAXREPORTLENGTH + 1] = L""; int NumChars = -1; // Display the current stack frame's information. if (foundline) { if (displacement == 0) NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" %s (%d): %s!%s + 0x%X bytes\n", sourceInfo.FileName, sourceInfo.LineNumber, moduleName, functionName, displacement); } else { if (displacement64 == 0) NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s\n", programCounter, moduleName, functionName); else NumChars = _snwprintf_s(stack_line, max_size, _TRUNCATE, L" " ADDRESSFORMAT L" (File and line number not available): %s!%s + 0x%X bytes\n", programCounter, moduleName, functionName, (DWORD)displacement64); } Print(stack_line); } }
void qtDLGCallstack::ShowCallStack() { clsDebugger *pDebugger = qtDLGNanomite::GetInstance()->coreDebugger; HANDLE hProc = pDebugger->GetCurrentProcessHandle(), hThread = OpenThread(THREAD_GETSET_CONTEXT,false,pDebugger->GetCurrentTID()); PSYMBOL_INFOW pSymbol = (PSYMBOL_INFOW)malloc(sizeof(SYMBOL_INFOW) + MAX_PATH * 2); DWORD dwMaschineMode = NULL; LPVOID pContext; STACKFRAME64 stackFr = {0}; stackFr.AddrPC.Mode = AddrModeFlat; stackFr.AddrFrame.Mode = AddrModeFlat; stackFr.AddrStack.Mode = AddrModeFlat; QString sFuncName, sFuncMod, sReturnToFunc, sReturnToMod; quint64 dwStackAddr, dwReturnTo, dwEIP, dwDisplacement; IMAGEHLP_LINEW64 imgSource = {0}; IMAGEHLP_MODULEW64 imgMod = {0}; #ifdef _AMD64_ BOOL bIsWOW64 = false; if(clsAPIImport::pIsWow64Process) clsAPIImport::pIsWow64Process(hProc,&bIsWOW64); if(bIsWOW64) { dwMaschineMode = IMAGE_FILE_MACHINE_I386; WOW64_CONTEXT cTT = pDebugger->wowProcessContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Eip; stackFr.AddrFrame.Offset = cTT.Ebp; stackFr.AddrStack.Offset = cTT.Esp; } else { dwMaschineMode = IMAGE_FILE_MACHINE_AMD64; CONTEXT cTT = pDebugger->ProcessContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Rip; stackFr.AddrFrame.Offset = cTT.Rbp; stackFr.AddrStack.Offset = cTT.Rsp; } #else dwMaschineMode = IMAGE_FILE_MACHINE_I386; CONTEXT cTT = pDebugger->ProcessContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Eip; stackFr.AddrFrame.Offset = cTT.Ebp; stackFr.AddrStack.Offset = cTT.Esp; #endif tblCallstack->setRowCount(0); do { if(!StackWalk64(dwMaschineMode,hProc,hThread,&stackFr,pContext,NULL,SymFunctionTableAccess64,SymGetModuleBase64,0)) break; memset(&imgSource,0,sizeof(IMAGEHLP_LINEW64)); imgSource.SizeOfStruct = sizeof(IMAGEHLP_LINEW64); dwStackAddr = stackFr.AddrStack.Offset; dwEIP = stackFr.AddrPC.Offset; dwReturnTo = stackFr.AddrReturn.Offset; memset(&imgMod,0,sizeof(IMAGEHLP_MODULEW64)); imgMod.SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); memset(pSymbol,0,sizeof(SYMBOL_INFOW) + MAX_PATH * 2); pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); pSymbol->MaxNameLen = MAX_PATH; SymGetModuleInfoW64(hProc,dwEIP,&imgMod); SymFromAddrW(hProc,dwEIP,&dwDisplacement,pSymbol); sFuncName = QString::fromWCharArray(pSymbol->Name); sFuncMod = QString::fromWCharArray(imgMod.ModuleName); memset(&imgMod,0,sizeof(IMAGEHLP_MODULEW64)); imgMod.SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); memset(pSymbol,0,sizeof(SYMBOL_INFOW) + MAX_PATH * 2); pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); pSymbol->MaxNameLen = MAX_PATH; SymGetModuleInfoW64(hProc,dwReturnTo,&imgMod); SymFromAddrW(hProc,dwReturnTo,&dwDisplacement,pSymbol); sReturnToMod = QString::fromWCharArray(imgMod.ModuleName); sReturnToFunc = QString::fromWCharArray(pSymbol->Name); if(SymGetLineFromAddrW64(hProc,dwEIP,(PDWORD)&dwDisplacement,&imgSource)) { OnCallStack(dwStackAddr, dwReturnTo,sReturnToFunc,sReturnToMod, dwEIP,sFuncName,sFuncMod, QString::fromWCharArray(imgSource.FileName),imgSource.LineNumber); } else { OnCallStack(dwStackAddr, dwReturnTo,sReturnToFunc,sReturnToMod, dwEIP,sFuncName,sFuncMod, QString(""),0); } }while(stackFr.AddrReturn.Offset != 0); free(pSymbol); CloseHandle(hThread); }
void clsCallstackWorker::run() { HANDLE hThread = OpenThread(THREAD_GETSET_CONTEXT, false, m_processingData.threadID); PSYMBOL_INFOW pSymbol = (PSYMBOL_INFOW)malloc(sizeof(SYMBOL_INFOW) + MAX_PATH * 2); DWORD dwMaschineMode = NULL; quint64 dwDisplacement = NULL; LPVOID pContext; QList<callstackDisplay> callstackDisplayData; callstackDisplay newDisplayData = { 0 }; STACKFRAME64 stackFr = { 0 }; IMAGEHLP_LINEW64 imgSource = { 0 }; IMAGEHLP_MODULEW64 imgMod = { 0 }; stackFr.AddrPC.Mode = AddrModeFlat; stackFr.AddrFrame.Mode = AddrModeFlat; stackFr.AddrStack.Mode = AddrModeFlat; #ifdef _AMD64_ if(m_processingData.isWOW64) { dwMaschineMode = IMAGE_FILE_MACHINE_I386; WOW64_CONTEXT cTT = m_processingData.wowProcessContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Eip; stackFr.AddrFrame.Offset = cTT.Ebp; stackFr.AddrStack.Offset = cTT.Esp; } else { dwMaschineMode = IMAGE_FILE_MACHINE_AMD64; CONTEXT cTT = m_processingData.processContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Rip; stackFr.AddrFrame.Offset = cTT.Rbp; stackFr.AddrStack.Offset = cTT.Rsp; } #else dwMaschineMode = IMAGE_FILE_MACHINE_I386; CONTEXT cTT = m_processingData.processContext; pContext = &cTT; stackFr.AddrPC.Offset = cTT.Eip; stackFr.AddrFrame.Offset = cTT.Ebp; stackFr.AddrStack.Offset = cTT.Esp; #endif do { if(!StackWalk64(dwMaschineMode, m_processingData.processHandle, hThread, &stackFr, pContext, NULL, SymFunctionTableAccess64, SymGetModuleBase64, 0)) break; memset(&imgSource, 0, sizeof(IMAGEHLP_LINEW64)); imgSource.SizeOfStruct = sizeof(IMAGEHLP_LINEW64); newDisplayData.stackAddress = stackFr.AddrStack.Offset; newDisplayData.currentOffset = stackFr.AddrPC.Offset; newDisplayData.returnOffset = stackFr.AddrReturn.Offset; memset(&imgMod, 0, sizeof(IMAGEHLP_MODULEW64)); imgMod.SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); memset(pSymbol, 0, sizeof(SYMBOL_INFOW) + MAX_PATH * 2); pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); pSymbol->MaxNameLen = MAX_PATH; SymGetModuleInfoW64(m_processingData.processHandle, newDisplayData.currentOffset, &imgMod); SymFromAddrW(m_processingData.processHandle, newDisplayData.currentOffset, &dwDisplacement, pSymbol); newDisplayData.currentFunctionName = QString::fromWCharArray(pSymbol->Name); newDisplayData.currentModuleName = QString::fromWCharArray(imgMod.ModuleName); memset(&imgMod, 0, sizeof(IMAGEHLP_MODULEW64)); imgMod.SizeOfStruct = sizeof(IMAGEHLP_MODULEW64); memset(pSymbol, 0, sizeof(SYMBOL_INFOW) + MAX_PATH * 2); pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); pSymbol->MaxNameLen = MAX_PATH; SymGetModuleInfoW64(m_processingData.processHandle, newDisplayData.returnOffset, &imgMod); SymFromAddrW(m_processingData.processHandle, newDisplayData.returnOffset , &dwDisplacement, pSymbol); newDisplayData.returnModuleName = QString::fromWCharArray(imgMod.ModuleName); newDisplayData.returnFunctionName = QString::fromWCharArray(pSymbol->Name); if(SymGetLineFromAddrW64(m_processingData.processHandle, newDisplayData.currentOffset, (PDWORD)&dwDisplacement, &imgSource)) { newDisplayData.sourceFilePath = QString::fromWCharArray(imgSource.FileName); newDisplayData.sourceLineNumber = imgSource.LineNumber; } else { newDisplayData.sourceFilePath = ""; newDisplayData.sourceLineNumber = 0; } callstackDisplayData.append(newDisplayData); } while(stackFr.AddrReturn.Offset != 0); free(pSymbol); CloseHandle(hThread); emit OnCallstackFinished(callstackDisplayData); }