Ich weiß, dass es dafür keine Standard-C-Funktion gibt. Ich habe mich gefragt, was die Techniken dazu unter Windows und * nix sind? (Windows XP ist derzeit mein wichtigstes Betriebssystem, um dies zu tun.)
Wie kann man in C einen Stack-Trace abrufen?
Kevin
sanxiin
glibc bietet backtrace()
Funktion.
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
-
glibc FTW … wieder. (Das ist ein weiterer Grund, warum ich die glibc als den absoluten Goldstandard betrachte, wenn es um die C-Programmierung geht (das und der dazugehörige Compiler).)
– Trevor Boyd Smith
9. September 2011 um 17:53 Uhr
-
Aber warte, es gibt noch mehr! Die backtrace()-Funktion stellt nur ein Array von void *-Zeigern bereit, die die Callstack-Funktionen darstellen. “Das ist nicht sehr nützlich. arg.” Keine Angst! glibc bietet eine Funktion, die alle void *-Adressen (die Callstack-Funktionsadressen) in für Menschen lesbare Zeichenfolgensymbole umwandelt.
char ** backtrace_symbols (void *const *buffer, int size)
– Trevor Boyd Smith
9. September 2011 um 17:55 Uhr
-
Vorbehalt: funktioniert nur für C-Funktionen, denke ich. @Trevor: Es sucht nur Syms nach Adresse in der ELF-Tabelle.
– Konrad Meyer
16. Oktober 2011 um 0:20 Uhr
-
Es gibt auch
void backtrace_symbols_fd(void *const *buffer, int size, int fd)
die die Ausgabe zum Beispiel direkt an stdout/err senden kann.– Wo
24. April 2012 um 13:47 Uhr
-
backtrace_symbols()
saugt. Es erfordert den Export aller Symbole und unterstützt keine DWARF-Symbole (Debugging). libbacktrace ist in vielen (den meisten) Fällen eine viel bessere Option.– Erwan Legrand
8. Februar 2018 um 11:18 Uhr
Tom
Es gibt backtrace()
und backtrace_symbols()
:
Aus der Manpage:
#include <execinfo.h>
#include <stdio.h>
...
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; ++i) {
printf("%s\n", strs[i]);
}
free(strs);
...
Eine Möglichkeit, dies auf bequemere/OOP-Weise zu verwenden, besteht darin, das Ergebnis von zu speichern backtrace_symbols()
in einem Ausnahmeklassenkonstruktor. Wenn Sie also diese Art von Ausnahme auslösen, haben Sie den Stack-Trace. Stellen Sie dann einfach eine Funktion zum Ausdrucken bereit. Zum Beispiel:
class MyException : public std::exception {
char ** strs;
MyException( const std::string & message ) {
int i, frames = backtrace(callstack, 128);
strs = backtrace_symbols(callstack, frames);
}
void printStackTrace() {
for (i = 0; i < frames; ++i) {
printf("%s\n", strs[i]);
}
free(strs);
}
};
…
try {
throw MyException("Oops!");
} catch ( MyException e ) {
e.printStackTrace();
}
Ta da!
Hinweis: Das Aktivieren von Optimierungs-Flags kann den resultierenden Stack-Trace ungenau machen. Idealerweise würde man diese Fähigkeit mit aktivierten Debug-Flags und deaktivierten Optimierungs-Flags verwenden.
-
@shuckc nur zum Konvertieren der Adresse in eine Symbolzeichenfolge, was bei Bedarf extern mit anderen Tools erfolgen kann.
– Woodrow Barlow
7. Juli 2016 um 19:57 Uhr
Überprüfen Sie für Windows die StackWalk64() API (auch auf 32-Bit-Windows). Für UNIX sollten Sie die native Methode des Betriebssystems verwenden oder auf backtrace() von glibc zurückgreifen, falls verfügbar.
Beachten Sie jedoch, dass es selten eine gute Idee ist, einen Stacktrace in nativem Code zu verwenden – nicht, weil es nicht möglich ist, sondern weil Sie normalerweise versuchen, das Falsche zu erreichen.
Die meiste Zeit versuchen die Leute, einen Stacktrace in, sagen wir, außergewöhnlichen Umständen zu bekommen, wie wenn eine Ausnahme abgefangen wird, ein Assert fehlschlägt oder – am schlimmsten und falschsten von allen – wenn Sie eine fatale “Ausnahme” oder ein Signal wie a erhalten Segmentierungsverletzung.
In Anbetracht des letzten Problems erfordern die meisten APIs, dass Sie Speicher explizit zuweisen oder dies intern tun. Wenn Sie dies in dem fragilen Zustand tun, in dem sich Ihr Programm möglicherweise derzeit befindet, kann dies die Dinge tatsächlich noch schlimmer machen. Der Absturzbericht (oder Coredump) spiegelt beispielsweise nicht die tatsächliche Ursache des Problems wider, sondern Ihren fehlgeschlagenen Versuch, es zu beheben).
Ich nehme an, Sie versuchen, diese fatale Fehlerbehandlung zu erreichen, da die meisten Leute dies zu versuchen scheinen, wenn es darum geht, einen Stacktrace zu erhalten. Wenn ja, würde ich mich auf den Debugger (während der Entwicklung) verlassen und den Prozess Coredump in der Produktion (oder Minidump unter Windows) lassen. Zusammen mit der richtigen Symbolverwaltung sollten Sie keine Probleme haben, die verursachende Anweisung nach dem Tod herauszufinden.
-
Sie haben Recht damit, dass es zerbrechlich ist, die Speicherzuweisung in einem Signal- oder Ausnahmehandler zu versuchen. Ein möglicher Ausweg besteht darin, beim Programmstart eine feste Menge an “Notfall” -Speicherplatz zuzuweisen oder einen statischen Puffer zu verwenden.
– j_random_hacker
19. Februar 2009 um 12:30 Uhr
-
Ein anderer Ausweg besteht darin, einen Coredump-Dienst zu erstellen, der unabhängig ausgeführt wird
– Kobor42
13. Juli 2012 um 7:59 Uhr
Für Windows, CaptureStackBackTrace()
ist auch eine Option, die weniger Vorbereitungscode auf der Benutzerseite erfordert als StackWalk64()
tut. (Außerdem hatte ich für ein ähnliches Szenario CaptureStackBackTrace()
funktionierte am Ende besser (zuverlässiger) als StackWalk64()
.)
Benutzer262802
Sie sollten die verwenden Bibliothek abspulen.
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (ctr >= 10) break;
a[ctr++] = ip;
}
Ihr Ansatz würde auch gut funktionieren, es sei denn, Sie rufen von einer gemeinsam genutzten Bibliothek aus an.
Du kannst den … benutzen addr2line
Befehl unter Linux, um die Quellfunktion / Zeilennummer des entsprechenden PCs zu erhalten.
-
“Quellfunktion/Zeilennummer”? Was ist, wenn die Verknüpfung für reduzierte Codegröße optimiert ist? Ich werde jedoch sagen, dass dies wie ein nützliches Projekt aussieht. Schade, dass es keine Möglichkeit gibt, die Register zu bekommen. Ich werde das auf jeden Fall prüfen. Wussten Sie, dass es absolut prozessorunabhängig ist? Funktioniert einfach auf allem, was einen C-Compiler hat?
– Mawg sagt, Monica wieder einzusetzen
31. Januar 2010 um 7:19 Uhr
-
Ok dieser Kommentar hat sich gelohnt, allein schon wegen der Erwähnung des hilfreichen addr2line-Befehls!
– Oger Psalm33
23. September 2010 um 14:43 Uhr
-
addr2line versagt für verschiebbaren Code auf Systemen mit ASLR (dh das meiste, was die Leute in den letzten zehn Jahren benutzt haben).
– Erwan Legrand
8. Februar 2018 um 11:13 Uhr
Nils Pipenbrink
Es gibt keine plattformunabhängige Möglichkeit, dies zu tun.
Am ehesten können Sie den Code ohne Optimierungen ausführen. Auf diese Weise können Sie an den Prozess anhängen (mithilfe des visuellen C++-Debuggers oder GDB) und erhalten einen brauchbaren Stack-Trace.
-
“Quellfunktion/Zeilennummer”? Was ist, wenn die Verknüpfung für reduzierte Codegröße optimiert ist? Ich werde jedoch sagen, dass dies wie ein nützliches Projekt aussieht. Schade, dass es keine Möglichkeit gibt, die Register zu bekommen. Ich werde das auf jeden Fall prüfen. Wussten Sie, dass es absolut prozessorunabhängig ist? Funktioniert einfach auf allem, was einen C-Compiler hat?
– Mawg sagt, Monica wieder einzusetzen
31. Januar 2010 um 7:19 Uhr
-
Ok dieser Kommentar hat sich gelohnt, allein schon wegen der Erwähnung des hilfreichen addr2line-Befehls!
– Oger Psalm33
23. September 2010 um 14:43 Uhr
-
addr2line versagt für verschiebbaren Code auf Systemen mit ASLR (dh das meiste, was die Leute in den letzten zehn Jahren benutzt haben).
– Erwan Legrand
8. Februar 2018 um 11:13 Uhr
Peter Mortensen
Solaris hat die Stapel Befehl, der auch in Linux kopiert wurde.
-
Nützlich, aber nicht wirklich C (es ist ein externes Dienstprogramm).
– vergänglich
31. Januar 2010 um 6:48 Uhr
-
auch aus der Beschreibung (Abschnitt: Einschränkungen) “: pstack funktioniert derzeit nur unter Linux, nur auf einem x86-Computer, auf dem 32-Bit-ELF-Binärdateien ausgeführt werden (64-Bit wird nicht unterstützt)”
– Ciro Costa
31. Oktober 2015 um 19:32 Uhr
Ich habe mehrere Methoden ausführlich getestet unter: stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c/…
– Ciro Santilli OurBigBook.com
25. Januar 2019 um 12:20 Uhr