42
Kernel Debugger Seminar Martin Mehlmann [email protected]

Kernel Debugger - Universität des Saarlandes...Begriffsklärung Bug -Fehlschlagen eines Programms n Der Programmierer hinterlässt einen Defekt im Quellcode ¤Fehler im Quellcode

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Kernel Debugger

SeminarMartin Mehlmann

[email protected]

Übersicht

n Bugn Debuggingn Debugger und Werkzeuge

n Kernel Debuggingn Kernel Debugger und Kernel Werkzeuge

Begriffsklärung Bug

n Woher kommt der Begriff Bug ?¨Der erste Bug

n 9. September 1945n Grace Hopper fand bei Fehlersuche in Mark 2 eine

Motte, deren Flügel das Einlesen der Lochkarte blockierten

¨Resultierende Begriffen Bug für Fehlern Debugging für Fehlersuche und Fehlerbehebung

Begriffsklärung Bug

Begriffsklärung Bug

n Fehler in Software¨ Fehler im Quellcode¨ Fehler im Programmzustand¨ Fehler im Design

n Fehler in Hardware¨ physikalischer Fehler¨ Fehler im Design

n oder doch ein Feature ?

Begriffsklärung Bug - Fehlschlagen eines Programmsn Der Programmierer hinterlässt einen Defekt im

Quellcode¨ Fehler im Quellcode

n Wenn dieser defekte Code ausgeführt wird, so ist das Resultat eine Infektion des Programmzustandes¨ Fehler im Programmzustand

n Die Infektion propagiert sich eventuell über mehrere Variablen

n Die Infektion resultiert in einem Fehlschlagen des Programms, welches vom Benutzer beobachtet wird¨ Fehler im Programm

Begriffsklärung Bug - Der Fluch des Testensn Nicht jeder Defekt im Programmzustand muss in

einem Fehlschlagen resultieren¨ Nicht jeder Defekt resultiert in einer Infektion¨ Nicht jede Infektion resultiert in einem Fehlschlagen

n Testen kann nur die Anwesenheit von Fehlern zeigen, nicht deren Abwesenheit (Dijkstra 1972)

n Nur Verifikation kann die Abwesenheit von Defekten garantieren

Begriffsklärung Debugging

n Jedes Fehlschlagen kann auf eine Infektion im Programmzustand zurückgeführt werden

n Jede Infektion kann auf einen Defektzurückgeführt werden¨ Ausnahme: physikalische Einflüsse

n Debuggen bedeutet ein beobachtetes Fehlschlagen einem Defekt zuzuordnen und diesen zu entfernen

Begriffsklärung Debugging

n Debugging ist ein zweidimensionales Suchproblem ¨Zeit

n Bestimmung des Infektionsbeginnsn Zustandsübergang von gesund nach infiziert

¨Variablenn Aufteilung in gesunde und infizierte Variablen

Debugging - Vorgehensweise

n Beobachte das Fehlschlagen des Programmsn Reproduziere das Fehlschlagen unter denselben

Umständen¨ Automatisierbar (capture and replay)

n Vereinfache die Umstände¨ Automatisierbar (Deltadebugging)

n Lokalisiere den Defekt¨ Automatisierbar (Deltadebugging)

n Beseitige den Defekt¨ most general fix

Debugging - Unterscheidung

n Statisches Debuggen¨ deduktiv¨ Debuggen ohne Programm auszuführen

n Dynamisches Debuggen¨ induktiv¨ Debuggen zur Laufzeit

n Beobachten von einzelnen Programmläufen¨ Debuggen nach dem Fehlschlagen

n Post Mortem Debuggen

Begriffsklärung Debugger

n Software, welche Debuggen anderer Software ermöglicht¨ Kontrollierte Ausführung¨ Überwachung ¨Manipulation

n Unterscheidung¨ Debugger auf Maschinenebene¨ Debugger auf Quellsprachenebene

n GNU Debugger GDB

Debugger -Maschinensprachenebenen Verfolgung des Programmgeschehens auf

Maschinensprachenebenen Vorteil¨Untersuchung von closed software möglich

n Nachteil¨ low level Assemblercode¨Kenntnis der Rechnerarchitektur nötig

Debugger - Quellsprachenebene

n Verfolgung des Programmgeschehens auf Quellsprachenebene

n Vorteile¨ Ausführen oder Überspringen von Funktionen¨ Auswerten von Ausdrücken in Quellsprache

n Nachteile¨ Benötigt Debuggingsymbole

n Symboltabelle ¨ Variablennamen, Funktionsnamen¨ Matching zwischen Quellcode und Assemblercode

¨ Ausführbare Datei kann erheblich größer sein¨ Quellcode muss vorliegen

Debugger - Grundprinzipien

n Das Heisenberg-Prinzip¨ Die Verwendung eines Debuggers darf das Verhalten

des untersuchten Programms nicht beeinflussenn Das untersuchte Programm ist auf einen Teil des Speichers

angewiesen, der aber auch vom Debugger verwendet wird

n Das Wahrheitsprinzip¨ Die Informationen, die der Debugger liefert, müssen

wahrheitsgemäß einn Eine Variable wurde in ein Register geladen und verändert,

der Debugger aber holt den Wert aus dem Speicher

Debugger Funktionalität - Anzeigen des Programmzustands n Suche in der Zeit¨Haltepunkte

n breakn continue

¨Einzelschrittausführungn stepn next

¨Programmzähler

Debugger Funktionalität - Anzeigen des Programmzustandsn Suche in den Variablen¨Werte von Variablen

n printn info locals

¨Funktionsstapeln backtrace

¨Registerinhalten info registers

Debugger Funktionalität - Anzeigen des Programmzustandsn Suche in Zeit und Variablen¨Datenhaltepunkte

n watch¨Bedingte Haltepunkte

n break if

Debugger Funktionalität - Ändern des Programmzustandsn Werte von Variablen¨ set

n Funktionsstapel¨ up¨ down

n Programmzähler¨ set

n Registerinhalte¨ set

Debugger - Funktionsweise

n Betriebsystem führt Programme als Prozesse aus n Debugger und untersuchtes Programm sind separate

Benutzerprozessen Kommunikation erfolgt über vom Kernel zur Verfügung

gestellte Debugschnittstelle zur Kontrolle der Ausführung von Prozessen durch andere Prozesse¨ long ptrace(enum request, pid_t pid, void* addr, void* data);

n Jede Interaktion zwischen Debugger und untersuchtem Programm läuft über diese Schnittstelle

Debugger - Funktionsweisen Vorbereitung des untersuchten Prozesses

¨ PTRACE_TRACEMEn Zugriff auf Register des untersuchten Prozesses

¨ PTRACE_GETREGS ¨ PTRACE_SETREGS

n Zugriff auf Speicher des untersuchten Prozesses¨ PTRACE_PEEKTEXT, PTRACE_PEEKDATA¨ PTRACE_POKETEXT, PTRACE_POKEDATA

n Fortsetzen und Einzelschrittausführung des untersuchten Prozesses¨ PTRACE_SYSCALL¨ PTRACE_CONT ¨ PTRACE_SINGLESTEP

n Beenden des untersuchten Prozesses¨ PTRACE_KILL

Debugger - Funktionsweise

n Debugger (Vaterprozess) ¨ fork()¨ waitpid(child_pid, &ret_val, 0))

n Debugger wartet auf SIGCHLD Signal vom Kernel, dass Kindprozess gestoppt oder beendet wurde

n Rückgabewert enthält Signal aufgrund dessen der Kindprozess gestoppt wurde

¨ Verwendung von ptrace um den Kindprozess zu kontrollieren

¨Wiedereintritt in waitpid

Debugger - Funktionsweise

n Kindprozess ¨ ptrace (PTRACE_TRACEME, 0, 0, 0)

n Anmelden beim Kernel für Tracing¨ Spezielle Behandlung von Signalen¨ Prozess-Kontroll-Mechanismen

n Erlaubt Vaterprozess Kontrolle über Kindprozess¨ execvp (debuggee, args)

n Ersetzt sich selbst durch das zu untersuchende Programm¨ Kindprozess stoppt nach jedem empfangenen Signal

n Wiederaufnahme bei: kill, singlestep, continuen Signal wird ignoriert

¨ Vaterprozess wird vom Kernel durch SIGCHLD Signal informiert

Debugger - Setzen eines Haltepunktsn Debugger möchte einen Haltepunkt an Adresse 0x109d4n Falls Debugregister für Haltepunkte vorhanden, wird

eines dieser Register verwendet (Hardwarehaltepunkt)n Ansonsten wird die Instruktion, die unter der Adresse

0x109d4 zu finden ist gesichert und durch eine breakinstruction ersetzt (Softwarehaltepunkt)

int rc; if (Haltepunkt-Register frei) {

rc = ptrace (PTRACE_SETREGS, 0, 0x109d4)} else {

saved_instruction = ptrace (PTRACE_PEEKTEXT, 0x109d4, 0);rc = ptrace (PTRACE_POKETEXT, 0x109d4, break_instruction );

}

Debugger - Erreichen eines Haltepunktsn Debugregister oder break instruction löst Trap aus welche vom Kernel

verarbeitet wirdn Kernel sendet SIGTRAP Signal an Prozess und lässt diesen an Adresse

0x109d4 stoppenn Debugger wird vom Kernel durch das SIGCHLD Signal informiertn Der Debugger versichert sich, dass das untersuchte Programm aufgrund

eines Haltepunktes gestoppt wurde und stellt die gesicherte Instruktion wieder her

n Nun kann der Debugger die Werte aus dem Speicher oder aus Registern holen, um den Benutzer über den Zustand des Programms zu informieren

int rc;if ( !(Aufruf von Register) ) {

rc = ptrace (PTRACE_POKETEXT, 0x109d4, saved_instruction);}

Debugger - Fortsetzen des Programmsn Falls Debugregister für Haltepunkt verwendet wurde, wird das

untersuchte Programm sofort fortgesetztn Ansonsten wird zuerst eine einzelne Anweisung ausgeführt, um

anschließend die break instruction wiederherzustellenn Danach wird das beobachtete Programm fortgesetzt

int rc;if ( Unterbrechung wurde von Haltepunkt-Register ausgelöst ) {

rc = ptrace (PTRACE_CONT, 0, 0);} else {

rc = ptrace (PTRACE_SINGLESTEP, 0, 0);rc = ptrace (PTRACE_POKETEXT, 0x109d4, break_instruction);rc = ptrace (PTRACE_CONT, 0, 0);

}

Debugger -Einzelschrittausführungn Falls Debugregister für Einzelschrittausführung

vorhanden, wird dieses Register verwendet ¨ Trap flag im Debug Register wird gesetzt, welches

Trap nach jeder Instruktion auslöst¨ Kernel sendet SIGTRAP Signal an Prozess und lässt

diesen stoppen¨ Debugger wird vom Kernel durch das SIGCHLD

Signal informiertn Ansonsten werden Haltepunkte nach jeder

Instruktion gesetzt

Debugger - Datenhaltepunkte

n Falls Debugregister für Datenhaltepunkte vorhanden, wird dieses Register verwendet ¨ Trap flag im Debug Register wird gesetzt, welches Trap auslöst,

sobald sich der Wert an der registrierten Adresse ändert ¨ Kernel sendet SIGTRAP Signal an Prozess und lässt diesen

stoppen¨ Debugger wird vom Kernel durch das SIGCHLD Signal informiert

n Falls keine Debugregister für Datenhaltepunkte vorhanden oder der beobachtete Ausdruck berechnet werden muss wird Einzelschrittausführung verwendet

Debugging Werkzeuge - STRACE

n Beobachten des Systemverhaltens¨ Verfolgung aller system calls die vom beobachteten Prozess

aufgerufen werdenn Namen Argumenten Rückgabewert

¨ Protokollierung aller Signale die vom beobachteten Prozess empfangen werden

n Vorteile¨ Programm muss nicht mit Debuginformationen übersetzt werden

n Nachteile¨ Suche begrenzt auf Schnittstelle zwischen libc und Kernel

Debugging Werkzeuge - STRACE

Debugging Werkzeuge - STRACE

n Realisierung durch Verwendung von ptrace¨ strace weist das nach fork() entstandene Kind an, ihm

durch PTRACE_TRACEME das Recht zur Kontrolle zu geben

¨ Kernel sendet SIGSTOP Signal an Kindprozess um diesen anzuhalten

¨ Kernel sendet SIGCHLD an Elternprozess um diesen zu benachrichtigen

¨ strace kann nun Kindprozess mithilfe von ptracekontrollierenn PTRACE_SYSCALL

Kernel Debugging - Problematik

n Keine übergeordnete Schicht, welche die Ausführung des Kernels kontrolliert

n Kernel läuft in eigenem speziell geschützten Adressraum

n Gängige Debuggerfunktionalität ist schwieriger zu erreichen¨Haltepunkte, Datenhaltepunkte¨Einzelschrittausführung

Kernel Debugging mit GDB

n laufender Kernel kann mit GNU Debugger GDB untersucht werden¨ Aufruf: gdb /usr/src/vmlinux /proc/kcore¨ /usr/src/vmlinux ist unkomprimierte Version des

