gpt4 book ai didi

c++ - Stackwalk 在调试中获取函数名、行号和文件名

转载 作者:行者123 更新时间:2023-11-30 04:48:37 25 4
gpt4 key购买 nike

快速总结

简而言之,我希望访问有关堆栈的调试信息,最好是将信息传递给 Logger。

我希望信息告诉我函数名行号文件名

我有这些符号,我正在尝试访问其中的垃圾值并将它们转换为英语。但是似乎没有任何效果。

我已经对代码进行了注释以供人们阅读,看看他们是否可以帮助我有效地遍历堆栈以提取我需要的信息。

  • 到目前为止,我可以指出 SymGetModuleBase() 不只返回正数 0,根据 MSDN,如果返回 0 则失败。这是正确的,因为它返回内存地址。

  • SymGetSymFromAddr() 无法返回 true,我假设它获取了堆栈框架/函数的名称

  • SymGetLineFromAddr() 继续失败,不返回文件中的行号位置,也不收集文件路径。

    <

我认为这是由于 process 参数无效所致。我将在下面详细说明。

尝试定位并修复问题

  • 我反复阅读了 MSDN 文档,感觉自己好像在用脑袋撞墙,我几乎按照文档中的说明做了很多,但我觉得它就是行不通。

    <
  • 但是我注意到 SymInitialize() 应该在尝试之前调用,我确实调用了。这将 GetLastError() 值从 6 ERROR_INVALID_HANDLE 更改为 0 ERROR_SUCCESS。然而,无论是否使用 SymInitialize()SymGetModuleBase() 仍然返回 0,尽管 GetLastError() 根据 SymInitialize() 报告不同的错误代码 使用。它应该返回一个有效的虚拟内存地址,这是我认为主要问题出在代码中的地方。

  • HANDLE process =::GetCurrentProcess(); 下面代码中的这一行返回 0xffffffffffffffff 如果你问我,我很怀疑。这应该返回一个伪虚拟内存地址,但无论如何对我来说它看起来像是一个错误的结果。每次我运行程序时都会发生这种情况,这让我想到 ::GetCurrentProcess() 这要么是有错误,要么是因为某种原因不起作用。根据 MSDN,这是获取当前进程的正确最新方法,我不知道如何以另一种方式获取进程的有效 HANDLE。所以我无法在正确的过程中传递 SymGetModuleBase() 中的第一个参数,尽管我可能错了。

函数的完整代码

