Debugger und verwandte Werkzeuge

Der letzte Ausweg beim Debuggen von Modulen besteht in der Benutzung eines Debuggers, um den Code schrittweise zu durchlaufen und dabei den Wert von Variablen und Maschinenregistern zu beobachten. Dieser Ansatz kostet viel Zeit und sollte, wo immer möglich, vermieden werden. Trotzdem kann der genaue Einblick in den Code, den man mit einem Debugger bekommt, wertvoll sein.

Die Verwendung eines interaktiven Debuggers im Kernel ist allerdings eine Herausforderung. Der Kernel läuft in einem eigenen Adreßraum im Namen aller Prozesse im System. Als Folge davon sind eine Reihe von gängigen Funktionen in User-Space-Debuggern - wie Breakpoints und Einzelschrittausführung im Kernel - schwieriger zu erreichen. In diesem Abschnitt schauen wir uns mehrere Möglichkeiten an, den Kernel zu debuggen. Alle haben ihre Vor- und Nachteile.

gdb verwenden

gdb kann sehr nützlich sein, wenn Sie einen Blick in die System-Interna werfen wollen. Eine effiziente Verwendung des Debuggers auf dieser Ebene verlangt eine gewisse Vertrautheit mit den gdb-Befehlen, ein paar Kenntnisse über den Assembler-Codes der zugrundeliegenden Plattform und die Fähigkeit, Quellcode und optimierten Assembler-Code zusammenzubringen.

Der Debugger muß so aufgerufen werden, als wäre der Kernel ein Anwendungsprogramm. Zusätzlich zu dem Dateinamen eines unkomprimierten Kernel-Images sollten Sie auf der Kommandozeile den Namen einer Core-Datei angeben. Bei einem laufenden Kernel ist diese Core-Datei das Kernel-Core-Image /proc/kcore. Ein typischer Aufruf des gdb sieht also so aus:


gdb /usr/src/linux/vmlinux /proc/kcore

Das erste Argument ist der Name des unkomprimierten Kernels, nicht von zImage oder bzImage oder von irgend etwas anderem Komprimiertem.

Das zweite Argument auf der Kommandozeile von gdb ist der Name der Core-Datei. Wie jede Datei in /proc wird auch /proc/kcore erzeugt, wenn sie ausgelesen wird. Wenn der Systemaufruf read im Dateisystem /proc ausgeführt wird, wird dieser auf eine Funktion zur Generierung und nicht auf eine Funktion zur Abfrage von Daten abgebildet; wir haben davon bereits im Abschnitt “Verwenden des /proc-Dateisystems” Gebrauch gemacht. kcore repräsentiert die ausführbare Kernel-Datei in Form einer Core-Datei. Diese Datei ist riesig, weil sie den gesamten Adreßraum des Kernels wiedergibt, der wiederum dem gesamten physikalischen Speicher entspricht. Aus dem gdb heraus können Sie Kernel-Variablen mit den normalen gdb-Befehlen ansehen. Beispielsweise gibt p jiffies die Anzahl der System-Ticks seit dem Starten des Systems an.

Wenn Sie Daten aus dem gdb ausgeben, läuft der Kernel noch, und die diversen Datenelemente haben zu verschiedenen Zeitpunkten verschiedene Werte. gdb optimiert allerdings den Zugriff auf die Core-Datei, indem einmal eingelesene Daten im Cache zwischengespeichert werden. Wenn Sie sich die Variable jiffies noch einmal ansehen, bekommen Sie die gleiche Antwort wie beim letzten Mal. Bei normalen Core-Dateien ist das Cachen von Werten zur Vermeidung zusätzlicher Festplattenzugriffe eine gute Sache, bei Verwendung eines dynamischen Cores aber natürlich unangenehm. Sie können das Programm umgehen, indem Sie jedesmal, wenn Sie den Cache des gdb leeren wollen, den Befehl core-file /proc/kcore eingeben. Der Debugger verwirft dann alle alten Informationen im Cache. Sie müssen aber nicht jedesmal core-file benutzen, wenn Sie einen neuen Wert auslesen wollen, denn gdb liest die Core-Datei in Blocks von wenigen Kilobytes und bewahrt nur solche Blocks im Cache auf, auf die bereits einmal zugegriffen wurde.

