Dieser Artikel wurde maschinell übersetzt.

Anwendungsinstrumentierung

Anwendungsanalyse mit Pin

Hadi Brais

Programm-Analyse ist ein grundlegender Schritt im Entwicklungsprozess. Es geht um die Analyse eines Programmes zu erkennen, wie es zur Laufzeit Verhalten wird. Es gibt zwei Arten von Programm-Analyse: statische und dynamische.

Sie würde eine statische Analyse durchführen, ohne das Zielprogramm, in der Regel während der Quelle Code-Kompilierung ausgeführt. Visual Studio bietet eine Reihe von hervorragende Werkzeuge für statische Analyse. Die meisten modernen Compiler ausführen automatisch statische Analyse, um sicherzustellen, dass das Programm die Sprache semantischen Regeln ehrt und den Code zu optimieren. Obwohl statische Analyse nicht immer präzise, ist sein Hauptvorteil aufzeigen potenzieller Probleme mit Code vor dem Ausführen, Verringerung der Zahl der Debugsitzungen erhalten und wertvolle Zeit gespart.

Sie würde eine dynamische Programm-Analyse durchführen, während der Ausführung des Zielprogramms. Wenn das Programm beendet wird, produziert der dynamische Analyzer ein Profil mit verhaltensbezogene Informationen. In der Microsoft .NET Framework, der just-in-Time (JIT) Compiler führt dynamischen Analyse zur Laufzeit in den Code zu optimieren und stellt sicher, das nicht alles was das Schriftsystem entspricht.

Der Hauptvorteil der statischen Analyse über dynamische Analyse ist, dass es garantiert 100 Prozent Codeabdeckung. Um solche hohen Codeabdeckung mit dynamischen Analyse zu gewährleisten, müssen Sie in der Regel das Programm mehrmals ausführen, jeweils mit unterschiedlichen Eingang also die Analyse nimmt unterschiedliche Wege. Der Hauptvorteil der dynamischen Analyse ist, dass es detaillierte und genaue Informationen erzeugen kann. Beim entwickeln und .NET Anwendung bzw. sichere C++-Anwendung ausführen, werden beide Arten der Analyse automatisch durchgeführt werden, unter der Haube zu gewährleisten, dass der Code die Regeln des Rahmens einhält.

Der Schwerpunkt in diesem Artikel werden dynamische Programm-Analyse, auch bekannt als Profilerstellung. Es gibt viele Möglichkeiten, ein Programm, wie die Verwendung von Framework-Ereignissen, OS-Haken und dynamische Instrumentierung zu profilieren. Visual Studio einen Profilerstellung Rahmen bietet, sind seine dynamische Instrumentierung-Kapazitäten derzeit begrenzt. Für alle, aber die einfachsten dynamische Verwaltungsinstrumentation Szenarien benötigen Sie einen erweiterten Rahmen. Das ist, wo Pin ins Spiel kommt.

Was ist die Pin?

PIN ist eine dynamische binäre Instrumentierung-Framework, entwickelt von Intel Corp. Das können Sie Programm-Analyse-Tools namens Pintools für Windows- und Linux-Plattformen zu erstellen. Diese Tools können Sie überwachen und erfassen das Verhalten eines Programms, während er ausgeführt wird. Dann können Sie viele wichtige Aspekte des Programms z.B. seine Richtigkeit, Performance und Sicherheit effektiv auswerten.

Sie können den Pin-Rahmen integrieren, mit Microsoft Visual Studio einfach erstellen und Debuggen von Pintools. In diesem Artikel werde ich zeigen, wie Pin mit Visual Studio zu entwickeln und zu debuggen eine einfache, aber nützliche Pintool. Die Pintool erkennt kritische Speicherprobleme wie Arbeitsspeicherbereiche und doppelte Freigabe reservierten Arbeitsspeicher in ein C/C++-Programm.

