
In der Softwareentwicklung ist ein Haltepunkt eine absichtliche Anhalte- oder Pausenstelle in einem Programm , die zu Debugging- Zwecken eingefügt wird . Er wird manchmal auch einfach als Pause bezeichnet .
Allgemeiner gesagt, ist ein Haltepunkt ein Mittel, um während der Programmausführung Informationen über das Programm zu gewinnen. Während der Unterbrechung untersucht der Programmierer die Testumgebung ( Allgemeinregister , Speicher , Protokolle, Dateien usw.), um festzustellen, ob das Programm wie erwartet funktioniert. In der Praxis besteht ein Haltepunkt aus einer oder mehreren Bedingungen, die festlegen, wann die Programmausführung unterbrochen werden soll.
Geschichte
Haltepunkte wurden für ENIAC , einen der ersten Digitalrechner, von der Programmiererin Betty Holberton erfunden . [ 1 ] Im ursprünglichen Design des ENIAC wurde der Programmablauf durch das Verbinden von Kabeln zwischen den einzelnen Einheiten festgelegt. Um das Programm an einem bestimmten Punkt anzuhalten, wurde ein Kabel entfernt, der sogenannte Haltepunkt . [ 2 ]
Arten von Haltepunkten
Maschinen-Haltepunkte
Frühe Großrechner wie der IBM/360 besaßen Konsolenschalter/Drehregler, mit denen Haltepunkte an bestimmten Speicheradressen gesetzt werden konnten. Zudem ermöglichten sie den „Einzelzyklusbetrieb“, wodurch der Inhalt von Registern und Speicher direkt über die Konsolenleuchten abgelesen werden konnte. Mit dem Aufkommen von Multitasking war diese Option nur noch eingeschränkt nutzbar, da der gesamte Rechner angehalten wurde.
Nicht-interaktive Haltepunkte
Seit den Anfängen der Computertechnik nutzen Programmierer Maschinencode-Patches, um gezielt einzelne, destruktive Haltepunkte zu implementieren und so einen Core-Dump zu erzeugen. Der Core-Dump liefert den Zustand der Register und des Speichers genau zum Zeitpunkt des absichtlich herbeigeführten „Absturzes“.
Interaktive Haltepunkte
Die Einführung von Fernschreiberkonsolen in den 1960er Jahren ermöglichte interaktivere Debugging-Möglichkeiten über die Kommandozeile. Doch erst mit dem Aufkommen allgegenwärtiger Videomonitore an Großrechnern Anfang der 1970er Jahre wurde vollständig interaktives Debugging im Vollbildmodus in Multitasking-Umgebungen Realität. Dies erlaubte auch die schrittweise Programmausführung in Form einer echten Programmanimation, wobei optionale Register- und Speicheränderungen gleichzeitig angezeigt wurden. Anfänglich erfolgte diese Animation auf der Ebene von disassembliertem oder dekompiliertem Maschinencode, später wurde sie auf die Ebene des Quellcodes höherer Programmiersprachen (HLL) erweitert.
Bedingte Haltepunkte
Haltepunkte werden am häufigsten verwendet, um ein laufendes Programm unmittelbar vor der Ausführung einer vom Programmierer festgelegten Anweisung zu unterbrechen. Dies wird oft als Anweisungshaltepunkt bezeichnet .
Es können auch andere Bedingungen verwendet werden, wie beispielsweise das Lesen, Schreiben oder Ändern einer bestimmten Speicherstelle. Dies wird häufig als Datenhaltepunkt oder Überwachungspunkt bezeichnet. Viele Systeme unterstützen auch Haltepunkte, die nur aktiv sind, wenn eine Bedingung erfüllt ist (z. B. wenn eine Variable einen bestimmten Wert hat); diese werden üblicherweise als bedingte Haltepunkte bezeichnet . [ 3 ]
Inspektionswerkzeuge
Wird ein Haltepunkt erreicht, stehen verschiedene Werkzeuge zur Verfügung, um den Programmzustand zu untersuchen oder ihn zu ändern. Mithilfe des Stack-Traces jedes Threads lässt sich die Kette der Funktionsaufrufe nachvollziehen , die zur angehaltenen Anweisung geführt haben. Eine Liste von Überwachungsvariablen ermöglicht die Anzeige der Werte ausgewählter Variablen und Ausdrücke . Zusätzlich können Werkzeuge bereitgestellt werden, um den Inhalt von Registern , geladenen Programmmodulen und weitere Informationen anzuzeigen .
Logpunkte
Ein Logpoint ist eine Art Haltepunkt, der lediglich Informationen ausgibt (oder „protokolliert“ ), anstatt die Ausführung zu unterbrechen. Normalerweise kann der Entwickler eine Meldung und/oder Variablenwerte angeben, die ausgegeben werden sollen, sobald die Ausführung einen bestimmten Punkt erreicht. [ 4 ] Logpoints sind eine Alternative zum Einfügen von Protokollierungsanweisungen in das zu debuggende Programm (manchmal auch printf-Debugging genannt ) und besonders hilfreich, wenn eine Änderung des Programms nicht praktikabel ist (z. B. beim Debuggen einer externen Bibliothek, die vom Programm aufgerufen wird).
Implementierungen
Hardware
Viele Prozessoren bieten Hardwareunterstützung für Haltepunkte (typischerweise Befehls- und Datenhaltepunkte). Beispielsweise stellt die x86-Befehlssatzarchitektur mit ihren x86-Debug-Registern Hardwareunterstützung für Haltepunkte bereit . Diese Hardware kann jedoch Einschränkungen aufweisen, beispielsweise das Verbot von Haltepunkten für Befehle in Verzweigungsverzögerungsslots . Solche Einschränkungen sind durch die Mikroarchitektur des Prozessors bedingt und variieren von Prozessor zu Prozessor.
Software
Ohne Hardwareunterstützung (und in Multitasking-Umgebungen) müssen Debugger Haltepunkte in Software implementieren. Bei Befehls-Haltepunkten ist dies eine vergleichsweise einfache Aufgabe: Der Befehl an der Haltepunktstelle wird entweder durch Folgendes ersetzt:
- eine Anweisung, die den Debugger direkt aufruft (z. B. ein Systemaufruf oder int3 im Fall von x86 ) oder
- eine ungültige Anweisung, die einen absichtlichen Programmabbruch auslöst (der dann vom Debugger abgefangen/behandelt wird).
Diese Technik kann in Multitasking-Systemen mit gemeinsam genutztem Programmspeicher schwieriger zu implementieren sein (die Unterbrechung kann in einem anderen Thread auftreten, was die erneute Ausführung der ursprünglichen Anweisung für diesen Thread erforderlich macht). Befindet sich das Programm in geschütztem Speicher, kann zudem das Überschreiben von Anweisungen verhindert werden.
Alternativ dazu
- Ein Befehlssatzsimulator kann unbedingte oder bedingte Haltepunkte implementieren, indem er die entsprechenden Bedingungstests einfach in seinen eigenen normalen Programmzyklus einbettet – das ermöglicht natürlich auch nicht-invasive Haltepunkte (zum Beispiel bei schreibgeschützten Programmen).
- Interpretierte Sprachen können das gleiche Konzept wie oben in ihrem Programmzyklus effektiv nutzen.
- Das „Instrumentieren“ des gesamten Quellcodes mit zusätzlichen Anweisungen, die eine Funktion aufrufen , welche wiederum eine interne oder externe Debug-Subroutine ausführt, ist ein weiterer gängiger Ansatz. Diese Methode erhöht die Binärgröße und kann die normale Speicherverwaltung und Ausnahmebehandlung beeinträchtigen . Einige Compiler bieten „Debug“-Optionen, um diese Technik semi-transparent zu implementieren.
Manche Debugger erlauben es, Register oder Programmvariablen im Speicher vor dem Fortsetzen zu modifizieren. Dadurch können temporäre, manuell codierte Zuweisungen zu Testzwecken vorgenommen werden. Ebenso lassen sich Programmbefehle oft überspringen, um die Auswirkungen von Änderungen an der Programmlogik zu ermitteln. So können Fragen zur Programmausführung direkt beantwortet werden (d. h. ohne Annahmen oder Vermutungen). In vielen Fällen ist dies die einzige praktikable Methode, um schwer verständliche, ereignisgesteuerte Fehlerbehandlungsroutinen zu testen, die selten oder nie ausgeführt werden – ohne das zusätzliche Risiko temporärer Quellcodeänderungen einzugehen. Durch manuelles Ändern der Fortsetzungsposition in einem pausierten Programm kann ein ansonsten selten ausgeführter Codeabschnitt aufgerufen werden (z. B. ein spezifischer Hardware-Fehlerbehandler).
Das Setzen von Daten-Breakpoints in Software kann die Performance der zu debuggenden Anwendung jedoch erheblich beeinträchtigen, da zusätzliche Ressourcen auf demselben Prozessor beansprucht werden. [ 5 ] Dies ist während des Testens in der Regel akzeptabel, und die vom Debugger verfügbare Informationsmenge ist nicht durch die der Hardware bekannten Debug-Daten beschränkt. Beispielsweise kann eine Software-Implementierung logische Pfaddaten auf Programm-, Subroutinen- und Befehlsebene erfassen, um die von der jeweiligen Hardwareplattform gespeicherten Daten erheblich zu erweitern. Die Befehlssatzsimulation reduziert den Overhead im Vergleich zur (wiederholten) Befehlsersetzungsmethode deutlich und verringert zudem Cache-Fehler .
Manche Programmiersprachen stellen ihre Debugging-Funktionen zur Verwendung durch andere Programme bereit. Beispielsweise verfügen einige FORTRAN- Dialekte über eine ATAnweisung, die ursprünglich als Haltepunkt für Anweisungen gedacht war. Python implementiert einen Debugger, der von einem Python-Programm aus zugänglich ist. [ 6 ] Diese Funktionen können und werden [ 7 ] missbraucht, um wie die COMEFROM- Anweisung zu funktionieren.
Siehe auch
- AUS
- Programmanimation (Schrittweise)
- SIMMON
Referenzen
- ^ Abbate, Janet (2012), Recoding Gender: Women's Changing Participation in Computing , MIT Press, S. 32, ISBN 9780262018067
- ^ Thomas Haigh; Mark Priestley; Crispen Rope (2016). ENIAC in Action: Making and Remaking the Modern Computer . MIT Press. S. 153. ISBN 978-0-262-03398-5Die
- ^ „FAQ Wie setze ich einen bedingten Haltepunkt?“ . Eclipse Wiki . Abgerufen am 19.04.2023 .
- ^ Walsh, David (22.03.2021). „Verwendet Logpoints!“ . David Walsh Blog . Abgerufen am 19.04.2023 .
- ^ GDB Internals, archiviert am 29. November 2011 in der Wayback Machine
- ^ Python-Bibliotheksreferenz: Der Python-Debugger (Archiviert am 13. September 2008 in der Wayback Machine)
- ^ entrian.com – goto und comefrom für Python