Files
OrcaSlicer-KX/src/dev-utils/StackWalker.cpp
SoftFever 451d2f946f feat: native Windows ARM64 build support (Snapdragon X Elite) (supersedes #14059) (#14381)
* 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>
2026-06-26 02:26:23 +08:00

550 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}