gpt4 book ai didi

c++ - StackWalk64 不适用于发布版本

转载 作者:太空宇宙 更新时间:2023-11-04 15:06:51 25 4
gpt4 key购买 nike

以下是我的代码,仅来自开源代码。为什么 StackWalk64 不适用于 release builddebug build without pdbs

头文件

#ifndef STACK_TRACE_H_
#define STACK_TRACE_H_

#include <string>
#include <deque>

struct StackItem {
std::string m_name;
std::string m_file;
int m_line;

StackItem() : m_line(0) {}
};

class StackTraceImpl;

class StackTrace {
public:
typedef std::deque<StackItem> ItemContainer;
typedef ItemContainer::const_iterator ItemIterator;

ItemContainer m_items;
StackTraceImpl *m_impl;
public:

StackTrace();
virtual ~StackTrace();
void print() const;

void popFront() {
m_items.pop_front();
}
ItemIterator begin() const {
return m_items.begin();
}
ItemIterator end() const {
return m_items.end();
}

};

#endif

CPP 文件

#include <windows.h>
#include <DbgHelp.h>
#include <tlhelp32.h>
#include <vector>

#include <iostream>

#include "StackTrace.h"

std::size_t const SYMBOL_NAME_MAXLEN = 1024;

struct SymStartup {
HANDLE process;
SymStartup(HANDLE process) : process(process) {
char current[MAX_PATH];
std::string path;
if (GetCurrentDirectoryA(MAX_PATH, current) > 0) {
path += current;
path += ";";
}

if (GetModuleFileNameA(NULL, current, MAX_PATH) > 0) {
std::string filePath = current;
std::string::size_type pos = filePath.find_last_of('\\');
if (pos != std::string::npos)
filePath.erase(pos);

path += filePath;
path += ";";
}

if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", current, MAX_PATH) > 0) {
path += current;
path += ";";
}

if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", current, MAX_PATH) > 0) {
path += current;
path += ";";
}

if (GetEnvironmentVariableA("SYSTEMROOT", current, MAX_PATH) > 0) {
path += current;
path += ";";
path += current;
path += "\\system32";
path += ";";
}

if (!SymInitialize(process, path.c_str(), FALSE))
throw 1;

DWORD options = SymGetOptions();
options |= SYMOPT_LOAD_LINES;
options |= SYMOPT_FAIL_CRITICAL_ERRORS;

options = SymSetOptions(options);
}

~SymStartup() {
if (process)
SymCleanup(process);
}
};


//inline std::string wstr2str(std::wstring const& ws)
//{
// using namespace std;
// std::string mbs;
// ctype<wchar_t> const& conv(use_facet<ctype<wchar_t> >(locale()));
//
// mbs.reserve(ws.size());
// for (wstring::const_iterator it = ws.begin(); it != ws.end(); ++it)
// mbs.push_back(conv.narrow(*it, '?'));
//
// return mbs;
//}

std::string wstr2str(const std::wstring &wstr) {
std::string strTo;
char *szTo = new char[wstr.length() + 1];
szTo[wstr.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
strTo = szTo;
delete[] szTo;
return strTo;
}


class StackTraceImpl {
private:
void load_modules(HANDLE process, DWORD processID) {
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processID);
if (snap == INVALID_HANDLE_VALUE)
return;

MODULEENTRY32 entry;
entry.dwSize = sizeof(entry);

if (Module32First(snap, &entry)) {
do {
std::string fileName = wstr2str(entry.szExePath);
std::string moduleName = wstr2str(entry.szModule);
SymLoadModule64(process, NULL, fileName.c_str(), moduleName.c_str(), (DWORD64) entry.modBaseAddr, entry.modBaseSize);
} while (Module32Next(snap, &entry));
}
CloseHandle(snap);
}

void retrieve_context(CONTEXT& context) {
std::memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
}

void retrieve_frame(CONTEXT& context, STACKFRAME64& frame, DWORD& imageType) {
std::memset(&frame, 0, sizeof(frame));
#ifdef _M_IX86
imageType = 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
imageType = 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
imageType = 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 "Platform not supported!"
#endif
}

public:
void retrieve(StackTrace::ItemContainer& items) {
HANDLE process = 0;

try {
items.clear();
process = GetCurrentProcess();
SymStartup startup(process);
load_modules(process, GetCurrentProcessId());

HANDLE thread = GetCurrentThread();

CONTEXT context;
retrieve_context(context);

DWORD imageType = 0;
STACKFRAME64 frame;
retrieve_frame(context, frame, imageType);

std::vector<char> symbolData(sizeof(IMAGEHLP_SYMBOL64) + SYMBOL_NAME_MAXLEN, 0);

IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(&symbolData[0]);
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol->MaxNameLength = SYMBOL_NAME_MAXLEN;

IMAGEHLP_LINE64 m_line;
std::memset(&m_line, 0, sizeof(IMAGEHLP_LINE64));
m_line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

for (int frameNum = 0; true; ++frameNum) {
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL))
break;

if (frame.AddrPC.Offset == frame.AddrReturn.Offset)
break;

if (frame.AddrPC.Offset != 0) {
StackItem item;

DWORD64 displacement64 = 0;
if (SymGetSymFromAddr64(process, frame.AddrPC.Offset, &displacement64, symbol)) {
char symbolName[SYMBOL_NAME_MAXLEN];
std::strncpy(symbolName, symbol->Name, SYMBOL_NAME_MAXLEN);

UnDecorateSymbolName(symbol->Name, symbolName, SYMBOL_NAME_MAXLEN, UNDNAME_COMPLETE);
item.m_name.assign(symbolName, symbolName + std::strlen(symbolName));
}

DWORD displacement = 0;
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, &m_line)) {
item.m_line = m_line.LineNumber;
item.m_file.assign(m_line.FileName, m_line.FileName + std::strlen(m_line.FileName));
}
items.push_back(item);
}
if (frame.AddrReturn.Offset == 0)
break;
}
} catch (...) {
}
}
};

