Handbuch zur dynamischen Ablaufverfolgung in Solaris

Kapitel 4 D-Programmstruktur

D-Programme bestehen aus einem Satz die zu aktivierenden Prüfpunkte beschreibender Klauseln und aus Prädikaten und Aktionen, die an diese Prüfpunkte gebunden werden. D-Programme enthalten auch Variablendeklarationen (siehe Kapitel 3Variablen) und Definitionen neuer Datentypen (siehe Kapitel 8Typ- und Konstantendefinitionen). Dieses Kapitel bietet eine formelle Beschreibung der Gesamtstruktur eines D-Programms und der Leistungsmerkmale zur Erstellung von Prüfpunktbeschreibungen, die auf mehrere Prüfpunkte zutreffen. Darüber hinaus wird der Einsatz des C-Preprozessors cpp in D-Programmen besprochen.

Prüfpunktklauseln und Deklarationen

Wie mit unseren bisherigen Beispielen gezeigt, besteht die Quelldatei eines D-Programms aus mindestens einer Prüfpunktklausel, mit der Sie die von DTrace zu aktivierende Instrumentation beschreiben. Eine Prüfpunktklausel hat die allgemeine Form:

Prüfpunktbeschreibungen
/ Prädikat
/ {
Aktionsanweisungen
}

Das Prädikat und die Liste der Aktionsanweisungen können ausgelassen werden. Sämtliche Anweisungen außerhalb von Prüfpunktklauseln werden als Deklarationen bezeichnet. Deklarationen dürfen nur außerhalb von Prüfpunktklauseln stehen. Deklarationen sind weder innerhalb der geschweiften Klammern { } noch eingestreut zwischen die o. g. Elemente der Prüfpunktklausel zulässig. Leerstellen dürfen zum Trennen beliebiger D-Programmelemente und zum Einrücken von Aktionsanweisungen verwendet werden.

Mit Deklarationen können Sie entweder D-Variablen und externe C-Symbole deklarieren (siehe Kapitel 3Variablen) oder neue Typen für die Verwendung in D definieren (siehe Kapitel 8Typ- und Konstantendefinitionen). Spezielle D-Compiler-Anweisungen, die so genannten Pragmas, können ebenfalls an jeder beliebigen Stelle in einem D-Programm, einschließlich außerhalb von Prüfpunktklauseln, stehen. D-Pragmas werden in Zeilen mit einleitendem #-Zeichen angegeben. Sie dienen beispielsweise zum Setzen von DTrace-Laufzeitoptionen. Näheres hierzu finden Sie in Kapitel 16Optionen und Tunables .

Prüfpunktbeschreibungen

Jede D-Programmklausel beginnt mit einer Liste von einer oder mehreren Prüfpunktbeschreibungen in der üblichen Form:

Provider:Modul: Funktion:Name

Wenn eines oder mehrere Felder der Prüfpunktbeschreibung ausgelassen wird, werden die angegebenen Felder vom D-Compiler von rechts nach links interpretiert. So würde beispielsweise die Prüfpunktbeschreibung foo:bar unabhängig von dem Wert der Provider- und Modulfelder auf einen Prüfpunkt mit der Funktion foo und dem Namen bar zutreffen. Aus diesem Grund ist eine Prüfpunktbeschreibung tatsächlich eher als ein Muster zu betrachten, das zur Bezugnahme auf einen oder mehrere Prüfpunkte anhand ihrer Namen dient.