Zum besseren Verständnis die Natur des Pin sehen Sie sich die komplette Definition Begriff von Begriff:

  • Ein Framework ist eine Sammlung von Code, auf dem Sie ein Programm schreiben. Es umfasst in der Regel eine Laufzeitkomponente, die teilweise die Ausführung des Programms (z. B. starten und beenden steuert).
  • Die Instrumentation ist der Prozess der Analyse eines Programms durch Hinzufügen oder Ändern von Code – oder beides.
  • Binary zeigt den Code hinzugefügt wird oder Maschinencode in binärer Form ist geändert.
  • Dynamisch bedeutet, dass die Instrumentierung-Prozesse zur Laufzeit ausgeführt werden, während das Programm ausgeführt wird.

Der komplette Satz "dynamische binäre Instrumentation" ist ein Schluck, so dass Menschen in der Regel die Abkürzung DBI verwenden. PIN ist ein DBI-Rahmen.

Pin können Sie unter Windows (IA32 und Intel64), Linux (IA32 und Intel64), Mac OS X (IA32 und Intel64) und Android (IA32). PIN unterstützt auch den Intel-Xeon-Phi-Mikroprozessor für Supercomputer. Es unterstützt nicht nur Windows, sondern auch nahtlos mit Visual Studio. Sie können Pintools in Visual Studio schreiben und Debuggen sie mit dem Visual Studio -Debugger. Sie können sogar entwickeln, Debuggen Erweiterungen für Pin von Visual Studionutzen.

Erste Schritte mit Pin

Obwohl Pin proprietäre Software ist, können Sie herunterladen und verwenden Sie es für nicht-kommerzielle Nutzung kostenlos. PIN unterstützen nicht noch Visual Studio 2013, so dass ich Visual Studio 2012 einsetzen werde. Wenn Sie beide Visual Studio 2012 und 2013 installiert haben, können Sie erstellen und Visual Studio 2012 Projekte ab 2013 öffnen und verwenden C++-Bibliotheken und Tools von Visual Studio 2012 ab 2013.

Download Pin von intel.ly/1ysiBs4. Neben der Dokumentation und die Binärdateien enthält Pin Quellcode für eine große Sammlung der Probe Pintools Sie in Source-Tools finden. Öffnen Sie aus dem MyPinTool-Ordner die MyPinTool-Lösung in Visual Studio.

Überprüfen Sie die Projekteigenschaften im Detail die richtige Pintool-Konfiguration ermitteln. Alle Pintools sind DLL-Dateien. Daher sollte das Projekt Konfigurationstyp in dynamische Bibliothek (.dll) festgelegt werden. Sie haben auch alle Header, Dateien, Bibliotheken und eine Reihe von Präprozessorsymbole geforderten Pin-Header-Dateien angeben. Legen Sie den Einstiegspunkt auf Ptrace_DllMainCRTStartup % 4012 C-Laufzeit richtig initialisiert werden. Geben Sie den /export:main-Schalter, um die main-Funktion importieren.

Können Sie entweder ordnungsgemäß konfigurierte MyPinTool Projekt verwenden oder ein neues Projekt erstellen und selbst konfigurieren. Sie können auch ein Eigenschaftenblatt, enthält die erforderlichen Konfigurationsdetails erstellen und importieren, die in das Pintool-Projekt.

PIN-Granularität

PIN können Sie Code in bestimmten Orten in das Programm einfügen du bist Instrumentieren — in der Regel nur vor oder nach der Ausführung eine bestimmte Anweisung oder Funktion. Beispielsweise sollten Sie Aufzeichnen aller dynamischen Speicherzuordnungen, um Speicherverluste zu erkennen.

Es gibt drei Ebenen der Granularität auf Pin: Routine, Unterweisung und Bild. PIN hat auch eine weitere Ebene nicht so offensichtliche — Trace Granularität. Eine Spur ist eine geradlinige Anweisungsfolge mit genau einem Eintrag. Sie endet in der Regel mit einer bedingungslosen Zweig. Eine Ablaufverfolgung kann mehrere Ausspeisepunkte enthalten, solange sie bedingte sind. Beispiele für unbedingte Verzweigungen Aufrufe, Retouren und unbedingte Sprünge. Beachten Sie, dass eine Spur genau einen Eintrag aufweist. Wenn Pin eine Verzweigung zu einer Position in einer Ablaufverfolgung erkannt, wird dieser Ablaufverfolgung an dieser Stelle zu beenden und starten Sie eine neue Ablaufverfolgung.