Viele normalerweise in gdb vorhandene Fähigkeiten stehen nicht zur Verfügung, wenn man mit dem Kernel arbeitet. Beispielsweise ist gdb nicht in der Lage, die Kernel-Daten zu ändern; er erwartet, das zu debuggende Programm unter eigener Kontrolle auszuführen, bevor mit dem Speicher herumgespielt werden kann. Außerdem ist es nicht möglich, Breakpoints oder Watchpoints zu setzen oder Kernel-Funktionen im Einzelschrittmodus zu durchlaufen.

Wenn Sie den Kernel mit Debug-Symbolen übersetzen (–g), dann ist die daraus resultierende vmlinux-Datei für die Verwendung mit gdb besser geeignet als eine ohne –g übersetzte Datei. Zum Übersetzen eines Kernels mit der Option –g benötigen Sie allerdings enorm viel Festplattenplatz (jede Objektdatei und der Kernel selbst sind dreimal (oder mehr) so groß wie sonst).

Auf Nicht-PCs sieht die Sache anders aus. Auf Alpha-Systemen entfernt make boot die Debugging-Symbole aus dem Kernel, bevor das bootfähige Image erzeugt wird, so daß Sie am Ende sowohl die Datei vmlinux als auch vmlinux.gz haben. Erstere kann mit dem gdb, letztere zum Booten verwendet werden. Auf Sparc-Systemen (zumindest im 2.0-Kernel) werden die Debugging-Symbole defaultmäßig nicht entfernt.

Wenn Sie den Kernel mit –g kompilieren und den Debugger zusammen mit /proc/kcore auf vmlinux ansetzen, dann kann gdb eine Menge an Informationen über die Kernel-Interna ausgeben. Beispielsweise können Sie Befehle wie p *module_list, p *module_list->next und p *chrdevs[4]->fops verwenden, um an Strukturen heranzukommen. Diese Operationen sind vor allem dann hilfreich, wenn Sie die Symboltabelle des Kernels und den Quellcode parat haben.

Eine weitere nützliche Funktion von gdb ist das Disassemblieren von Funktionen im laufenden Kernel mit dem disassemble-Befehl (der auch als disass abgekürzt werden kann) oder mit dem Befehl zum Anzeigen von Maschinenanweisungen (x/i). Der Befehl disassemble erwartet als Argumente entweder einen Funktionsnamen oder einen Speicherbereich, während x/i eine Speicheradresse, ebenfalls in Form eines Symbolnamens, benötigt. Sie können beispielsweise mit x/20i zwanzig Anweisungen disassemblieren. Beachten Sie, daß Sie eine Modulfunktion nicht disassemblieren können, denn der Debugger arbeitet auf der Datei vmlinux, die von Ihrem Modul nichts weiß. Wenn Sie versuchen, ein Modul unter Angabe seiner Adresse zu disassemblieren, wird gdb höchstwahrscheinlich mit “Cannot access memory at xxxx” antworten. Aus dem gleichen Grund können Sie auch keine Moduldaten ansehen. Wenn Sie die Adresse der Variablen kennen, können diese aus /dev/mem ausgelesen werden, aber es ist schwierig, die aus dem System-RAM ausgelesenen Daten zu interpretieren.

Wenn Sie eine Modulfunktion disassemblieren wollen, sollten Sie besser das Hilfsprogramm objdump verwenden. Unglücklicherweise arbeitet dieses Programm auf der Festplattenkopie der Datei und nicht auf der laufenden. Daher sind die von objdump angezeigten Adressen die Adressen vor der Relozierung und haben nichts mit der Ausführungsumgebung des Moduls zu tun. Ein weiterer Nachteil beim Disassemblieren der ungelinkten Objektdatei besteht darin, daß noch kein Funktionsaufruf aufgelöst ist, so daß es nicht so leicht ist, einen printk-Aufruf von einem kmalloc-Aufruf zu unterscheiden.

Wie Sie sehen, ist gdb ein nützliches Werkzeug, wenn Sie in einen laufenden Kernel hineinschauen wollen, aber es fehlen doch noch einige Funktionen, die man zum Debuggen von Gerätetreibern dringend braucht.

Der Kernel-Debugger kdb

