- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
以下是我的代码,仅来自开源代码。为什么 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
最佳答案
您不能指望在优化代码上可靠地遍历堆栈。消除堆栈帧位于代码优化器命中列表的顶部。 “省略帧指针”优化是一个重要的优化,它释放了一个额外的寄存器 (EBP),这对于 x86 代码总是很重要。它通常默认关闭,但代码生成器在可以内联函数时无论如何都会应用它。
最强的是“Inline function expansion”优化,它用目标函数体中的代码替换函数调用。这对你的测试代码有很大帮助,它完全消除了你的所有功能。换句话说,func1() 中的代码被移到了 main() 中。
禁用这些优化是不明智的,它会极大地影响代码的效率。 C 和 C++ 语言被设计为快速,可调试性不是主要考虑因素。这就是首先存在调试和发布配置的原因。请记住,您的测试代码过于人为化,无法可靠地指示实际代码中会发生什么。您将从堆栈跟踪中得到一些东西,而不是您在调试代码时习惯的东西。
关于c++ - StackWalk64 不适用于发布版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12280472/
你知道如何在delphi中读取另一个进程堆栈吗?? 最佳答案 是的。 您可以使用 Toolhelp 枚举线程功能;使用 GetThreadContext() 获取上下文;并使用 ReadProcess
快速总结 简而言之,我希望访问有关堆栈的调试信息,最好是将信息传递给 Logger。 我希望信息告诉我函数名、行号和文件名。 我有这些符号,我正在尝试访问其中的垃圾值并将它们转换为英语。但是似乎没有任
有没有人知道比“StackWalk”更好/更快的获取调用堆栈的方法?我还认为 stackwalk 在有很多变量的方法上也会变慢......(我想知道商业分析员是做什么的?)我在 Windows 上使用
我可以构建 google breakpad 客户端,stackwalker 可以将转储转换为人类可读的 txt 文件。但是没有制作vs2008解决方案的gyp文件。有谁知道如何在 Windows 上构
我可能做错了什么,但我无法弄清楚这一点。 我有一个简单的崩溃小型转储,在 Windows 上生成。 如果我在 Visual Studio 中打开转储,它会毫无问题地加载并显示崩溃线。 但是我无法在 m
我正在尝试使用 Java 9 的 Stackwalking API,并注意到收集的帧少于实际堆栈跟踪给出的帧。我想知道是否有可能获得相同数量的框架和元素? 看看下面的测试: @Test public
我正在尝试使用 Java 9 的 Stackwalking API,并注意到收集的帧少于实际堆栈跟踪给出的帧。我想知道是否有可能获得相同数量的框架和元素? 看看下面的测试: @Test public
这是一个错误吗?我至少期望出现异常而不是空字符串: jshell> ((Supplier)(()->StackWalker.getInstance(StackWalker.Option.RETAIN_
我习惯于使用 gprof 来分析我的 C 代码,但我想开始使用基于 GUI 的 Windows 应用程序,例如 Luke Stackwalker。 gprof 在我的二进制文件上工作得很好,但是 Lu
需要通过线程句柄打印 C++ 应用程序线程的调用堆栈,我求助于 StackWalker这在以前的 stackoverflow 答案中提到过。 然而,the StakWalker code日期为 200
Java9 的新 StackWalker 特性让我意识到,如果 Eclipse(最好是 IntelliJ)可以配置为使用自定义 StackWalker,它可以修改 IDE 调试器中的正常调用堆栈 Vi
我正在尝试在异常 block 中打印堆栈遍历器,但它仅显示当前类 public class Test1 { public void test() throws Exception{
我一直在探索 jdk9 中引入的 StackWalking API。使用或不使用选项 StackWalker.Option.SHOW_HIDDEN_FRAMES,我看不出输出有任何差异。 根据 API
我是一名优秀的程序员,十分优秀!