2012-09-05 87 views
0

以下是我的代码,仅来自开放源代码。为什么StackWalk64不release builddebug build without pdbsStackWalk64不适用于发布版本

头文件

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

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 
+1

这很可能是由于优化。 –

+0

@Joachim Pileborg:是的,禁用优化后,一切都开始正常工作。但不幸的是,我的产品与“全面优化” – Avinash

回答

7

你不能指望可靠地走邻堆栈优化代码。消除堆栈帧位于代码优化器的命中列表的顶部。 “忽略帧指针”优化是一个非常重要的优化,它释放了一个额外的寄存器(EBP),对于x86代码来说总是很重要。它通常默认是关闭的,但代码生成器在内联函数时可以应用它。

最强的是“内联函数扩展”优化,它用目标函数体中的代码替换函数调用。它在你的测试代码上做了一个好数字,它完全消除了你的函数的所有全部。换句话说,func1()中的代码被移入main()。

禁用这些优化是不明智的,它会极大地影响代码的效率。 C和C++语言设计得很快,可调试性不是主要考虑因素。这就是为什么Debug和Release配置首先存在的原因。切记,你的测试代码太虚假了,不能作为实际代码中会发生什么的可靠指标。你会得到出栈跟踪,只是不是你在调试代码时习惯的。

相关问题