StackWalk64 не работает с выпуском сборки

Ниже приведен мой код, только с открытым исходным кодом. Почему StackWalk64 не работает с release build а также debug 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 FILE

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

DEBUG СТРОИТЕЛЬНЫЙ ВЫХОД

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

0

Решение

Вы не можете ожидать надежного обхода стека по оптимизированному коду. Устранение кадров стека находится в верхней части списка совпадений для оптимизатора кода. Оптимизация «Опустить указатель кадра» является важной, которая освобождает дополнительный регистр (EBP), всегда важный для кода x86. Обычно он выключен по умолчанию, но генератор кода применяет его в любом случае, когда он может выполнять встроенные функции.

Наиболее сильной является оптимизация «Расширение встроенной функции», она заменяет вызов функции кодом в теле целевой функции. Что делает хороший номер в вашем тестовом коде, это полностью исключает все ваших функций. Другими словами, код внутри func1 () перемещается в main ().

Отключать эти оптимизации неразумно, это может сильно повлиять на эффективность вашего кода. Языки C и C ++ были разработаны, чтобы быть быстрыми, отладка не была главным соображением. Вот почему конфигурация отладки и выпуска существует в первую очередь. Помните, что ваш тестовый код слишком искусственный, чтобы быть надежным индикатором того, что произойдет в реальном коде. Ты получишь что-то из трассировки стека, просто не то, к чему вы привыкли при отладке кода.

7

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector