0

以下は、オープンソースのみからの私のコードです。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ファイル

#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
4

1 に答える 1

9

最適化されたコードでスタックを確実にウォークすることは期待できません。スタックフレームの削除は、コードオプティマイザーのヒットリストの一番上にあります。「フレームポインタを省略する」最適化は重要なものであり、余分なレジスタ(EBP)を解放します。これは、x86コードにとって常に重要です。通常はデフォルトでオフになっていますが、コードジェネレーターは関数をインライン化できる場合にとにかくそれを適用します。

最も強力なのは「インライン関数拡張」最適化であり、関数呼び出しをターゲット関数本体のコードに置き換えます。これはあなたのテストコードに良い数字を与えます、それはあなたのすべての機能を完全に排除します。つまり、func1()内のコードはmain()に移動されます。

これらの最適化を無効にすることは賢明ではありません。コードの効率に大きな影響を与える可能性があります。CおよびC++言語は高速になるように設計されており、デバッグ可能性は主要な考慮事項ではありませんでした。そもそもデバッグとリリースの構成が存在するのはそのためです。テストコードは人工的すぎて、実際のコードで何が起こるかを信頼できる指標にできないことに注意してください。コードをデバッグするときに慣れているものではなく、スタックトレースから何かを取得します。

于 2012-09-05T12:59:18.157 に答える