StackTrace::StackTrace() : m_impl(new StackTraceImpl) {
m_impl->retrieve(m_items);
if (m_items.size() > 1)
m_items.erase(m_items.begin(), m_items.begin() + 2);
}

StackTrace::~StackTrace() {
}

void StackTrace::print() const {
for (StackTrace::ItemIterator it = m_items.begin(), end = m_items.end(); it != end; ++it)
std::cout << it->m_file << "(" << it->m_line << ") : " << it->m_name << std::endl;
}

主文件

#include "StackTrace.h"
void func1() {
StackTrace st;
st.print();
}
void func2() {
func1();
}
void func3() {
func2();
}
void func4() {
func3();
}
void func5() {
func4();
}
void func6() {
func5();
}
int main ( int argc, char **argv ) {
func5();
return 0;
}

调试构建输出

E:\Avinash\my_work\StackWalk64>Debug\StackWalk64.exe
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(3) : func1
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(8) : func2
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(11) : func3
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(14) : func4
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(17) : func5
e:\avinash\my_work\stackwalk64\stackwalk64\stackwalk64main.cpp(23) : main
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c(555) : __tmainCRTStartup
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c(371) : mainCRTStartup
(0) : BaseThreadInitThunk
(0) : RtlInitializeExceptionChain
(0) : RtlInitializeExceptionChain

发布构建输出

E:\Avinash\my_work\StackWalk64>Release\StackWalk64.exe
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c(555) : __tmainCRTStartup
(0) : BaseThreadInitThunk
(0) : RtlInitializeExceptionChain
(0) : RtlInitializeExceptionChain

删除 PDB 文件后

E:\Avinash\my_work\StackWalk64\Debug>StackWalk64.exe
(0) :
(0) :
(0) :
(0) :
(0) :
(0) :
(0) :
(0) :
(0) : BaseThreadInitThunk
(0) : RtlInitializeExceptionChain
(0) : RtlInitializeExceptionChain

最佳答案

您不能指望在优化代码上可靠地遍历堆栈。消除堆栈帧位于代码优化器命中列表的顶部。 “省略帧指针”优化是一个重要的优化,它释放了一个额外的寄存器 (EBP),这对于 x86 代码总是很重要。它通常默认关闭,但代码生成器在可以内联函数时无论如何都会应用它。

最强的是“Inline function expansion”优化,它用目标函数体中的代码替换函数调用。这对你的测试代码有很大帮助,它完全消除了你的所有功能。换句话说,func1() 中的代码被移到了 main() 中。

禁用这些优化是不明智的,它会极大地影响代码的效率。 C 和 C++ 语言被设计为快速,可调试性不是主要考虑因素。这就是首先存在调试和发布配置的原因。请记住,您的测试代码过于人为化,无法可靠地指示实际代码中会发生什么。您将从堆栈跟踪中得到一些东西,而不是您在调试代码时习惯的东西。

关于c++ - StackWalk64 不适用于发布版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12280472/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com