void Logger::WriteStackFrames(log::TextColor tc)
{
// Initalize some memory
DWORD machine = IMAGE_FILE_MACHINE_AMD64;
HANDLE process = ::GetCurrentProcess();
HANDLE thread = GetCurrentThread();

// Initalize more memory
CONTEXT context;
STACKFRAME stack_frame;

// Set some memory
memset(&context, 0, sizeof(CONTEXT));
memset(&stack_frame, 0, sizeof(STACKFRAME));

// Capture the context
RtlCaptureContext(&context);

// Initalize a few things here and there
stack_frame.AddrPC.Offset = context.Rip;
stack_frame.AddrPC.Mode = AddrModeFlat;
stack_frame.AddrStack.Offset = context.Rsp;
stack_frame.AddrStack.Mode = AddrModeFlat;
stack_frame.AddrFrame.Offset = context.Rbp;
stack_frame.AddrFrame.Mode = AddrModeFlat;

// Randomly saw this was supposed to be called prior to StackWalk so tried it
if (!SymInitialize(process, 0, false))
{
wprintf(L"SymInitialize unable to find process!! Error: %d\r\n", GetLastError());
}

for (ULONG frame = 0; ; frame++)
{
// Set text color
SetTextColor(tc);

// Check for frames
BOOL result = StackWalk(machine, process, thread, &stack_frame, &context, 0,
SymFunctionTableAccess, SymGetModuleBase, 0);

// Get memory address of base module. Returns 0 although when SymInitialize is called before it the GetLastError returns 0 without return 6
DWORD64 module_base = SymGetModuleBase(process, stack_frame.AddrPC.Offset);
if (module_base == 0) {
wprintf(L"SymGetModuleBase is unable to get virutal address!! Error: %d\r\n", GetLastError());
}

// Initalize more memory
MODULEINFO module_info;
SecureZeroMemory(&module_info, sizeof(MODULEINFO));

// Get the file name of the file containing the function
TCHAR module_buffer[log::MaxPath];
DWORD mod_file = GetModuleFileName((HINSTANCE)module_base, module_buffer, log::MaxPath);
if ((module_base != 0) && (mod_file != 0))
{
module_info.module_name = module_buffer;
}

// Initalize more memory and clear it out
PIMAGEHLP_SYMBOL64 symbol;
IMAGEHLP_LINE64 line_num;
SecureZeroMemory(&symbol, sizeof(PIMAGEHLP_SYMBOL64));
SecureZeroMemory(&symbol, sizeof(IMAGEHLP_LINE64));

// Get the symbol
TCHAR symbol_buffer[log::MaxPath];
symbol = (PIMAGEHLP_SYMBOL)symbol_buffer;
symbol->SizeOfStruct = (sizeof(IMAGEHLP_SYMBOL) + log::MaxPath);
symbol->MaxNameLength = 254;

// Attempt to get name from symbol (fails)
LPSTR name_buffer = new CHAR[254];
if (SymGetSymFromAddr(process, stack_frame.AddrPC.Offset, 0, symbol))
{
name_buffer = symbol->Name;
}

// Set the size of something
DWORD offset = 0;
line_num.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

// Attempt to get the line and file name of where the symbol is
if (SymGetLineFromAddr(process, stack_frame.AddrPC.Offset, &offset, &line_num))
{
module_info.line = line_num.LineNumber;
module_info.file = line_num.FileName;
}

// Initalize memory
LPWSTR console_message = new TCHAR[log::MaxMsgLength];
LPWSTR file_message = new TCHAR[log::MaxMsgLength];

// Set some strings
swprintf(console_message, log::MaxMsgLength, L">> Frame %02lu: called from: %016X Stack: %016X Frame: %016X Address return: %016X\r\n",
frame, stack_frame.AddrPC.Offset, stack_frame.AddrStack.Offset, stack_frame.AddrFrame.Offset, stack_frame.AddrReturn.Offset);
swprintf(file_message, log::MaxMsgLength, L"Frame %02lu: called from: %016X Stack: %016X Frame: %016X Address return: %016X\r\n",
frame, stack_frame.AddrPC.Offset, stack_frame.AddrStack.Offset, stack_frame.AddrFrame.Offset, stack_frame.AddrReturn.Offset);

/* When the symbol can yield the name, line and file name the above strings
will also include that information */
// To go here . . .

// Write some strings
wprintf(console_message);
WriteAsync(file_message);

// Delete some memory
if (console_message) {
delete[] console_message; console_message = nullptr;
}
if (file_message) {
delete[] file_message; file_message = nullptr;
}

// If nothing else to do break loop
if (!result) {
break;
}
}
}

我希望实现的目标

尽管我意识到这只能在 Debug模式下正常工作,而且我知道我可以使用 __LINE__ __FUNCTION__ __FILE__ 宏编写宏,但这不是我想要的。

结果应该是从底部堆栈开始的结束,显示调用 PC、堆栈和帧的内存地址。这行得通。

但是它还应该显示函数的名称、行号和文件路径。这行不通。

仅供引用:我意识到我需要将代码添加到生成字符串并输出它,但代码无法获取字符串的信息,因此尚未编码。

如果有人能帮助我,那就太棒了,所有代码都集中在“DbgHelp.h”windows 文件周围,大部分信息都可以在 MSDN 上找到。所以对于这个很长的问题,但我觉得我应该提供我所知道的一切。

最佳答案

::GetCurrentProcess() = 0xffffffffffffffff

没有可疑。

关于c++ - Stackwalk 在调试中获取函数名、行号和文件名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55742243/

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