Я разметил следующий код:
#include "stdafx.h"
#include <process.h>
#include <iostream>
#include <Windows.h>
#include "dbghelp.h"
using namespace std;
#define TRACE_MAX_STACK_FRAMES 1024
#define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
int printStackTrace()
{
void *stack[TRACE_MAX_STACK_FRAMES];
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
WORD numberOfFrames = CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL);
SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
DWORD displacement;
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
for (int i = 0; i < numberOfFrames; i++)
{
DWORD64 address = (DWORD64)(stack[i]);
SymFromAddr(process, address, NULL, symbol);
if (SymGetLineFromAddr64(process, address, &displacement, line))
{
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
}
else
{
printf("\tSymGetLineFromAddr64 returned error code %lu.\n", GetLastError());
printf("\tat %s, address 0x%0X.\n", symbol->Name, symbol->Address);
}
}
return 0;
}
void function2()
{
int a = 0;
int b = 0;
throw new exception;
}
void function1()
{
int a = 0;
function2();
}
void function0()
{
function1();
}
static void threadFunction(void *param)
{
try
{
function0();
}
catch (...)
{
printStackTrace();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
_beginthread(threadFunction, 0, NULL);
printf("Press any key to exit.\n");
cin.get();
return 0;
}
Что он делает, так это регистрирует трассировку стека, но проблема в том, что регистрируемая трассировка стека не дает мне нужных мне номеров строк. Я хочу, чтобы он регистрировал номера строк мест, вызвавших исключение, в стеке вызовов и вверх, вроде как в C#. Но что он на самом деле делает прямо сейчас, так это выводит следующее:
at printStackTrace in c:\users\<yourusername>\documents\visual studio 2013\pr
ojects\stacktracing\stacktracing\stacktracing.cpp: line: 17: address: 0x10485C0
at threadFunction in c:\users\<yourusername>\documents\visual studio 2013\pro
jects\stacktracing\stacktracing\stacktracing.cpp: line: 68: address: 0x10457C0
SymGetLineFromAddr64 returned error code 487.
at beginthread, address 0xF9431E0.
SymGetLineFromAddr64 returned error code 487.
at endthread, address 0xF9433E0.
SymGetLineFromAddr64 returned error code 487.
at BaseThreadInitThunk, address 0x7590494F.
SymGetLineFromAddr64 returned error code 487.
at RtlInitializeExceptionChain, address 0x7713986A.
SymGetLineFromAddr64 returned error code 487.
at RtlInitializeExceptionChain, address 0x7713986A.
Проблема, с которой я снова сталкиваюсь, заключается в том, что line: 68
в этой трассировке соответствует строке, которая вызывает метод printStackTrace();
, в то время как я хотел бы, чтобы она дала мне строку номер 45, которая соответствует строке, которая выдает исключение: throw new exception;
, а затем продолжайте дальше вверх по стеку.
Как я могу добиться такого поведения и проникнуть в этот поток именно тогда, когда он выдает это исключение, чтобы получить правильную трассировку стека?
PS Приведенный выше код был запущен для консольного приложения с использованием MSVC++ с включенным юникодом на компьютере с Windows 8.1 x64, при этом приложение выполнялось как приложение Win32 в режиме отладки.