Viele Leser fragen sich vielleicht, warum keine besseren Debugging-Möglichkeiten in den Kernel eingebaut sind. Die Antwort lautet schlicht und einfach, daß Linus nichts von interaktiven Debuggern hält. Er befürchtet, daß diese zu schlechten Fixes führen, die nur Symptome kurieren, anstatt die eigentliche Ursache des Problems zu beheben. Also gibt es keine eingebauten Debugger.

Andere Kernel-Entwickler hätten aber schon von Zeit zu Zeit ganz gern einmal interaktive Debugging-Werkzeuge. Ein solches Werkzeug ist der eingebaute Kernel-Debugger kdb, der als nicht-offizieller Patch von oss.sgi.com heruntergeladen werden kann. Um kdb verwenden zu können, müssen Sie sich diesen Patch holen (stellen Sie sicher, daß Sie eine Version haben, die zu Ihrer Kernel-Version paßt), diesen anwenden und den Kernel neu bauen und installieren. Beachten Sie, daß kdb derzeit nur für IA-32-(x86)-Systeme existiert (auch wenn eine IA-64-Version für einige Zeit in den Haupt-Kernel-Quellen vorhanden war, bis sie entfernt wurde).

Wenn Sie einen kdb-fähigen Kernel verwenden, gibt es einige Möglichkeiten, den Debugger zu starten. Das Drücken der Pause- (oder Break-)Taste auf der Konsole startet den Debugger. kdb startet auch, wenn ein Kernel-Oops auftritt oder wenn ein Breakpoint getroffen wird. In allen Fällen bekommen Sie eine Meldung wie die folgende:

Entering kdb (0xc1278000) on processor 1 due to Keyboard Entry
[1]kdb>

Beachten Sie, daß so ziemlich alles im Kernel anhält, während kdb läuft. Es sollte nichts auf einem System laufen, wenn Sie kdb aufrufen, insbesondere sollte das Netzwerk abgeschaltet sein (selbstverständlich nicht, wenn Sie einen Netzwerktreiber debuggen). Es ist im allgemeinen eine gute Idee, das System im Single User-Modus zu booten, wenn Sie kdb verwenden wollen.

Als Beispiel schauen wir uns eine schnelle Debugging-Sitzung mit scull an. Nehmen wir an, daß der Treiber bereits geladen ist. Dann können wir kdb mit folgendem Befehl veranlassen, einen Breakpoint in scull_read zu setzen:

[1]kdb> bp scull_read
Instruction(i) BP #0 at 0xc8833514 (scull_read)
    is enabled on cpu 1
[1]kdb> go

Der Befehl bp weist kdb an, anzuhalten, wenn der Kernel das nächste Mal in die Funktion scull_read gelangt. Danach setzen wir die Ausführung mit go fort. Nachdem wir etwas in eines der scull-Geräte geschrieben haben, können wir in einer Shell auf einem anderen Terminal cat ausführen, um das folgende Ergebnis zu bekommen:

Entering kdb (0xc3108000) on processor 0 due to Breakpoint @ 0xc8833515
Instruction(i) breakpoint #0 at 0xc8833514
scull_read+0x1:   movl   %esp,%ebp
[0]kdb>

Wir stehen jetzt am Anfang von scull_read. Ein Stack Trace zeigt uns, wie wir dorthin geraten sind:

[0]kdb> bt
    EBP       EIP         Function(args)
0xc3109c5c 0xc8833515  scull_read+0x1
0xc3109fbc 0xfc458b10  scull_read+0x33c255fc( 0x3, 0x803ad78, 0x1000, 0x1000, 0x804ad78)
0xbffffc88 0xc010bec0  system_call
[0]kdb>

kdb versucht, die Argumente aller Funktionen im Stack Trace auszugeben. Optimierungstricks des Compilers können den Debugger aber verwirren. Deswegen werden fünf Argumente bei scull_read ausgegeben, obwohl es nur vier gibt.

Es ist Zeit, sich einige Daten anzuschauen. Der Befehl mds manipuliert Daten; wir können damit den Wert des Zeigers scull_devices pointer abfragen:

[0]kdb> mds scull_devices 1
c8836104: c4c125c0 ....

Wir fragen hier nach einem Datenwort (vier Bytes), das an der Position scull_devices beginnt; die Antwort teilt uns mit, daß unser Geräte-Array ab der Adresse c4c125c0 alloziert worden ist. Um sich die Gerätestruktur selbst anzuschauen, verwenden wir diese Adresse:

