* feat: native Windows ARM64 build support Builds on the merged DEPS_ARCH=arm64 plumbing (#13424) by adding the dependency and source fixes needed for a green native ARM64 build on the windows-11-arm runner. Validated end-to-end on Snapdragon X Elite hardware (via a downstream fork using the same fixes); see OrcaSlicer/OrcaSlicer#8271 for the full writeup. Dependencies: - OpenEXR 2.5.5: ImfSimd.h hard-codes IMF_HAVE_SSE2 for any MSVC, pulling in <emmintrin.h> (x86-only) -> C1189. Patch the header to require an x86 target and force SSE cache vars off on ARM64. - Boost.Context: use the winfib implementation on ARM64 (Windows Fiber API) to avoid the armasm64 / CMake ASM_ARMASM linker-module bug, while keeping the Boost::context target Boost.Asio needs. - OpenCV: disable WITH_IPP on ARM64 (Intel IPP/IPP-ICV is x86/x64 only; otherwise ~200 unresolved ippicv* externals at link). - OpenSSL: use VC-WIN64-ARM on ARM64. - FindGLEW: add an ARM64 arch branch. Sources: - clipper Int128.hpp: _mul128 is an x64-only intrinsic guarded by _WIN64 (true on ARM64); guard on _M_X64 and use the portable path. - imgui imgui_widgets.cpp: fix va_start(vaList, &text) -> va_start(vaList, text) (the &-form compiled on x64 but is invalid on ARM64). - crash reporter: StackWalker.cpp gains an _M_ARM64 branch; BaseException.cpp uses Cpsr instead of the x86-only EFlags on ARM64. CI: - New build_windows_arm64.yml on windows-11-arm: pins CMake 3.31.x, stages ARM64 GMP/MPFR from MSYS2 clangarm64 (with llvm-dlltool import libs), caches deps with a fixed-depth hashFiles key, builds and uploads the binary. OCCT/STEP, SVG-to-3D and text emboss all build and work on ARM64 (no stubs needed). Full feature parity with x64. * fix(ci): use forward-slash DESTDIR to avoid CMake '\a' escape error deps configure failed at GMP/GMP.cmake: "Invalid character escape '\a'" because DESTDIR carried Windows backslashes (C:\a\...) and is re-parsed when re-set with the /usr/local suffix. Pass DESTDIR (and the slicer's DEPS prefix) with forward slashes via %CD:\=/%. * fix(ci): don't export DESTDIR env var (CMake staged-install doubles paths) Setting a DESTDIR *environment* variable made CMake treat it as the staged install prefix and prepend it to every dependency's install path, so e.g. FreeType installed to <DESTDIR>/a/.../OrcaSlicer_dep/usr/local and OCCT then couldn't find its headers. Compute the forward-slash path into a differently-named var (ORCA_DESTDIR) and pass it only via -DDESTDIR. * ci(windows-arm64): fold ARM64 build into the standard Windows matrix Replace the standalone build_windows_arm64.yml with a matrix entry on the existing build_windows job, so x64 and ARM64 share one reusable workflow chain (build_all -> build_check_cache -> build_deps -> build_orca), per review feedback on #14059. - build_all.yml: build_windows now matrices over {x64: windows-latest, arm64: windows-11-arm} and threads `arch` through. Self-hosted runner stays x64-only. - build_check_cache.yml: cache key and dep-prefix path are now architecture-specific on Windows (deps/build-arm64/OrcaSlicer_dep). - build_release_vs.bat: accept an `arm64` argument (mirrors build_release_vs2022.bat) -> uses `-A ARM64` and the build-arm64 tree. The top-level CMake auto-derives CMAKE_PREFIX_PATH from the build dir, so no explicit prefix is needed. - build_deps.yml / build_orca.yml: gate the ARM64-only prep behind `inputs.arch == 'arm64'` -- pin CMake 3.31.x, and stage MSYS2 clangarm64 GMP/MPFR import libs. NSIS installer/PDB/profile_validator remain x64-only; ARM64 ships the portable zip. Artifact names get an arch suffix to avoid collisions between the two Windows jobs. https://claude.ai/code/session_0164c7ZhCLsYBmCiVN9pWDjK * ci(temp): generate GMP/MPFR win-arm64 blobs to commit to repo * feat(deps): add prebuilt GMP/MPFR win-arm64 blobs The repo ships prebuilt GMP/MPFR import libs + DLLs for win-x64 and win-x86; the Windows ARM64 build path copies from win-${DEPS_ARCH} (CMakeLists.txt) but the win-arm64 blobs were missing, so the slicer configure failed at "file COPY cannot find .../win-arm64/libgmp-10.dll". Add win-arm64 libgmp-10.{dll,lib} and libmpfr-4.{dll,lib}, generated from the MSYS2 clangarm64 gmp/mpfr packages with MSVC-compatible import libs via llvm-dlltool. Headers are shared across arches and unchanged. * simplify OpenEXR.cmake * set default arch * support msix * ship installer * try to fix webview2runtime issue --------- Co-authored-by: Adam Behrman <adam.behrman@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Adam Behrman <abehrman@users.noreply.github.com>
550 lines
16 KiB
C++
550 lines
16 KiB
C++
#include "StackWalker.h"
|
||
#include <strsafe.h>
|
||
//#include <atlconv.h>
|
||
#include <dbghelp.h>
|
||
#pragma comment(lib, "version.lib")
|
||
#pragma comment( lib, "dbghelp.lib" )
|
||
|
||
CStackWalker::CStackWalker(HANDLE hProcess, WORD wPID, LPCTSTR lpSymbolPath):
|
||
m_hProcess(hProcess),
|
||
m_wPID(wPID),
|
||
m_bSymbolLoaded(FALSE),
|
||
m_lpszSymbolPath(NULL)
|
||
{
|
||
if (NULL != lpSymbolPath)
|
||
{
|
||
size_t dwLength = 0;
|
||
StringCchLength(lpSymbolPath, MAX_SYMBOL_PATH, &dwLength);
|
||
m_lpszSymbolPath = new TCHAR[dwLength + 1];
|
||
ZeroMemory(m_lpszSymbolPath, sizeof(TCHAR) * (dwLength + 1));
|
||
StringCchCopy(m_lpszSymbolPath, dwLength, lpSymbolPath);
|
||
}
|
||
|
||
}
|
||
|
||
CStackWalker::~CStackWalker(void)
|
||
{
|
||
if (NULL != m_lpszSymbolPath)
|
||
{
|
||
delete[] m_lpszSymbolPath;
|
||
}
|
||
|
||
if (m_bSymbolLoaded)
|
||
{
|
||
SymCleanup(m_hProcess);
|
||
}
|
||
}
|
||
|
||
BOOL CStackWalker::LoadSymbol()
|
||
{
|
||
//USES_CONVERSION;
|
||
//只加载一次
|
||
if(m_bSymbolLoaded)
|
||
{
|
||
return m_bSymbolLoaded;
|
||
}
|
||
|
||
if (NULL != m_lpszSymbolPath)
|
||
{
|
||
|
||
m_bSymbolLoaded = SymInitialize(m_hProcess, textconv_helper::T2A_(m_lpszSymbolPath), FALSE);
|
||
return m_bSymbolLoaded;
|
||
}
|
||
|
||
//添加当前程序路径
|
||
TCHAR szSymbolPath[MAX_SYMBOL_PATH] = _T("");
|
||
StringCchCopy(szSymbolPath, MAX_SYMBOL_PATH, _T(".;"));
|
||
|
||
//添加程序所在目录
|
||
TCHAR szTemp[MAX_PATH] = _T("");
|
||
if (GetCurrentDirectory(MAX_PATH, szTemp) > 0)
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
}
|
||
|
||
//添加程序主模块所在路径
|
||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||
if (GetModuleFileName(NULL, szTemp, MAX_PATH) > 0)
|
||
{
|
||
size_t sLength = 0;
|
||
StringCchLength(szTemp, MAX_PATH, &sLength);
|
||
for (int i = sLength; i >= 0; i--)
|
||
{
|
||
if (szTemp[i] == _T('\\') || szTemp[i] == _T('/') || szTemp[i] == _T(':'))
|
||
{
|
||
szTemp[i] = _T('\0');
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
|
||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||
if (GetEnvironmentVariable(_T("_NT_SYMBOL_PATH"), szTemp, MAX_PATH) > 0)
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
}
|
||
|
||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||
if (GetEnvironmentVariable(_T("_NT_ALTERNATE_SYMBOL_PATH"), szTemp, MAX_PATH) > 0)
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
}
|
||
|
||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||
if (GetEnvironmentVariable(_T("SYSTEMROOT"), szTemp, MAX_PATH) > 0)
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
// also add the "system32"-directory:
|
||
StringCchCat(szTemp, MAX_PATH, _T("\\system32"));
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T(";"));
|
||
}
|
||
|
||
ZeroMemory(szTemp, MAX_PATH * sizeof(TCHAR));
|
||
if (GetEnvironmentVariable(_T("SYSTEMDRIVE"), szTemp, MAX_PATH) > 0)
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("SRV*"));
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, szTemp);
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("\\websymbols"));
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("*http://msdl.microsoft.com/download/symbols;"));
|
||
}
|
||
else
|
||
{
|
||
StringCchCat(szSymbolPath, MAX_SYMBOL_PATH, _T("SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"));
|
||
}
|
||
|
||
size_t sLength = 0;
|
||
StringCchLength(szSymbolPath, MAX_SYMBOL_PATH, &sLength);
|
||
if (sLength > 0)
|
||
{
|
||
m_lpszSymbolPath = new TCHAR[sLength + 1];
|
||
ZeroMemory(m_lpszSymbolPath, sizeof(TCHAR) * (sLength + 1));
|
||
StringCchCopy(m_lpszSymbolPath, sLength, szSymbolPath);
|
||
}
|
||
|
||
if (NULL != m_lpszSymbolPath)
|
||
{
|
||
m_bSymbolLoaded = SymInitialize(m_hProcess, textconv_helper::T2A_(m_lpszSymbolPath), TRUE); //这里设置为TRUE,让它在初始化符号表的同时加载符号表
|
||
}
|
||
|
||
DWORD symOptions = SymGetOptions();
|
||
symOptions |= SYMOPT_LOAD_LINES;
|
||
symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||
symOptions |= SYMOPT_DEBUG;
|
||
SymSetOptions(symOptions);
|
||
|
||
return m_bSymbolLoaded;
|
||
}
|
||
|
||
LPMODULE_INFO CStackWalker::GetLoadModules()
|
||
{
|
||
LPMODULE_INFO pHead = GetModulesTH32();
|
||
if (NULL == pHead)
|
||
{
|
||
pHead = GetModulesPSAPI();
|
||
}
|
||
|
||
return pHead;
|
||
}
|
||
|
||
void CStackWalker::FreeModuleInformations(LPMODULE_INFO pmi)
|
||
{
|
||
LPMODULE_INFO head = pmi;
|
||
while (NULL != head)
|
||
{
|
||
pmi = pmi->pNext;
|
||
delete head;
|
||
head = pmi;
|
||
}
|
||
}
|
||
|
||
LPMODULE_INFO CStackWalker::GetModulesTH32()
|
||
{
|
||
//这里为了防止加载Toolhelp.dll 影响最终结果,所以采用动态加载的方式
|
||
LPMODULE_INFO pHead = NULL;
|
||
LPMODULE_INFO pTail = pHead;
|
||
|
||
typedef HANDLE (WINAPI *pfnCreateToolhelp32Snapshot)(DWORD dwFlags, DWORD th32ProcessID);
|
||
typedef BOOL (WINAPI *pfnModule32First)(HANDLE hSnapshot, LPMODULEENTRY32 lpme );
|
||
typedef BOOL (WINAPI *pfnModule32Next)(HANDLE hSnapshot, LPMODULEENTRY32 lpme );
|
||
|
||
const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};
|
||
HINSTANCE hToolhelp = NULL;
|
||
|
||
pfnCreateToolhelp32Snapshot CreateToolhelp32Snapshot = NULL;
|
||
pfnModule32First Module32First = NULL;
|
||
pfnModule32Next Module32Next = NULL;
|
||
|
||
HANDLE hSnap;
|
||
MODULEENTRY32 me;
|
||
me.dwSize = sizeof(me);
|
||
BOOL keepGoing;
|
||
size_t i;
|
||
|
||
for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
|
||
{
|
||
hToolhelp = LoadLibrary(dllname[i]);
|
||
if (hToolhelp == NULL)
|
||
continue;
|
||
CreateToolhelp32Snapshot = (pfnCreateToolhelp32Snapshot)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
|
||
#ifdef UNICODE
|
||
Module32First = (pfnModule32First)GetProcAddress(hToolhelp, "Module32FirstW");
|
||
Module32Next = (pfnModule32Next)GetProcAddress(hToolhelp, "Module32NextW");
|
||
#else
|
||
Module32First = (pfnModule32First)GetProcAddress(hToolhelp, "Module32FirstA");
|
||
Module32Next = (pfnModule32Next)GetProcAddress(hToolhelp, "Module32NextA");
|
||
#endif
|
||
|
||
if ((CreateToolhelp32Snapshot != NULL) && (Module32First != NULL) && (Module32Next != NULL))
|
||
break;
|
||
|
||
FreeLibrary(hToolhelp);
|
||
hToolhelp = NULL;
|
||
}
|
||
|
||
if (hToolhelp == NULL)
|
||
return pHead;
|
||
|
||
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, m_wPID);
|
||
|
||
if (hSnap == INVALID_HANDLE_VALUE)
|
||
{
|
||
FreeLibrary(hToolhelp);
|
||
return pHead;
|
||
}
|
||
|
||
keepGoing = Module32First(hSnap, &me);
|
||
|
||
while (keepGoing)
|
||
{
|
||
LPMODULE_INFO pmi = new MODULE_INFO;
|
||
ZeroMemory(pmi, sizeof(MODULE_INFO));
|
||
|
||
pmi->dwModSize = me.modBaseSize;
|
||
pmi->ModuleAddress = (DWORD64)me.modBaseAddr;
|
||
StringCchCopy(pmi->szModuleName, MAX_MODULE_NAME32, me.szModule);
|
||
StringCchCopy(pmi->szModulePath, MAX_PATH, me.szExePath);
|
||
GetModuleInformation(pmi);
|
||
if (pHead == NULL)
|
||
{
|
||
pHead = pmi;
|
||
pTail = pHead;
|
||
}else
|
||
{
|
||
pTail->pNext = pmi;
|
||
pTail = pmi;
|
||
}
|
||
|
||
keepGoing = Module32Next(hSnap, &me);
|
||
}
|
||
|
||
CloseHandle(hSnap);
|
||
FreeLibrary(hToolhelp);
|
||
return pHead;
|
||
}
|
||
|
||
LPMODULE_INFO CStackWalker::GetModulesPSAPI()
|
||
{
|
||
LPMODULE_INFO pHead = NULL;
|
||
LPMODULE_INFO pTail = pHead;
|
||
typedef BOOL(WINAPI *pfnEnumProcessModules)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,LPDWORD lpcbNeeded);
|
||
typedef DWORD(WINAPI *pfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
||
typedef DWORD(WINAPI *pfnGetModuleBaseName)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
||
typedef BOOL(WINAPI *pfnGetModuleInformation)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);
|
||
|
||
HINSTANCE hPsapi;
|
||
pfnEnumProcessModules EnumProcessModules = NULL;
|
||
pfnGetModuleFileNameEx GetModuleFileNameEx = NULL;
|
||
pfnGetModuleBaseName GetModuleBaseName = NULL;
|
||
pfnGetModuleInformation GetModuleInformation = NULL;
|
||
|
||
DWORD i;
|
||
//ModuleEntry e;
|
||
DWORD cbNeeded;
|
||
MODULEINFO mi;
|
||
HMODULE* hMods = NULL;
|
||
TCHAR szModuleName[MAX_MODULE_NAME32 + 1] = _T("");
|
||
TCHAR szModulePath[MAX_PATH] = _T("");
|
||
|
||
hPsapi = LoadLibrary(_T("psapi.dll"));
|
||
if (hPsapi == NULL)
|
||
{
|
||
return pHead;
|
||
}
|
||
|
||
EnumProcessModules = (pfnEnumProcessModules)GetProcAddress(hPsapi, "EnumProcessModules");
|
||
#ifdef UNICODE
|
||
GetModuleFileNameEx = (pfnGetModuleFileNameEx)GetProcAddress(hPsapi, "GetModuleFileNameExW");
|
||
GetModuleBaseName = (pfnGetModuleBaseName)GetProcAddress(hPsapi, "GetModuleBaseNameW");
|
||
#else
|
||
GetModuleFileNameEx = (pfnGetModuleFileNameEx)GetProcAddress(hPsapi, "GetModuleFileNameExA");
|
||
GetModuleBaseName = (pfnGetModuleBaseName)GetProcAddress(hPsapi, "GetModuleBaseNameA");
|
||
#endif
|
||
GetModuleInformation = (pfnGetModuleInformation)GetProcAddress(hPsapi, "GetModuleInformation");
|
||
if ((EnumProcessModules == NULL) || (GetModuleFileNameEx == NULL) || (GetModuleBaseName == NULL) || (GetModuleInformation == NULL))
|
||
{
|
||
FreeLibrary(hPsapi);
|
||
return pHead;
|
||
}
|
||
|
||
EnumProcessModules(m_hProcess, hMods, 0, &cbNeeded);
|
||
hMods = new HMODULE[cbNeeded / sizeof(HMODULE)];
|
||
ASSERT(NULL != hMods);
|
||
ZeroMemory(hMods, cbNeeded);
|
||
|
||
if (!EnumProcessModules(m_hProcess, hMods, cbNeeded, &cbNeeded))
|
||
{
|
||
goto cleanup;
|
||
}
|
||
|
||
for (i = 0; i < cbNeeded / sizeof(HMODULE); i++)
|
||
{
|
||
GetModuleInformation(m_hProcess, hMods[i], &mi, sizeof(mi));
|
||
GetModuleFileNameEx(m_hProcess, hMods[i], szModulePath, MAX_PATH);
|
||
GetModuleBaseName(m_hProcess, hMods[i], szModuleName, MAX_MODULE_NAME32);
|
||
LPMODULE_INFO pmi = new MODULE_INFO;
|
||
ZeroMemory(pmi, sizeof(MODULE_INFO));
|
||
pmi->dwModSize = mi.SizeOfImage;
|
||
pmi->ModuleAddress = (DWORD64)mi.lpBaseOfDll;
|
||
StringCchCopy(pmi->szModuleName, MAX_MODULE_NAME32, szModuleName);
|
||
StringCchCopy(pmi->szModulePath, MAX_PATH, szModulePath);
|
||
this->GetModuleInformation(pmi);
|
||
if (pHead == NULL)
|
||
{
|
||
pHead = pmi;
|
||
pTail = pHead;
|
||
}else
|
||
{
|
||
pTail->pNext = pmi;
|
||
pTail = pmi;
|
||
}
|
||
}
|
||
|
||
cleanup:
|
||
if (hPsapi != NULL)
|
||
{
|
||
FreeLibrary(hPsapi);
|
||
}
|
||
if (hMods != NULL)
|
||
{
|
||
delete[] hMods;
|
||
}
|
||
|
||
return pHead;
|
||
}
|
||
|
||
void CStackWalker::OutputString(LPCTSTR lpszFormat, ...)
|
||
{
|
||
TCHAR szBuf[1024] = _T("");
|
||
va_list args;
|
||
va_start(args, lpszFormat);
|
||
_vsntprintf_s(szBuf, 1024, lpszFormat, args);
|
||
va_end(args);
|
||
|
||
OutputDebugString(szBuf);
|
||
}
|
||
|
||
void CStackWalker::GetModuleInformation(LPMODULE_INFO pmi)
|
||
{
|
||
//USES_CONVERSION;
|
||
IMAGEHLP_MODULE64 im = {0};
|
||
im.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
||
|
||
VS_FIXEDFILEINFO* pvfi = NULL;
|
||
DWORD dwHandle = 0;
|
||
DWORD dwInfoSize = 0;
|
||
dwInfoSize = GetFileVersionInfoSize(pmi->szModulePath, &dwHandle);
|
||
|
||
if (dwInfoSize > 0)
|
||
{
|
||
LPVOID lpData = new byte[dwInfoSize];
|
||
ZeroMemory(lpData, dwInfoSize * sizeof(byte));
|
||
|
||
if (GetFileVersionInfo(pmi->szModulePath, dwHandle, dwInfoSize, lpData) > 0 )
|
||
{
|
||
TCHAR szBlock[] = _T("\\");
|
||
UINT len;
|
||
if (VerQueryValue(lpData, szBlock, (LPVOID*)&pvfi, &len))
|
||
{
|
||
WORD v1 = HIWORD(pvfi->dwFileVersionMS);
|
||
WORD v2 = LOWORD(pvfi->dwFileVersionMS);
|
||
WORD v3 = HIWORD(pvfi->dwFileVersionLS);
|
||
WORD v4 = LOWORD(pvfi->dwFileVersionLS);
|
||
_stprintf_s(pmi->szVersion, MAX_VERSION_LENGTH, _T("%d.%d.%d.%d"), v1, v2, v3, v4);
|
||
}
|
||
}
|
||
|
||
delete[] lpData;
|
||
}
|
||
|
||
SymGetModuleInfo64(m_hProcess, pmi->ModuleAddress, &im);
|
||
StringCchCopy(pmi->szSymbolPath, MAX_PATH, textconv_helper::A2T_(im.LoadedPdbName));
|
||
}
|
||
|
||
LPSTACKINFO CStackWalker::StackWalker(HANDLE hThread, const CONTEXT* context)
|
||
{
|
||
//USES_CONVERSION;
|
||
//加载符号表
|
||
LoadSymbol();
|
||
|
||
LPSTACKINFO pHead = NULL;
|
||
LPSTACKINFO pTail = pHead;
|
||
|
||
//获取当前线程的上下文环境
|
||
CONTEXT c = {0};
|
||
if (context == NULL)
|
||
{
|
||
#if _WIN32_WINNT <= 0x0501
|
||
if (hThread == GetCurrentThread())
|
||
#else
|
||
if (GetThreadId(hThread) == GetCurrentThreadId())
|
||
#endif
|
||
{
|
||
GET_CURRENT_THREAD_CONTEXT(c, CONTEXT_FULL);
|
||
}
|
||
else
|
||
{
|
||
//如果不是当前线程,需要停止目标线程,以便取出正确的堆栈信息
|
||
SuspendThread(hThread);
|
||
memset(&c, 0, sizeof(CONTEXT));
|
||
c.ContextFlags = CONTEXT_FULL;
|
||
if (GetThreadContext(hThread, &c) == FALSE)
|
||
{
|
||
ResumeThread(hThread);
|
||
return NULL;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
c = *context;
|
||
|
||
STACKFRAME64 sf = {0};
|
||
DWORD imageType;
|
||
|
||
//intel X86
|
||
#ifdef _M_IX86
|
||
imageType = IMAGE_FILE_MACHINE_I386;
|
||
sf.AddrPC.Offset = c.Eip;
|
||
sf.AddrPC.Mode = AddrModeFlat;
|
||
sf.AddrFrame.Offset = c.Ebp;
|
||
sf.AddrFrame.Mode = AddrModeFlat;
|
||
sf.AddrStack.Offset = c.Esp;
|
||
sf.AddrStack.Mode = AddrModeFlat;
|
||
// AMD
|
||
#elif _M_X64
|
||
imageType = 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;
|
||
////intel Itanium(安腾)
|
||
#elif _M_IA64
|
||
imageType = 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;
|
||
// ARM64
|
||
#elif defined(_M_ARM64)
|
||
imageType = IMAGE_FILE_MACHINE_ARM64;
|
||
sf.AddrPC.Offset = c.Pc;
|
||
sf.AddrPC.Mode = AddrModeFlat;
|
||
sf.AddrFrame.Offset = c.Fp;
|
||
sf.AddrFrame.Mode = AddrModeFlat;
|
||
sf.AddrStack.Offset = c.Sp;
|
||
sf.AddrStack.Mode = AddrModeFlat;
|
||
#else
|
||
#error "Platform not supported!"
|
||
#endif
|
||
|
||
|
||
DWORD64 dwDisplayment = 0;
|
||
PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)new BYTE[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN];
|
||
PIMAGEHLP_LINE64 pLine = new IMAGEHLP_LINE64;
|
||
while (StackWalk64(imageType, m_hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||
{
|
||
ZeroMemory(pSym, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
|
||
ZeroMemory(pLine, sizeof(IMAGEHLP_LINE64));
|
||
|
||
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||
pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
|
||
pLine->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||
|
||
LPSTACKINFO pCallStack = new STACKINFO;
|
||
ZeroMemory(pCallStack, sizeof(STACKINFO));
|
||
pCallStack->szFncAddr = sf.AddrPC.Offset;
|
||
if (sf.AddrPC.Offset != 0)
|
||
{
|
||
if(SymGetSymFromAddr64(m_hProcess, sf.AddrPC.Offset, &dwDisplayment, pSym))
|
||
{
|
||
char szName[STACKWALK_MAX_NAMELEN] = "";
|
||
StringCchCopy(pCallStack->szFncName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(pSym->Name));
|
||
UnDecorateSymbolName(pSym->Name, szName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
|
||
StringCchCopy(pCallStack->undFullName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(szName));
|
||
ZeroMemory(szName, STACKWALK_MAX_NAMELEN * sizeof(char));
|
||
UnDecorateSymbolName(pSym->Name, szName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
|
||
StringCchCopy(pCallStack->undName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_(szName));
|
||
}else
|
||
{
|
||
//调用错误一般是487(地址无效或者没有访问的权限、在符号表中未找到指定地址的相关信息)
|
||
//this->OutputString(_T("Call SymGetSymFromAddr64 ,Address %08x Error:%08x\n"), sf.AddrPC.Offset, GetLastError());
|
||
|
||
StringCchCopy(pCallStack->undFullName, STACKWALK_MAX_NAMELEN, textconv_helper::A2T_("Unknown"));
|
||
}
|
||
|
||
if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, (DWORD*)&dwDisplayment, pLine))
|
||
{
|
||
StringCchCopy(pCallStack->szFileName, MAX_PATH, textconv_helper::A2T_(pLine->FileName));
|
||
pCallStack->uFileNum = pLine->LineNumber;
|
||
}else
|
||
{
|
||
//this->OutputString(_T("Call SymGetLineFromAddr64 ,Address %08x Error:%08x\n"), sf.AddrPC.Offset, GetLastError());
|
||
|
||
StringCchCopy(pCallStack->szFileName, MAX_PATH, textconv_helper::A2T_("Unknown file"));
|
||
pCallStack->uFileNum = -1;
|
||
}
|
||
|
||
//这里为了将获取函数信息失败的情况与正常的情况一起输出,防止用户在查看时出现误解
|
||
this->OutputString(_T("%08llx:%s [%s][%ld]\n"), pCallStack->szFncAddr, pCallStack->undFullName, pCallStack->szFileName, pCallStack->uFileNum);
|
||
if (NULL == pHead)
|
||
{
|
||
pHead = pCallStack;
|
||
pTail = pHead;
|
||
}else
|
||
{
|
||
pTail->pNext = pCallStack;
|
||
pTail = pCallStack;
|
||
}
|
||
}
|
||
}
|
||
|
||
delete[] pSym;
|
||
delete pLine;
|
||
|
||
return pHead;
|
||
}
|
||
|
||
void CStackWalker::FreeStackInformations(LPSTACKINFO psi)
|
||
{
|
||
LPSTACKINFO head = psi;
|
||
while (NULL != head)
|
||
{
|
||
psi = psi->pNext;
|
||
delete head;
|
||
head = psi;
|
||
}
|
||
|
||
} |