Wie können Sie CaptureStackBackTrace zur Erfassung der Ausnahme-stack, nicht die Aufruf-stack?
Markierte ich den folgenden code:
#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;
}
Was es tut, ist, meldet es einen stack-trace, aber das problem ist, dass der stack-trace protokolliert er gibt mir nicht die Zeilennummern, die ich will. Ich will, dass er log die Zeilen-Nummern der Plätze, die die Ausnahme ausgelöst hat, und auf den call-stack, der Art wie in C#. Aber was es tatsächlich tut, ist es gibt die folgenden:
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.
Das problem, das ich mich vor, wieder, ist, dass line: 68
in diese Spur bezieht sich auf die Zeile, die die Methode aufruft printStackTrace();
, während ich es möchte, um mir die Linie Nummer 45, das entspricht der Linie, die die Ausnahme ausgelöst: throw new exception;
und dann weiter oben im Stapel.
Wie kann ich erreichen, diese Art von Verhalten und brechen in diesem thread genau dann, wenn es wirft diese Ausnahme, um eine richtige stack-trace?
PS Der obige code ausgeführt wurde, für eine Konsolenanwendung, die mit MSVC++ mit unicode-fähig unter Windows 8.1 x64-Maschine, mit der die Anwendung ausgeführt wird, wie eine Win32-Anwendung im Debug-Modus.
- Müssen Sie natürlich überspringen Sie die stack-frames, die Teil Ihrer logging-code. Einfach zählen Sie ab, __declspec(noinline) ist ratsam.
- Aber dann wäre es einfach überspringen printStackTrace und threadFunction...und ließ mich mit beginthread, die, denke ich es nicht haben Zugriff auf die von der Kind-thread...siehe mein dilemma? Ich meine, nur um zu klären, Sie deuten die übergabe in eine übersprungene frame-Menge in den Ruf zu CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL); wie CaptureStackBackTrace(2, TRACE_MAX_STACK_FRAMES, stack, NULL); richtig? Seine immer noch nicht, was ich nach 😛
- Sagen wir es so, ich will meinen stack trace zu gehören function2, function1, und function0. Vor allem function2 aber, und die Linie, an der die Ausnahme geworfen wird, an.
- Das ist nicht möglich, wenn Sie verwenden catch(...), der Stapel ist schon abgewickelt und die Ausnahme abgetan. Müssen Sie SetUnhandledExceptionFilter() zum auffangen der nicht behandelte Ausnahme.
- Es muss einen Weg, denn selbst, indem Sie eine vektorielle Ausnahme-handler ist es immer noch nicht mir der exakte Linie. Ich arbeite für ein Unternehmen, das keine stack-Trace in der Produktion (LOL), und ich muss hinzufügen, dass es in (offensichtlich die Leute zu faul sind es selbst zu tun, so dass alle die Arbeit bekommt verpfändet Weg für mich). Also ich bin auf der Suche nach einem Weg, um meine eigene stack-Trace-Bibliothek. Etwas kleines, einfach alle Ausnahmen abfangen und werfen einen stack-trace. Was empfehlen Sie? Und...warum in Gottes Namen ist es so schwer zu tun, dies in C++?!
- PS ich will nicht verwenden StackWalker. Ich habe es nicht geschrieben, und soweit ich sagen kann, das ist fast das gleiche in Bezug auf die Funktionalität, die ich will, die einzige Sache ist, dass ich muss einen Weg finden, zu brechen, in einen thread, wenn eine Ausnahme geworfen wird, und der trace von dort; nicht nach der Ausnahme und nicht in jedem exception-handler / Verbraucher, denn das scheint nicht zu funktionieren.
- stackoverflow.com/questions/19656946/...
- Ich hätte zu verwenden, __try und __except und Holen Sie sich die Spur aus dem Kontext, dass...wie stack walker hat mit StackWalk64...ich wusste wirklich nicht wollen, um darüber zu gehen, wie dies seit der __try und __except funktioniert nicht, wenn gewickelt anderen try-catch-Blöcke...
- Spin-Off, mehr Probleme...solche Kopfschmerzen. stackoverflow.com/questions/22481126/...
- Am Ende, ich hatte zu schmücken alle Funktionen mit __declspec(noinline). Es hat funktioniert, und ich bekam eine neue Verständnis von inline-Methoden. Ich denke, wenn ich versuchte zunächst, ich habe nicht schmücken alle meine Methoden mit __declspec(noinline) - Richtlinie.
- Tut mir Leid für die nicht die Anwendung Ihrer Konzepte vollständig, @HansPassant. Du bist verdammt gut in dem was Sie tun.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Unter windows, nicht behandelte C++ - Ausnahme generiert automatisch SEH Ausnahme. SEH __außer block ermöglicht das anbringen eines filters, der akzeptiert _EXCEPTION_POINTERS - Struktur als parameter enthält den Zeiger auf den Prozessor-Kontext aufnehmen im moment exception geworfen wurde. Die Weitergabe dieser Zeiger StackWalk64 Funktion gibt den stack-trace in dem moment Ausnahme. So, dieses problem kann gelöst werden durch die Verwendung von SEH-Stil Ausnahmebehandlung anstelle von C++ - Stil.
Beispiel-code:
Beispiel der Ausgabe (die ersten zwei Einträge sind Lärm, aber der rest korrekt widerspiegelt Funktionen verursacht, dass die Ausnahme):
Andere option ist das erstellen eigener exception-Klasse, die fängt Kontext im Konstruktor und verwenden Sie es (oder abgeleiteten Klassen) Ausnahmen:
Wenn Sie wollte den Stapel backtrace von dem Punkt, wo der code ist, wirf eine Ausnahme, Sie müssen erfassen der stack backtrace im ctor des exception-Objekts und speichern Sie Sie in die exception-Objekt. Also das Teil aufrufen CaptureStackBackTrace() verschoben werden soll, an den Konstruktor des exception-Objekts, die sollten auch Methoden, um es zu Holen, entweder als Vektor von Adressen oder als ein Vektor, der Symbole. Das ist genau wie Throwable in Java Exception in C# arbeiten.
Endlich, bitte nicht schreiben:
in C++ wie in C# oder Java. Dies ist ein ausgezeichneter Weg, um beide zu produzieren, memory-leaks und nicht fangen der Ausnahmen nach Art (als Sie sind, werfen Zeiger auf diese Typen). Verwenden Sie lieber:
Ich bin mir bewusst, dass dies ist eine alte Frage, aber die Leute (einschließlich mich) sind noch zu finden.