[0]kdb> mds c4c125c0
c4c125c0: c3785000  ....
c4c125c4: 00000000  ....
c4c125c8: 00000fa0  ....
c4c125cc: 000003e8  ....
c4c125d0: 0000009a  ....
c4c125d4: 00000000  ....
c4c125d8: 00000000  ....
c4c125dc: 00000001  ....

Die hier gezeigten acht Zeilen entsprechen den acht Feldern in der Struktur Scull_Dev. Wir sehen also, daß der Speicher des ersten Geräts ab der Adresse 0xc3785000 alloziert ist, daß es kein weiteres Element in der Liste gibt, daß das Quantum 4000 (hex fa0) und die Array-Größe 1000 (hex 3e8) ist, daß es 154 Datenbytes (hex 9a) im Gerät gibt und so weiter.

kdb kann die Daten auch ändern. Wenn wir etwa Daten aus dem Gerät löschen wollen, könnten wir folgendes eingeben:

[0]kdb> mm c4c125d0 0x50
0xc4c125d0 = 0x50

Der nächste cat-Aufruf auf diesem Gerät gibt weniger Daten zurück als vorher.

> > > kdb hat eine Reihe weiterer Fähigkeiten wie Einzelschrittausführung (anweisungsweise, nicht per C-Quellcode-Zeile), Setzen von Breakpoints bei Datenzugriff, Disassemblieren von Code, Durchlaufen verketteter Listen, Zugriff auf Registerdaten und andere. Nach dem Anwenden des kdb-Patches finden Sie die vollständigen Manual-Pages im Verzeichnis Documentation/kdb in den Kernel-Quellen.

Der Integrated Kernel Debugger-Patch

Eine Reihe von Kernel-Entwicklern haben einen inoffiziellen Patch namens Integrated Kernel Debugger oder IKD beigesteuert. IKD liefert eine Reihe nützlicher Funktionen zum Debuggen von Kerneln. x86 ist die Hauptplattform für diesen Patch, aber ein großer Teil davon funktioniert auch auf anderen Architekturen. Sie finden den Patch derzeit unter ftp://ftp.kernel.org/pub/linux/kernel/people/andrea/ikd. Sie müssen ihn auf Ihre Kernel-Quellen anwenden; der Patch ist versionsabhängig; laden Sie also die zu Ihrem Kernel passende Version herunter.

Eines der Features des IKD-Patches ist ein Kernel Stack Debugger. Wenn Sie dieses Feature einschalten, überprüft der Kernel bei jedem Funktionsaufruf die Menge des freien Platzes auf dem Kernel-Stack und erzwingt ein Oops, wenn dieser zu klein wird. Wenn etwas in Ihrem Kernel den Stack durcheinanderbringt, dann können Sie das mit diesem Werkzeug herausfinden. Es gibt auch ein “Stack Meter”, mit dem Sie jederzeit sehen können, wie dicht Sie an die Füllgrenze des Stacks herangekommen sind.

Der IKD-Patch enthält auch Werkzeuge zum Einkreisen von Kernel-Lockups. Ein “Soft Lockup”-Detektor erzwingt ein Oops, wenn eine Kernel-Prozedur zu lange läuft, ohne den Scheduler aufzurufen. Dies wird durch Zählen der Funktionsaufrufe implementiert; wenn diese Zahl einen vorkonfigurierten Grenzwert überschreitet, bricht der Prozeß die Ausführung ab. Ein anderes Feature kann ununterbrochen den Programmzähler auf einer virtuellen Konsole ausgeben; dieses ist das allerletzte Mittel, wenn Sie nach Lockups suchen. Der Semaphor-Deadlock-Detektor erzwingt ein Oops, wenn ein Prozeß zuviel Zeit in einem down-Aufruf verbringt.

Weitere Debugging-Funktionalitäten in IKD sind die Kernel-Trace-Fähigkeit, mit der die Pfade aufgezeichnet werden können, die der Kernel-Code nimmt. Es gibt einige Werkzeuge zum Debuggen des Speichers, darunter einen Leak-Detektor und mehrere “Speichermusterprüfer”, die nützlich sein können, wenn Sie Speicherkorruptionsproblemen auf die Spur kommen wollen.

Schließlich enthält IKD auch eine Version des kdb-Debuggers, den wir im letzten Abschnitt besprochen haben. Derzeit ist die im IKD-Patch enthaltene kdb-Version aber etwas älter. Wenn Sie kdb benötigen, empfehlen wir Ihnen, sich die neueste Version direkt von oss.sgi.com zu holen.

Der kgdb-Patch

kgdb ist ein Patch, der die vollständige Verwendung von gdb auf dem Linux-Kernel erlaubt, allerdings nur auf x86-Systemen. Der Patch hakt sich in das zu debuggende System über eine serielle Leitung ein, auf deren anderem Ende gdb läuft. Sie brauchen also zwei Systeme, um kgdb verwenden zu können: eines, um den Debugger laufen zu lassen, und eines, das den zu debuggenden Kernel enthält. Wie kdb kann auch kgdb von oss.sgi.com heruntergeladen werden.

Das Einrichten von kgdb erfordert das Einspielen eines Kernel-Patches und das Booten des geänderten Kernels. Sie müssen die beiden Systeme mit einem seriellen Kabel (einem Null-Modem-Kabel) verbinden und einige Hilfsdateien auf der gdb-Seite der Verbindung installieren. Der Patch enthält detaillierte Anweisungen in der Datei Documentation/i386/gdb-serial.txt; wir drucken diese hier nicht ab. Lesen Sie sich auf jeden Fall die Anweisungen zum Debuggen von Modulen durch; gegen Ende finden Sie einige nützliche gdb-Makros, die genau zu diesem Zweck geschrieben worden sind.

Kernel Crash Dump Analyzer

Crash Dump Analyzer ermöglichen es dem System, seinen Zustand aufzuzeichnen, wenn ein Oops auftritt, so daß der Zustand hinterher nach Belieben analysiert werden kann. Dies kann besonders nützlich sein, wenn Sie es mit einem Treiber eines Benutzers an einem anderen Ort zu tun haben. Viele Benutzer wollen nicht gern Oops-Meldungen abschreiben, so daß Sie durch die Installation eines solchen Systems Informationen über das Problem des Benutzers bekommen können, ohne daß dieser dazu einen Finger rühren muß. Es ist daher auch nicht erstaunlich, daß die verfügbaren Crash Dump Analyzer von Firmen geschrieben worden sind, die Support für Benutzersysteme anbieten.

Es gibt derzeit zwei Crash Dump Analyzer-Patches für Linux. Beide waren relativ neu, als wir diesen Abschnitt geschrieben haben, und befanden sich noch mitten in der Entwicklung. Anstatt hier vermutlich veraltete Informationen zu präsentieren, beschränken wir uns darauf, Ihnen einen Überblick zu geben und auf weitere Informationsquellen zu verweisen.

Der erste Analyzer ist LKCD (Linux Kernel Crash Dumps). Auch dieses Programm stammt von oss.sgi.com. Wenn ein Kernel-Oops auftritt, schreibt LKCD eine Kopie des aktuellen Systemzustands (hauptsächlich den Speicher) in das Dump-Gerät, das Sie vorher angegeben haben. Dieses muß ein System-Swap-Bereich sein. Ein Hilfsprogramm namens LCRASH wird nach dem nächsten Neustart (vor dem Einschalten des Swapping) ausgeführt, um eine Zusammenfassung des Crashs zu erzeugen und optional eine Kopie des Auszugs in einer konventionellen Datei zu speichern. LCRASH kann interaktiv ausgeführt werden und liefert eine Reihe von Debugger-artigen Befehlen zum Abfragen des Systemzustands.

LKCD wird derzeit nur für die Intel-32-Bit-Architektur unterstützt und funktioniert nur mit Swap-Partitionen auf SCSI-Festplatten.

Ein weiteres Crash Dump-Programm finden Sie auf www.missioncriticallinux.com. Dieses erzeugt Crash Dump-Dateien direkt in /var/dumps und verwendet den Swap-Bereich nicht. Dies macht manches einfacher, bedeutet aber auch, daß das System das Dateisystem zu einem Zeitpunkt modifizieren muß, zu dem schon etwas schiefgegangen ist. Die erzeugten Crash Dumps liegen im Standardformat für Core-Dateien vor; Werkzeuge wie gdb können also für die Post-Mortem-Analyse verwendet werden. Dieses Package enthält auch einen separaten Analyzer, der mehr Informationen als gdb aus Crash Dump-Dateien extrahieren kann.

Die User-Modus-Linux-Portierung

User-Modus-Linux ist ein interessantes Konzept. Es ist als separate Portierung des Linux-Kernels mit eigenem arch/um-Unterverzeichnis strukturiert. Es läuft aber nicht auf einer neuen Art von Hardware, sondern als virtuelle Maschine, die unter Verwendung der Linux-Systemaufrufe implementiert ist. User-Modus-Linux erlaubt es dem Linux-Kernel also, als separater Prozeß im User-Modus auf einem Linux-System zu laufen.

Die Verfügbarkeit einer Kernel-Kopie, die im User-Modus läuft, bringt eine Reihe von Vorteilen mit sich. Weil es sich um einen beschränkten, virtuellen Prozessor handelt, kann ein fehlerhafter Kernel nicht das "richtige" System zerstören. Verschiedene Hardware- und Software-Konfigurationen können leicht auf dem gleichen Rechner ausprobiert werden. Und, was vielleicht am wichtigsten für Kernel-Entwickler ist, der User-Modus-Kernel kann leicht mit gdb oder einem anderen Debugger manipuliert werden — schließlich ist er einfach nur ein weiterer Prozeß. User-Modus-Linux hat eindeutig das Potential, die Kernel-Entwicklung zu beschleunigen.

Derzeit wird User-Modus-Linux nicht im normalen Kernel mitgeliefert, sondern muß separat von http://user-mode-linux.sourceforge.net heruntergeladen werden. Es heißt, daß User-Modus-Linux in eine der 2.4-Versionen nach 2.4.0 integriert werden soll; das könnte schon der Fall sein, wenn Sie dies lesen.

User-Modus-Linux weist derzeit auch noch einige wesentliche Einschränkungen auf, von denen die meisten sicherlich bald behoben werden. Der virtuelle Prozessor arbeitet derzeit nur im Einzelprozessor-Modus; die Portierung läuft problemlos auf einem SMP-System, kann aber nur einen Einzelprozessor-Host emulieren. Das größte Problem für Treiber-Autoren ist aber, daß der User-Modus-Kernel keinen Zugriff auf die Hardware des Host-Systems hat. Er kann daher zwar nützlich sein, um die meisten der Beispiel-Treiber in diesem Buch zu debuggen, aber nicht für Treiber verwendet werden, bei denen es um echte Hardware geht. Schließlich gibt es User-Modus-Linux nur für die IA-32-Architektur.

Weil an all diesen Problemen bereits gearbeitet wird, wird User-Mode-Linux in naher Zukunft ein unverzichtbares Werkzeug für Programmierer von Linux-Gerätetreibern sein.

Das Linux Trace Toolkit

Das Linux Trace Toolkit (LTT) ist ein Kernel-Patch samt dazugehörigen Hilfsprogrammen, mit denen Ereignisse im Kernel verfolgt werden können. Der Trace enthält Timing-Informationen und kann ein ziemlich vollständiges Bild darüber liefern, was zu einem bestimmten Zeitpunkt passiert ist. Daher kann LTT nicht nur zum Debuggen, sondern auch zum Einkreisen von Performance-Problemen verwendet werden.

LTT finden Sie zusammen mit einer ausführlichen Dokumentation unter www.opersys.com/LTT.

Dynamic Probes

Dynamic Probes (oder DProbes) ist ein Debugging-Werkzeug, das von IBM unter der GPL für die IA-32-Architektur freigegeben wurde. Es erlaubt das Einsetzen einer “Sonde” an fast jeder Stelle im System, sowohl im User als auch im Kernel-Space. Die Sonde besteht aus Code (der in einer speziellen, Stack-orientierten Sprache geschrieben wird), der ausgeführt wird, wenn die jeweilige Stelle erreicht wird. Dieser Code kann Informationen an den User-Space zurückliefern, Register ändern oder eine Reihe anderer Dinge tun. DProbes ist deswegen so nützlich, weil Sonden ohne ein Neukompilieren des Kernels oder ein Rebooten an beliebigen Stellen in einem laufenden System eingefügt werden können, wenn DProbes einmal in den Kernel eingebaut worden ist. DProbes kann auch mit dem Linux Trace Toolkit zusammenarbeiten, um neue Tracing-Ereignisse an beliebigen Stellen einzusetzen.

> > DProbes kann vom IBMs Open Source-Site oss.software.ibm.com heruntergeladen werden.