PIN bietet diese Instrumentierung Granularities um Ihnen zu helfen den geeigneten Kompromiss zwischen Leistung und Detaillierungsgrad wählen. Instrumentierung bei der "Instruction" Ebene kann schwere Leistungsabfall führen, da gäbe es Milliarden von Anweisungen. Auf der anderen Seite Instrumentieren Ebene Funktion möglicherweise zu allgemein und, daher könnte es die Komplexität des Codes Analyse zu erhöhen. Spuren helfen Sie Instrument ohne Kompromisse bei Leistung oder Detail.

Schreiben einer Pintool

Jetzt ist es Zeit, eine nützliche Pintool zu schreiben. In diesem Beispiel Pintool dient, Gedächtnisstörungen Zuordnungseinheiten, die C/C++-Programme zu erkennen. Die einfache Pintool werde ich schreiben kann ein vorhandenes Programm diagnostizieren, ohne den Quellcode ändern oder neu kompilieren, da Pin seine Arbeit zur Laufzeit führt. Hier sind die Probleme, die die Pintool erkennt:

  • Memory-Leaks: Speicher reserviert, aber nicht freigegeben.
  • Doppelte Freigabe: Speicher freigegeben mehr als einmal.
  • Nicht zugeordneter Speicher freigibt: Freigeben von Speicher, die noch nicht zugewiesen (z. B. das Aufrufen von freien und übergeben NULL darauf).

Um den Code zu vereinfachen, werde ich nehme Folgendes an:

  • Die Hauptfunktion des Programms heißt Haupt. Andere Varianten halte ich wird nicht.
  • Die einzigen Funktionen, die zuordnen und Freigeben von Speicher sind neue/Malloc und Löschen/frei, beziehungsweise. Ich wird nicht Calloc und Realloc, angenommen.
  • Das Programm besteht aus einer ausführbaren Datei.

Sobald Sie den Code kennen, können Sie es ändern und bilden das Werkzeug viel praktischer.

Definieren Sie die Lösung

Um diese Probleme mit dem Speicher zu erkennen, muss die Pintool Aufrufe der Reservierung und Freigabe-Funktionen überwachen. Da der new-Operator intern Malloc ruft und der Delete-Operator intern frei ruft, kann ich nur die Aufrufe zu überwachen und frei.

Sobald das Programm Malloc aufruft, werde ich die zurückgegebene Adresse (entweder NULL oder die Adresse der reservierten Speicherbereich) aufnehmen. Sobald es freie aufruft, werde ich die Adresse des Speichers mit meiner Aufzeichnungen freigegeben wird übereinstimmen. Wenn es reserviert aber nicht freigegeben wurde, werde ich es markieren, wie befreit. Jedoch wenn es reserviert wurde und befreit hat, versucht es wieder frei wäre das ein Problem anzeigt. Schließlich, wenn es keine Aufzeichnungen, die der Speicher freigegeben wird zugewiesen wurde gibt, ein Versuch, nicht zugeordneter Speicher frei wäre. Wenn das Programm beendet wird, werde ich wieder Datensätze für diese Speicherbereiche überprüfen, die zugeteilt wurden aber nicht freigegeben, um Speicherverluste zu erkennen.

Wählen Sie eine Granularität

PIN kann ein Programm an vier Granularities instrument: Bild, Routine, Trace und Unterricht. Welches ist am besten für diese Pintool? Während der Granularities die Stelle unterlassen wird, muss ich das zu wählen, das die geringste Leistung Aufwand entsteht. In diesem Fall wäre die Bild-Granularität der beste. Sobald das Bild des Programms geladen ist, kann die Pintool finden die Malloc und free-Code innerhalb des Bildes und fügen Sie den Analysecode. Auf diese Weise Instrumentation overhead wird sein pro-anstatt der für zumieten, pro-Anleitung.

Um die Pin-API verwenden, muss ich den PIN-Code enthalten.H-Headerdatei im Code. Die Pintool wird schriftlich die Ergebnisse in eine Datei, also muss ich auch die Fstream-Header-Datei aufnehmen. Ich verwende die STL-Kartentyp zu verfolgen den Speicher reserviert und freigegeben wird. Diese Art ist in der Karte-Header-Datei definiert. Ich verwende auch den Stream Cerr, informative Meldungen zeigen:

