Wie Sie vielleicht wissen, können wir GDB verwenden und Haltepunkte für unseren Code festlegen, um die Ausführung für das Debuggen anzuhalten.
Meine Frage ist, wie pausiert GDB einen Prozess und lässt Sie den Inhalt von Registern i r
beispielsweise anzeigen . Werden diese Register nicht ständig von anderen Betriebssystemprozessen verwendet? Wie werden sie nicht überschrieben?
Ist es nur ein Schnappschuss des Inhalts und keine Live-Daten?
Antworten:
Es variiert leicht mit der Architektur, aber die wichtigen Punkte gelten fast universell:
Durch die Unterbrechung der Wartung wird der CPU-Status (einschließlich der Register) vor dem Ausführen des ISR gespeichert und beim Beenden des ISR wiederhergestellt.
Wenn eine Interrupt-Serviceroutine den Inhalt des Speicherorts austauscht, in dem diese Register gespeichert sind, kann sie eine Kontextumschaltung durchführen . Jeder Thread hat einen Speicherbereich, in dem seine Register gespeichert werden, wenn der Thread nicht ausgeführt wird.
Der Kontextwechsel wird von einem Thread-Scheduler gesteuert, der berücksichtigt, ob ein Thread auf E / A, Synchronisation, Priorität, Signalübermittlung usw. wartet. Oft wird eine Anzahl von Unterbrechungen berücksichtigt.
Der Debugger kann die Anzahl der Unterbrechungen erhöhen, wodurch sichergestellt wird, dass der Thread nicht ausgeführt werden kann. Dann kann es die gespeicherte Kopie der Register des Threads überprüfen (und ändern).
quelle
Gestatten Sie mir zusätzlich zu den großartigen Informationen von @BenVoigt einige Ergänzungen:
Ein Haltepunkt wird vom Debugger gesetzt, indem ein Maschinencodewert (ein Befehl oder ein Teil eines Befehls) im zu debuggenden Prozess durch einen bestimmten Trap-Befehl an der Stelle im Code ersetzt wird, an der die gewünschte (Quell-) Zeile unterbrochen werden soll. Dieser spezielle Trap-Befehl ist als Haltepunkt gedacht - der Debugger weiß das und das Betriebssystem auch.
Wenn der zu debuggende Prozess / Thread auf den Trap-Befehl trifft, der den Prozess @Ben auslöst, wird beschrieben, welcher die Hälfte eines Context-Swaps enthält, der den aktuell ausgeführten Thread anhält (einschließlich des Speicherns seines CPU-Status im Speicher), um ihn möglicherweise später wiederaufzunehmen. Da es sich bei diesem Trap um einen Haltepunkt handelt, hält das Betriebssystem den zu debuggenden Prozess möglicherweise mithilfe eines von @Ben beschriebenen Mechanismus angehalten und benachrichtigt den Debugger und setzt ihn schließlich fort.
Der Debugger verwendet dann Systemaufrufe, um auf den gespeicherten Status des angehaltenen Prozesses / Threads zuzugreifen, der debuggt wird.
Um die unterbrochene Codezeile (die jetzt den speziellen Trap-Befehl enthält) auszuführen (fortzusetzen), stellt der Debugger den ursprünglichen Maschinencode-Wert wieder her, den er mit dem Breakpoint-Trap-Befehl überschrieben hat. oder der Benutzer erstellt neue Haltepunkte) und markiert den Prozess / Thread als ausführbar, möglicherweise unter Verwendung eines Mechanismus, wie er von @Ben beschrieben wird.
Tatsächliche Details können komplizierter sein, da das Beibehalten eines langen Haltepunkts, der getroffen wird, das Austauschen der Haltepunktfalle gegen echten Code bedeutet, damit die Zeile ausgeführt werden kann, und das erneute Eintauschen des Haltepunkts ...
Wie @Ben beschreibt, können mit der bereits vorhandenen Funktion zum Anhalten / Fortsetzen von Threads (Kontextwechsel / Austauschen von Multitasking ) Prozessoren von mehreren Prozessen / Threads mithilfe von Time Slicing gemeinsam genutzt werden.
Es ist beides. Da der Thread, der den Haltepunkt erreicht hat, angehalten wird, handelt es sich um eine Momentaufnahme der Live-Daten (CPU-Register usw.) zum Zeitpunkt des Anhaltens und des autorisierenden Masters der CPU-Registerwerte, die im Prozessor wiederhergestellt werden sollen, falls der Thread wieder aufgenommen wird . Wenn Sie die Benutzeroberfläche des Debuggers zum Lesen und / oder Ändern der CPU-Register (des zu debuggenden Prozesses) verwenden, wird dieser Snapshot / Master mithilfe von Systemaufrufen gelesen und / oder geändert.
quelle
Genau genommen pausiert gdb die Ausführung nicht, zumindest in den meisten typischen Fällen. Stattdessen fragt gdb das Betriebssystem, und das Betriebssystem hält die Ausführung an.
Das mag zunächst wie eine Unterscheidung ohne Unterschied erscheinen - aber ehrlich, es gibt wirklich einen Unterschied. Der Unterschied besteht darin, dass diese Funktion bereits in das typische Betriebssystem integriert ist, da es in der Lage sein muss, die Ausführung eines Threads anzuhalten und erneut zu starten - wenn ein Thread nicht ausgeführt werden soll (z. B. eine Ressource, die benötigt wird) ist derzeit nicht verfügbar) muss das Betriebssystem angehalten werden, bis die Ausführung geplant werden kann.
Zu diesem Zweck verfügt das Betriebssystem normalerweise über einen Speicherblock, der für jeden Thread reserviert wird, um den aktuellen Status der Maschine zu speichern. Wenn ein Thread angehalten werden muss, wird der aktuelle Status der Maschine in diesem Bereich gespeichert. Wenn ein Thread fortgesetzt werden muss, wird der Status des Computers in diesem Bereich wiederhergestellt.
Wenn der Debugger einen Thread anhalten muss, hält das Betriebssystem diesen Thread genauso an wie aus anderen Gründen. Um dann den Status des angehaltenen Threads zu lesen, überprüft der Debugger den gespeicherten Status des Threads. Wenn Sie den Status ändern, schreibt der Debugger in den gespeicherten Status. Dieser wird dann wirksam, wenn der Thread fortgesetzt wird.
quelle