Es empfiehlt sich, in der D-Prüfpunktbeschreibung alle vier Feldtrenner zu verwenden, sodass Sie auf der linken Seite den gewünschten Provider angeben können. Bei Verzicht auf die Angabe eines Providers erhalten Sie möglicherweise unerwartete Resultate, wenn mehrere Provider Prüfpunkte mit demselben Namen veröffentlichen. Ebenso ist es nicht auszuschließen, dass zukünftige Versionen von DTrace neue Provider enthalten, deren Prüfpunkte zufällig mit den von Ihnen nur teilweise angegebenen Prüfpunktbeschreibungen übereinstimmen. Um einen Provider mit all seinen Prüfpunkten anzugeben, lassen Sie die Modul-, Funktions- und Namensfelder leer. So können Sie beispielsweise mit der Beschreibung syscall::: jeden von dem DTrace-Provider syscall veröffentlichten Prüfpunkt ansprechen.

Prüfpunktbeschreibungen unterstützen auch eine Mustervergleichssyntax wie die in sh(1) beschriebene Globbing-Syntax. Bevor DTrace einen Prüfpunkt für eine Beschreibung einsetzt, werden alle Beschreibungsfelder nach den Zeichen *, ? und [ durchsucht. Wenn eines dieser Zeichen in einem Feld der Prüfpunktbeschreibung ohne vorangestelltes \-Zeichen vorkommt, wird das Feld als Suchmuster interpretiert. Das Beschreibungsmuster muss mit dem gesamten entsprechenden Feld eines gegebenen Prüfpunkts übereinstimmen. Um einen Prüfpunkt erfolgreich zu identifizieren und zu aktivieren, muss die vollständige Prüfpunktbeschreibung in jedem Feld übereinstimmen. Ein Prüfpunktbeschreibungsfeld, bei dem es sich nicht um ein Suchmuster handelt, muss exakt mit dem entsprechenden Feld des Prüfpunkts übereinstimmen. Leere Beschreibungsfelder treffen auf alle Prüfpunkte zu.

In Suchmustern für Prüfpunktnamen werden die Sonderzeichen in folgender Tabelle erkannt:

Tabelle 4–1 Mustervergleichszeichen für Prüfpunktnamen

Symbol 

Beschreibung 

*

Trifft auf jede Zeichenkette einschließlich der Null-Zeichenkette zu. 

?

Trifft auf jedes Einzelzeichen zu. 

[ ... ]

Trifft auf jedes der eingeklammerten Zeichen zu. Ein durch - getrenntes Zeichenpaar trifft auf jedes Zeichen zwischen den beiden Zeichen (einschließlich dieser) zu. Wenn das erste Zeichen nach der öffnenden Klammer [ ein ! ist, besteht Übereinstimmung mit allen nicht im Satz enthaltenen Zeichen.

\

Das nächste Zeichen wird ohne Sonderbedeutung in seiner normalen Bedeutung interpretiert. 

Mustervergleichszeichen können in beliebigen oder allen vier Feldern einer Prüfpunktbeschreibung verwendet werden. Mit dtrace - l können Sie Suchmuster für übereinstimmende Prüfpunkte auch in der Befehlszeile angeben. Beispielsweise listet der Befehl dtrace -l -f kmem_* alle DTrace-Prüfpunkte in Funktionen auf, deren Namen mit dem Präfix kmem_ beginnen.

Wenn Sie dasselbe Prädikat und dieselben Aktionen für mehrere Prüfpunktbeschreibungen oder Beschreibungsmuster angeben möchten, können Sie die Beschreibungen durch Kommata getrennt auflisten. So würde beispielsweise das folgende D-Programm bei jeder Auslösung von Prüfpunkten im Zusammenhang mit dem Eintritt in Systemaufrufe, die die Wörter „lwp” oder „sock” enthalten, eine Zeitmarke protokollieren:

syscall::*lwp*:entry, syscall::*sock*:entry
{
	trace(timestamp);
}

Prüfpunkte können in Prüfpunktbeschreibungen auch anhand ihrer ganzzahligen Prüfpunkt-ID angegeben werden. So kann beispielsweise mit der Klausel:

12345
{
	trace(timestamp);
}

der Prüfpunkt mit der ID 12345, der von dtrace -l -i 12345 gemeldet wird, aktiviert werden. Fügen Sie in Ihre D-Programme stets vom Menschen lesbare Prüfpunktbeschreibungen ein. Numerische Prüfpunkt-IDs bleiben über das Einladen und Entfernen der DTrace-Provider-Kernelmodule hinweg oder nach einem Systemneustart möglicherweise nicht unverändert bestehen.

Prädikate

Prädikate sind zwischen Schrägstrichen / / stehende Ausdrücke, die zum Zeitpunkt der Prüfpunktauslösung ausgewertet werden, um festzustellen, ob die zugehörigen Aktionen ausgeführt werden sollen. Prädikate sind das wichtigste bedingte Konstrukt für die Bildung komplexerer Kontrollflüsse in einem D-Programm. Sie können für jeden Prüfpunkt den Prädikatteil der Prüfpunktklausel ganz auslassen. In diesem Fall werden die Aktionen bei der Auslösung des Prüfpunkts immer ausgeführt.

Prädikatausdrücke akzeptieren alle bisher beschriebenen D-Operatoren und können sich auf beliebige D-Datenobjekte wie zum Beispiel Variablen und Konstanten beziehen. Der Prädikatausdruck muss einen Wert des Integer- oder Zeigertyps ergeben, sodass er als wahr oder falsch interpretiert werden kann. Wie bei allen D-Ausdrücken wird ein Nullwert als falsch und ein Wert ungleich Null als wahr interpretiert.

Aktionen

Die Beschreibung von Prüfpunktaktionen erfolgt in Form einer Liste durch Strichpunkt (;) getrennter Anweisungen in geschweiften Klammern { }. Wenn Sie nur feststellen möchten, ob ein bestimmter Prüfpunkt auf einer bestimmten CPU ausgelöst wurde, ohne Daten zu verfolgen oder zusätzliche Aktionen durchzuführen, können Sie ein leeres geschweiftes Klammernpaar ohne darin enthaltene Anweisungen angeben.

Einsatz des C-Preprozessors

Die Programmiersprache C, in der die Solaris-Systemschnittstellen definiert sind, umfasst einen Preprozessor, der einige Anfangsschritte bei der C-Programmkompilierung durchführt. Der C-Preprozessor wird in der Regel zum Definieren von Makroersetzungen, bei denen ein Symbol (Token) in einem C-Programm durch einen vordefinierten Satz anderer Symbole ersetzt wird, oder zum Anlegen von Kopien der Systemdefinitionsdateien verwendet. Wenn Sie den C-Preprozessor in Verbindung mit den D-Programmen verwenden möchten, geben Sie die dtrace-Option -C an. Diese Option bewirkt, dass dtrace zuerst den cpp(1)-Preprozessor auf Ihrer Programmquelldatei ausführt und die Ergebnisse dann an den D-Compiler weiterleitet. Eine ausführlichere Beschreibung des C-Preprozessors finden Sie in Programmieren in C.

Der D-Compiler lädt die C-Typbeschreibungen für die entsprechende Betriebssystemimplementierung zwar automatisch ein, doch mit dem Preprozessor haben Sie die Möglichkeit, weitere Typdefinitionen wie zum Beispiel Typen aus eigenen C-Programmen einzubinden. Der Preprozessor bietet sich auch für andere Vorgänge wie etwa die Erstellung von Makros an, die sich durch D-Codechunks und andere Programmelemente ersetzen lassen. Wenn Sie den Preprozessor für ein D-Programm verwenden, dürfen Sie nur Dateien mit gültigen D-Deklarationen aufnehmen. Typische C-Definitionsdateien laden nur externe Deklarationen von Typen und Symbolen, die der D-Compiler fehlerfrei interpretiert. Der D-Compiler kann C-Definitionsdateien mit zusätzlichen Programmelementen wie C-Funktionsquellcode nicht analysieren und generiert in diesen Fällen eine entsprechende Fehlermeldung.