#include "pin.H"
#include <iostream>
#include <fstream>
#include <map>

Ich werden drei Symbole, um die Namen der Funktionen Malloc, frei und wichtigsten halten definieren:

#define MALLOC "malloc"
#define FREE "free"
#define MAIN "main"

Dies sind die erforderlichen globalen Variablen:

bool Record = false;
map<ADDRINT, bool> MallocMap;
ofstream OutFile;
string ProgramImage;
KNOB<string> OutFileName(KNOB_MODE_WRITEONCE, 
  "Pintool", "o", "memtrace.txt",
  "Memory trace file name");

Die Record-Variable gibt an, ob ich innerhalb der main-Funktion bin. Die MallocMap-Variable enthält den Status der einzelnen reservierten Speicherbereich. Der ADDRINT Typ wird von Pin definiert.H und stellt eine Speicheradresse. Wenn ein Speicher zugeordnete Wert TRUE vorgenommen, hat es wurde aufgehoben.

Die ProgramImage-Variable enthält den Namen des Bildes Programm. Die letzte Variable ist ein Vollidiot. Dies entspricht eine Befehlszeilenoption für die Pintool. PIN erleichtert die Schalter für ein Pintool zu definieren. Definieren Sie für jeden Switch KNOB-Variablen. Die Vorlage Type Parameter String stellt den Typ der Werte, die der Schalter stattfinden wird. Hier können der Regler Sie den Namen der Ausgabedatei von Pintool über dem "o"-Schalter angeben. Der Standardwert ist memtrace.txt.

Als nächstes habe ich die Analyseroutinen ausgeführt an bestimmten Punkten in der Codesequenz zu definieren. Ich brauche eine Analysefunktion im Sinne Abbildung 1, aufgerufen, nachdem Malloc kehrt zurück, um die Adresse des reservierten Speicher aufzuzeichnen. Diese Funktion nimmt die Adresse von Malloc zurückgegeben und gibt nichts zurück.

Abbildung 1 die RecordMalloc Analyse-Routine jedes Mal aufgerufen, Malloc gibt

VOID RecordMalloc(ADDRINT addr) {
  if (!Record) return;
  if (addr == NULL) {
    cerr << "Heap full!";
    return;
  }
  map<ADDRINT, bool>::iterator it = MallocMap.find(addr);
  if (it != MallocMap.end()) {
    if (it->second) {
      // Allocating a previously allocated and freed memory.
      it->second = false;
    }
    else {
      // Malloc should not allocate memory that has
      // already been allocated but not freed.
      cerr << "Imposible!" << endl;
    }
  }
  else {
    // First time allocating at this address.
    MallocMap.insert(pair<ADDRINT, bool>(addr, false));
  }
}

Jedes Mal, wenn Malloc aufgerufen wird, wird diese Funktion aufgerufen werden. Jedoch interessiert mich nur in der Erinnerung ist es Bestandteil des instrumentierten Programms. Also werde ich die Adresse aufnehmen, nur wenn Datensatz wahr ist. Wenn die Adresse NULL ist, werde ich es einfach ignorieren.

Dann die Funktion bestimmt, ob die Adresse bereits im MallocMap ist. Wenn es ist, dann es muss zuvor reserviert und wurden freigegeben und daher wird jetzt wiederverwendet wird. Wenn die Adresse nicht in MallocMap, werde ich sie mit FALSE als Einfügen der Wert gibt an, dass es noch nicht freigegeben wurde.

Ich werde in einer weiteren Analyse definieren Routine, im Abbildung 2, die ich habe nur angerufen bevor gratis aufgerufen wird, um die Adresse des freizugebenden Speicherbereich aufzuzeichnen. Verwenden MallocMap, kann ich leicht erkennen, wenn der Speicher freigegeben wird, bereits befreit worden hat oder es hat nicht zugewiesen worden.

Abbildung 2 die RecordFree Analyse-Routine

