L'éditeur suivant vous proposera un article sur la façon d'obtenir les informations actuelles sur la pile sous Linux et Windows. L'éditeur le trouve plutôt bon, je vais donc le partager avec vous maintenant et le donner comme référence pour tout le monde. Suivons l'éditeur et jetons un coup d'œil
Lors de l'écriture de services logiciels stables et fiables, il est souvent utilisé pour générer des informations sur la pile afin que les utilisateurs/développeurs puissent obtenir des informations d'exécution précises. Couramment utilisé dans la sortie de journaux, le rapport d'erreurs et la détection d'anomalies.
Il existe une fonction relativement simple pour obtenir des informations sur la pile sous 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. }
La le code ci-dessus provient de Il est légèrement modifié par rapport à la pile de référenceoverflow. Le cœur est constitué des deux fonctions backtrace et backtrace_symbols.
Il est recommandé d'utiliser le code open source StackWalker sous Windows, qui prend en charge X86, AMD64 et IA64.
Si vous avez besoin du code le plus simple, voici le code que j'ai extrait, qui est évidemment plus compliqué que Linux. (De nombreuses fonctions de Win sont plus compliquées à mettre en œuvre, et bien sûr il existe de nombreuses fonctions qui sont beaucoup plus simples à mettre en œuvre que Linux.)
Je donnerai quelques explications plus tard.
#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; }
Veuillez lier dbghelp.lib pour la compilation
Le noyau est StackWalk et SymGetSymFromAddr64, SymGetLineFromAddr64.
StackWalk est utilisé pour obtenir la couche suivante de la pile.
SymGetSymFromAddr64 est utilisé pour obtenir le nom de la fonction actuelle.
SymGetLineFromAddr64 est utilisé pour obtenir le fichier et le numéro de ligne de la fonction.
Pour que ces trois fonctions fonctionnent correctement, il est nécessaire d'initialiser les fonctions liées aux symboles (SymInitialize), d'obtenir la table de description du thread actuel (RtlCaptureContext), et de charger le fichier utilisé (SymLoadModule64).
Les deux fichiers d'en-tête
Une fois le code ci-dessus exécuté, les informations sur la pile seront affichées sur la console.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!