Der folgende Editor bringt Ihnen einen Artikel darüber, wie Sie die aktuellen Stack-Informationen unter Linux und Windows erhalten. Der Herausgeber findet es ziemlich gut, deshalb teile ich es jetzt mit Ihnen und gebe es als Referenz. Folgen wir dem Editor und werfen wir einen Blick darauf
Beim Schreiben stabiler und zuverlässiger Softwaredienste wird er häufig zur Ausgabe von Stack-Informationen verwendet, damit Benutzer/Entwickler genaue Betriebsinformationen erhalten können. Wird häufig bei der Protokollausgabe, der Fehlerberichterstattung und der Anomalieerkennung verwendet.
Es gibt eine relativ einfache Funktion zum Abrufen von Stack-Informationen unter Linux:
#include <stdio.h> #include <execinfo.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> void handler(int sig) { void *array[5]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 5); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); char** msgs = backtrace_symbols(array, size); for(int i=1;i<size && msgs[i];++i) printf("[%d] %s\n", i, msgs[i]); exit(1); } void baz() { int *foo = (int*)-1; // make a bad pointer printf("%d\n", *foo); // causes segfault } void bar() { baz(); } void foo() { bar(); } int main(int argc, char **argv) { signal(SIGSEGV, handler); // install our handler foo(); // this will call foo, bar, and baz. baz segfaults. }
The Der obige Code stammt von Er ist gegenüber dem Referenzstapel leicht modifiziertÜberlauf. Den Kern bilden die beiden Funktionen backtrace und backtrace_symbols.
Es wird empfohlen, den Open-Source-Code StackWalker unter Windows zu verwenden, der X86, AMD64 und IA64 unterstützt.
Wenn Sie den einfachsten Code benötigen, ist der folgende Code, den ich extrahiert habe, offensichtlich komplizierter als Linux. (Viele Funktionen von Win sind komplizierter zu implementieren, und natürlich gibt es viele Funktionen, die viel einfacher zu implementieren sind als Linux.)
Ich werde später einige Erklärungen geben.
#include "stdafx.h" #include <Windows.h> #include <iostream> #include <DbgHelp.h> #include <TlHelp32.h> using namespace std; HANDLE ph; void baz() { int* v = 0; *v = 0; } void bar() { baz(); } void foo(){ try { bar(); } except(EXCEPTION_EXECUTE_HANDLER) { auto sire = SymInitialize(ph, 0, FALSE); sire = SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS); CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&ctx); STACKFRAME64 sf = { 0 }; #ifdef _M_IX86 // ignore IA64 auto imageType = IMAGE_FILE_MACHINE_I386; sf.AddrPC.Offset = ctx.Eip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat; #elif _M_X64 auto imageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = ctx.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = ctx.Rsp; sf.AddrFrame.Mode = AddrModeFlat; sf.AddrStack.Offset = ctx.Rsp; sf.AddrStack.Mode = AddrModeFlat; #endif MODULEENTRY32 me; auto snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); auto info = Module32First(snap, &me); while (info) { auto dw = SymLoadModule64(ph, 0, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr, me.modBaseSize); if (!Module32Next(snap, &me))break; } CloseHandle(snap); auto thread = GetCurrentThread(); PIMAGEHLP_SYMBOL64 sym = (IMAGEHLP_SYMBOL64 *)malloc(sizeof(IMAGEHLP_SYMBOL64) + 100); if (!sym) return; memset(sym, 0, sizeof(IMAGEHLP_SYMBOL64) + 100); sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); sym->MaxNameLength = 100; IMAGEHLP_LINE64 line = { 0 }; line.SizeOfStruct = sizeof(line); for (;;) { auto result = StackWalk(imageType, ph, thread, &sf, &ctx, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0); if (result) { DWORD64 offset = 0; DWORD offset_for_line = 0; CHAR und_fullname[100]; if (sf.AddrPC.Offset != 0) { if (SymGetSymFromAddr64(ph, sf.AddrPC.Offset, &offset, sym)) { UnDecorateSymbolName(sym->Name, und_fullname, 100, UNDNAME_COMPLETE); cout << und_fullname; } if (SymGetLineFromAddr64(ph, sf.AddrPC.Offset, &offset_for_line, &line)) { cout << " " << line.FileName << "(" << line.LineNumber << ")"; } cout << endl; } } else break; } SymCleanup(ph); } } int main() { ph = GetCurrentProcess(); foo(); return 0; }
Bitte verlinken Sie dbghelp.lib zur Kompilierung
Der Kern ist StackWalk und SymGetSymFromAddr64, SymGetLineFromAddr64.
StackWalk wird verwendet, um die nächste Schicht des Stapels abzurufen.
SymGetSymFromAddr64 wird verwendet, um den aktuellen Funktionsnamen abzurufen.
SymGetLineFromAddr64 wird verwendet, um die Datei- und Zeilennummer der Funktion abzurufen.
Damit diese drei Funktionen ordnungsgemäß funktionieren, ist es notwendig, die symbolbezogenen Funktionen (SymInitialize) zu initialisieren, die aktuelle Thread-Beschreibungstabelle (RtlCaptureContext) abzurufen und die verwendeten zu laden Modul (SymLoadModule64).
Die beiden Header-Dateien
Nachdem der obige Code ausgeführt wurde, werden Stapelinformationen auf der Konsole ausgegeben.
Das obige ist der detaillierte Inhalt vonTeilen Sie ein Beispiel für den Erhalt aktueller Stack-Informationen unter Linux und Windows. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!