VOID RecordFree(ADDRINT addr) {
  if (!Record) return;
  map<ADDRINT, bool>::iterator it = MallocMap.find(addr);
  if (it != MallocMap.end()) {
    if (it->second) {
      // Double freeing.
      OutFile << "Object at address " << hex << addr << "
        has been freed more than once."  << endl;
    }
    else {
      it->second = true; // Mark as freed.
    }
  }
  else {
    // Freeing unallocated memory.
    OutFile << "Freeing unallocated memory at " 
      << hex << addr << "." << endl;
  }
}

Als nächstes werde ich brauche zwei weitere Analyseroutinen markieren die Ausführung und der Hauptfunktion zurückkehren:

 

VOID RecordMainBegin() {
  Record = true;
}
VOID RecordMainEnd() {
  Record = false;
}

Analyseroutinen bestimmen den Code um das Programm zu instrumentieren. Ich habe auch Pin sagen wann diese Routinen ausführen. Das ist der Zweck der Instrumentierung-Routinen. Ich eine Instrumentierung-Routine wie in gezeigt definiert Abbildung 3. Diese Routine wird aufgerufen, jedes Mal, wenn ein Bild in den laufenden Prozess geladen wird. Wenn das Programmabbild geladen ist, erkläre ich Pin die Analyseroutinen an den entsprechenden Stellen eingefügt.

Abbildung 3 die Bild-Instrumentation-Routine

VOID Image(IMG img, VOID *v) {
  if (IMG_Name(img) == ProgramImage) {
    RTN mallocRtn = RTN_FindByName(img, MALLOC);
    if (mallocRtn.is_valid()) {
      RTN_Open(mallocRtn);
      RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)RecordMalloc,
        IARG_FUNCRET_EXITPOINT_VALUE,
        IARG_END);
      RTN_Close(mallocRtn);
    }
    RTN freeRtn = RTN_FindByName(img, FREE);
    if (freeRtn.is_valid()) {
      RTN_Open(freeRtn);
      RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)RecordFree,
        IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
        IARG_END);
      RTN_Close(freeRtn);
    }
    RTN mainRtn = RTN_FindByName(img, MAIN);
    if (mainRtn.is_valid()) {
      RTN_Open(mainRtn);
      RTN_InsertCall(mainRtn, IPOINT_BEFORE, (AFUNPTR)RecordMainBegin,
        IARG_END);
      RTN_InsertCall(mainRtn, IPOINT_AFTER, (AFUNPTR)RecordMainEnd,
        IARG_END);
      RTN_Close(mainRtn);
    }
  }
}

Das IMG-Objekt repräsentiert das ausführbare Abbild. Alle Pin-Funktionen, die auf dem Bild-Niveau arbeiten beginnen mit IMG_ *. IMG_Name gibt z. B. den Namen des angegebenen Image. Ebenso beginnen alle Pin-Funktionen, die auf der Routinenebene operieren mit RTN_ *. Z. B. RTN_FindByName akzeptiert ein Bild und eine C-Zeichenfolge und gibt ein RTN-Objekt, die Routine, die ich mich für interessiere, darstellt. Wenn die angeforderte Routine im Bild definiert ist, wäre das zurückgegebene RTN-Objekt gültig. Sobald ich die Malloc, free und wichtigsten Routinen gefunden haben, kann ich Analyseroutinen an den entsprechenden Stellen mit der RTN_InsertCall-Funktion einfügen.

Diese Funktion akzeptiert drei obligatorische Argumente, gefolgt von einer Variablen Anzahl von Argumenten:

  • Die erste ist die Routine, die ich will Instrument.
  • Die zweite ist eine Enumeration des Typs IPOINT, der angibt, wo die Analyse-Routine eingefügt.
  • Die dritte ist die Analyse-Routine eingefügt werden soll.

Dann kann ich eine Liste der Argumente, die für die Analyse-Routine übergeben werden angeben. Diese Liste muss von IARG_END beendet werden. Um den Rückgabewert der Funktion Malloc an die Analyse-Routine übergeben, werde ich IARG_FUNCRET_EXITPOINT_VALUE angeben. Um das Argument der freien Funktion an die Analyse-Routine übergeben, werde ich die IARG_FUNCARG_ENTRYPOINT_VALUE, gefolgt von den Index des Arguments der freien Funktion angeben. All diese Werte beginnend mit IARG_ * sind durch die IARG_TYPE-Enumeration definiert. Durch Aufruf von RTN_InsertCall wird durch Aufrufen von RTN_Open und RTN_Close eingeschlossen werden, so dass die Pintool die Analyseroutinen einfügen kann.

Jetzt, wo ich meine Analyse und Instrumentation Routinen definiert haben, werde ich haben, um eine Finalisierung-Routine zu definieren. Diese wird nach Beendigung des instrumentierten Programms aufgerufen werden. Es akzeptiert zwei Argumente, nämlich das Code-Argument, das den Rückgabewert aus der main-Funktion des Programms enthält. Andererseits werden später diskutiert werden. Ich habe eine bereichsbasierte for-Schleife verwendet, um den Code lesbarer zu gestalten:

VOID Fini(INT32 code, VOID *v) {
  for (pair<ADDRINT, bool> p : MallocMap) {
    if (!p.second) {
      // Unfreed memory.
      OutFile << "Memory at " << hex << p.first << "
        allocated but not freed." << endl;
    }
  }
  OutFile.close();
}

Alles was ich habe zu tun, die Finalisierung-Routine ist MallocMap durchlaufen und erkennen diese Zuweisungen, die noch nicht freigegeben wurde. Die Rückkehr von Fini markiert das Ende des Instrumentationsvorgangs.

Der letzte Teil des Codes ist die Hauptfunktion der Pintool. In der main-Funktion wird PIN_Init aufgerufen, um die Pin, die der Befehlszeile um die Knöpfe zu initialisieren zu analysieren haben. Weil ich bin auf der Suche nach Funktionen mit den Namen, muss PIN die Symboltabelle des Bildes Programm zu laden. Ich kann dies tun, durch Aufrufen von PIN_InitSymbols. Die Funktion IMG_AddInstrumentFunction registriert die Instrumentierung-Funktion Bild aufgerufen werden, jedes Mal, wenn ein Bild geladen wird.

Darüber hinaus wird der Beendigungsfunktion mit PIN_AddFiniFunction registriert. Beachten Sie, dass das zweite Argument für diese Funktionen an den V-Parameter übergeben wird. Ich kann diesen Parameter verwenden, zusätzliche Informationen an Instrumentierung Funktionen übergeben. Schließlich wird PIN_StartProgram aufgerufen, um das Programm zu starten, was, das ich bin analysieren. Diese Funktion gibt eigentlich nie an die Hauptfunktion. Sobald sie aufgerufen wird, übernimmt alles Pin:

int main(int argc, char *argv[]) {
  PIN_Init(argc, argv);
  ProgramImage = argv[6]; // Assume that the image name is always at index 6.
  PIN_InitSymbols();
  OutFile.open(OutFileName.Value().c_str());
  IMG_AddInstrumentFunction(Image, NULL);
  PIN_AddFiniFunction(Fini, NULL);
  PIN_StartProgram();
  return 0;
}

Montage dieser Teile des Codes stellt einen voll Func­Tional Pintool.

Führen Sie die Pintool

Sie sollten dieses Projekt ohne Fehler erstellen können. Außerdem benötigen Sie ein Programm zum Testen der Pintool. Sie können das folgenden Test-Programm verwenden:

#include <new>
void foo(char* y) {
  int *x = (int*)malloc(4);
}
int main(int argc, char* argv[]) {
  free(NULL);
  foo(new char[10]);
  return 0;
}

Klar, dieses Programm zwei Memory-Leaks und ein unnötiger Aufruf an frei, leidet ein Problem mit der Programmlogik. Erstellen Sie ein weiteres Projekt, das das Testprogramm beinhaltet. Erstellen Sie das Projekt um eine EXE-Datei zu erzeugen.

Der letzte Schritt der Pintool ausgeführt ist Pin Visual Studioals externes Tool hinzu. Wählen Sie im Menü Extras externe Tools. Ein Dialogfeld wird geöffnet, wie in Abbildung 4. Klicken Sie auf hinzufügen, um ein neues externes Tool hinzufügen. Der Titel sollte Pin sein und der Befehl sollte das Verzeichnis der Datei pin.exe. Die Argumente sind die Argumente an pin.exe übergeben werden. -T-Switch gibt das Pintool-Verzeichnis. Geben Sie das Programm, nachdem die zwei Bindestriche instrumentiert werden. Klicken Sie auf OK, und Sie sollte Pin aus dem Menü Extras ausführen können.

Hinzufügen Visual Studio über das Dialogfeld "externe Tools" Pin
Abbildung 4 Hinzufügen Visual Studio über das Dialogfeld "externe Tools" Pin

Beim Ausführen des Programms druckt im Ausgabefenster nichts, die Sie in die Cerr und Cout-Streams zu werfen. Der Cerr-Stream druckt normalerweise informative Nachrichten aus Pintool während der Ausführung. Sobald Pin beendet wird, können Sie die Ergebnisse anzeigen, durch Öffnen der Datei, die die Pintool geschaffen hat. Standardmäßig wird das memtrace.txt aufgerufen. Wenn Sie die Datei öffnen, sollten Sie so etwas sehen:

Freeing unallocated memory at 0.
Memory at 9e5108 allocated but not freed.
Memory at 9e5120 allocated but not freed.

Wenn Sie komplexere Programme haben, die die Pintool Annahmen entsprechen, sollten Sie sie mit Hilfe der Pintool instrumentieren, wie Sie andere Speicherprobleme finden könnten, die Sie nicht bewusst waren.

Debuggen der Pintool

Bei der Entwicklung einer Pintool werde Sie durch eine Reihe von Fehler stolpern. Sie können nahtlos Debuggen mit dem Debugger Visual Studio durch Hinzufügen der - Pause_tool-Schalter. Der Wert dieses Schalters gibt die Anzahl der Sekunden, die Pin wartet, bevor die Pintool tatsächlich ausgeführt wird. Dadurch können Sie den Visual Studio -Debugger anfügen, um den Prozessbetrieb Pintool (die den Prozessbetrieb das instrumentierte Programm identisch ist). Dann können Sie Ihre Pintool normalerweise Debuggen.

Pintool entwickelte ich hier wird davon ausgegangen, dass der Name des Bildes am Index 6 im Argv-Array befindet. So dass, wenn Sie den Pause-Tool-Schalter hinzufügen möchten, den Namen des Abbilds an Index 8. Sie können dies automatisieren, indem Sie ein bisschen mehr Code schreiben.

Zusammenfassung

Um Ihre Fähigkeiten weiter zu entwickeln, können Sie die Pintool erhöhen, damit es andere Arten von Gedächtnisstörungen wie baumelnden Zeigern und wild Zeiger erkennen kann. Außerdem ist die Pintool-Ausgabe nicht sehr nützlich, weil sie nicht daran, welchen Teil des Codes das Problem verursacht. Es wäre schön, Drucken Sie den Namen der Variablen, die das Problem verursacht und den Namen der Funktion, in der die Variable deklariert ist. Dies würde Ihnen leicht zu lokalisieren und zu beheben den Fehler im Quellcode. Drucken von Funktionsnamen einfach ist, zwar drucken Variablennamen schwieriger wegen des Mangels an Unterstützung durch Pin.

Es gibt eine Menge von Interaktionen zwischen Pin, die Pintool und das instrumentierte Programm passiert. Es ist wichtig, diese Interaktionen zu verstehen, bei der Entwicklung von fortschrittlichen Pintools. Jetzt sollten Sie sich durch die Beispiele mit Pin zu einem besseren Verständnis seiner Macht arbeiten.


Hadi Brais ist ein Ph.d. Stipendiat am Indian Institute von Technologie Delhi (IITD), Erforschung optimierender Compiler Design für die nächste Generation-Memory-Technologie. Er verbringt die meiste seiner Zeit, das Schreiben von Code in C / C + + / c# und Graben tief in die CLR und CRT. Er Blogs auf hadibrais.wordpress.com. Sie erreichen ihn am hadi.b@live.com.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Preeti Ranjan Panda