根据here和here的建议,我创建了一个类来打印带有行号的调用堆栈,只需在我的代码中的某个位置插入一个调用。它运作良好,但是,我对输出的一个方面感到困惑 - 行号。我的测试代码:
#define _WIN32 1
#define DEBUG 1
#include "C:\git\StackTrace\StackTrace.h"
int main()
{
MyCompany::PrintStackTrace();
return 0;
}
打印堆栈跟踪的调用在线 8 ,但是,输出表明它在线 9 :
*** 0: main in c:\git\tests\stacktrace\stacktrace\st_test.cpp: line: 9: address: 0x7FF629172070
*** 1: invoke_main in f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl: line: 41: address: 0x7FF629173710
*** 2: __scrt_common_main_seh in f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl: line: FD: address: 0x7FF6291734C0
*** 3: __scrt_common_main in f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl: line: 128: address: 0x7FF6291734A0
*** 4: mainCRTStartup in f:\dd\vctools\crt\vcstartup\src\startup\exe_main.cpp: line: 11: address: 0x7FF629173760
*** SymGetLineFromAddr64 returned error code 487
*** at BaseThreadInitThunk address 0x7FFA09648350
*** SymGetLineFromAddr64 returned error code 487
*** at RtlUserThreadStart address 0x7FFA0BF070B0
请帮助我理解我在这里缺少什么?
我的StackTrace.h代码:
#ifdef _WIN32
#ifdef DEBUG
#include <Windows.h>
#include <fstream>
#include <iostream>
#include <DbgHelp.h>
#include <WinBase.h>
#pragma comment(lib, "Dbghelp.lib")
using namespace std;
namespace MyCompany
{
class StackTrace
{
private:
static bool instanceFlag;
static StackTrace *single;
StackTrace() { }
public:
static StackTrace* GetInstance();
void PrintStack();
void PrintStack(ostream& out, int skipFrames);
~StackTrace()
{
instanceFlag = false;
}
};
bool StackTrace::instanceFlag = false;
StackTrace* StackTrace::single = NULL;
/**
* Returns the instance of the StackTrace class, generating the instance if needed.
*
* @return A pointer to the instance of the StackTrace class.
*/
StackTrace* StackTrace::GetInstance()
{
if (!instanceFlag)
{
single = new StackTrace();
instanceFlag = true;
return single;
}
else
{
return single;
}
}
/**
* Prints the call stack to stdout.
*
* @param sourceStr
* The multibyte character string.
*/
void StackTrace::PrintStack()
{
// If PrintStackTrace() was called with no parameters, there is one more
// wrapper in the stack (this one) to skip.
int skipFrames = 3;
PrintStack(cout, skipFrames);
}
/**
* Prints the call stack to the given stream.
*
* @param out
* The already-opened stream where the call stack will be printed.
*
* @param skipFrames
* The number of frames to skip when capturing the call stack.
*/
void StackTrace::PrintStack(ostream& out, int skipFrames = 2)
{
const int maxCallers = 1024; // Not worried about size limits of OS's older than Windows 7.
void * callers_stack[maxCallers];
unsigned short frames;
SYMBOL_INFO * symbol;
HANDLE process;
DWORD displacement;
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
if (NULL == line)
{
return;
}
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
frames = CaptureStackBackTrace(skipFrames, maxCallers, callers_stack, NULL);
symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
if (NULL == symbol)
{
return;
}
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
out << uppercase;
const unsigned short MAX_CALLERS_SHOWN = 64;
frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN;
for (unsigned int i = 0; i < frames; i++)
{
DWORD64 address = (DWORD64)(callers_stack[i]);
SymFromAddr(process, address, 0, symbol);
if (SymGetLineFromAddr64(process, address, &displacement, line))
{
out << "*** " << dec << i << ": " << symbol->Name << " in " << line->FileName
<< ": line: " << line->LineNumber << ": address: 0x" << hex << symbol->Address << endl;
}
else
{
out << "*** SymGetLineFromAddr64 returned error code " << dec << GetLastError() << endl;
out << "*** at " << symbol->Name << " address 0x" << hex << symbol->Address << endl;
}
}
if (symbol) free(symbol);
if (line) free(line);
}
/**
* Print the call stack to stdout.
*/
void PrintStackTrace()
{
StackTrace::GetInstance()->PrintStack();
}
/**
* Print the call stack to the given stream.
*
* @param out
* The already-opened stream where the call stack will be printed.
*/
void PrintStackTrace(ostream& out)
{
StackTrace::GetInstance()->PrintStack(out);
}
}
#endif // DEBUG
#endif // _WIN32
答案 0 :(得分:0)
你不能指望行号完全可靠 - 甚至连堆栈跟踪本身都没有。一旦优化器完成了对代码的咀嚼,它将与您实际编写的内容完全不同,并且只有很多信息可以保存在调试信息中以将其映射回源。
你必须学会用一粒盐阅读堆栈痕迹。