Kernels mit Debugsymbolen¨ /proc/kcore ist Name der Coredatei

n Repräsentiert den momentan laufenden Kernel im Speichern /proc/kcore wird beim Auslesen erzeugt

Kernel Debugging mit GDB

n Kernel wird nicht angehalten¨ Eingelesene Daten werden von GDB zwischengespeichert¨ Wiederholter Zugriff liefert Daten aus Zwischenspeicher ¨ Aktuelle Werte durch Reinitialisierung des Zwischenspeichers

n core-file /proc/kcore leert den Cache des GDB

n Nachteile¨ Keine Änderung des Kernelzustands durch den GDB¨ Keine kontrollierte Ausführung des Kernels durch den GDB

n Keine Haltepunkten Keine Datenhaltepunkten Keine Einzelschrittausführung

Kernel Debugging mit User Mode Linuxn Portierung des Linux Kernels als virtuelle Maschine

¨ Hardwareschicht wird durch system calls an das Hostsystem emuliert

n Kernel läuft als separater Prozess im User Adressraum auf einem Host System

n Vorteile¨ Ein defekter Kernel kann nicht das Hostsystem zerstören¨ Verschiedene Konfigurationen können leicht auf dem gleichen

Rechner getestet werden¨ Kernel kann mit GDB ohne Einschränkungen manipuliert werden

Kernel Debugger - KGDBn Kernel Patch (http://oss.sgi.com)

¨ Volle Debuggerfunktionalitätn Haltepunkte, Datenhaltepunkten Einzelschrittausführung

¨ Komponentenn GDB stub

¨ Verarbeitet ankommende Anfragen vom GDBn Änderungen der Fehlerbehandlung

¨ Kernel gibt Kontrolle an Debugger wenn ein unerwarteter Fehler auftritt¨ Es werden 2 Rechner mit serieller Schnittstelle benötigt

n Testmaschine ¨ Enthält gepatchten zu untersuchenden Kernel

n Entwicklungsmaschine ¨ GDB kommuniziert über serielle Verbindung mit Kernel

Kernel Debugger - KGDB

Kernel Debugging - LKCA

n Linux Kernel Crash Analyzer (http://oss.sgi.com)¨ Kernel Oops

n LKCD schreibt Kopie des aktuelles Systemzustand in ein Dump Gerätn Dump Gerät: System Swap Bereich

¨ Hilfprogramm LCRASH n Aktiv bei nächstem Neustart des Systems

¨ Erzeugt Zusammenfassung des Crash¨ Schreibt Zusammenfassung in eine konventionelle Datei

n Interaktiv¨ Debugger ähnliche Funktionalität

¨ Nachteilen Nur x86 32-Bit-Architekturn Nur Swap-Partitionen von SCSI-Festplatte

Kernel Debugging - DynamicProbesn Entwickelt von IBM (http://oss.software.ibm.com)

¨ Einsetzen einer Sonde im Systemn Sowohl im User als im Kernel Adressraum

¨ Sonde besteht aus Coden spezielle stackorientierte Sprachen Zurückliefern von Daten an den User Adressraumn Ändern von Registern

n Vorteile¨ Einmaliges Einbauen von DProbes in den Kernel¨ Einfügen von Sonden an beliebigen Stellen ohne Neukompilieren des Kernels

oder Neustart des Systems¨ Zusammenarbeit mit LTT

n Einfügen von Tracing Ergebnissen an bestimmten Stellenn Nachteile

¨ Nur x86 32-Bit-Architektur

Kernel Debugging - Linux TraceToolkitn Kernel Patch inklusive Hilfsprogramme¨ Verfolgen von Ereignissen im Kernel

n Kernel kann Ereignisse loggenn Kernel Modul speichert diese in einem Puffern Hilfsprogramm liest den Puffer und präsentiert Ereignisse in

lesbarer Form

¨ Timing Informationenn Was ist zu welchem Zeitpunkt passiertn Einkreisen von Performanzproblemen

¨ Finden von Bottlenecks

Kernel Debugging - Kernel-Oops Meldungenn Kernel-Oops Meldungen¨ Fehlermeldungen des Kernels ¨ Informationen zu Zustand von Registern und

Kernelstapel¨ Ausgabe hexadezimal

n klogd ¨ Loggt Kernel-Oops Meldungen

n ksymoops¨ Decodiert Kernel-Oops Meldungen¨ Anzeige der decodierten Informationen

Ende

n Vielen Dank für die Aufmerksamkeit !n Fragen ?