Heim  >  Artikel  >  Betrieb und Instandhaltung  >  Teilen Sie ein Beispiel für den Erhalt aktueller Stack-Informationen unter Linux und Windows

Teilen Sie ein Beispiel für den Erhalt aktueller Stack-Informationen unter Linux und Windows

零下一度
零下一度Original
2017-06-29 15:35:471925Durchsuche

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*&#39;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 f09cc4b7bed6d9cc68d3d0b1b9d93304 715cd25a5675b4112aa1e30746b0ebb2

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn