Handbuch zur dynamischen Ablaufverfolgung in Solaris

Der Provider pid

Der Provider pid ermöglicht die Ablaufverfolgung beliebiger Anweisungen in einem Prozess. Anders als mit den meisten anderen Providern, werden pid-Prüfpunkte nach Bedarf und gemäß den in den D-Programmen enthaltenen Prüfpunktbeschreibungen erzeugt. Deshalb sind in der Ausgabe von dtrace -l keine pid-Prüfpunkte aufgeführt, die Sie nicht selbst aktivieren.

Ablaufverfolgung von Benutzerfunktionsgrenzen

Am einfachsten kann der Provider pid als Gegenstück des Providers fbt für den Benutzerraum eingesetzt werden. Das folgende Beispielprogramm verfolgt jeden Eintritt in eine und Rückkehr aus einer einzigen Funktion. Die Makrovariable $1 (erster Operand in der Befehlszeile) ist die Prozess-ID des zu überwachenden Prozesses. Die Makrovariable $2 (zweiter Operand in der Befehlszeile) ist der Name der Funktion, aus der alle Funktionsaufrufe verfolgt werden sollen.


Beispiel 33–1 userfunc.d: Ablaufverfolgung von Eintritt in und Rückkehr aus einer Benutzerfunktion

pid$1::$2:entry
{
	self->trace = 1;
}

pid$1::$2:return
/self->trace/
{
	self->trace = 0;
}

pid$1:::entry,
pid$1:::return
/self->trace/
{
}

Geben Sie das obige Beispielskript ein und speichern Sie es in einer Datei namens userfunc.d. Machen Sie es dann mit chmod ausführbar. Das Skript produziert eine Ausgabe wie im folgenden Beispiel:


# ./userfunc.d 15032 execute
dtrace: script './userfunc.d' matched 11594 probes
  0  -> execute
  0    -> execute
  0      -> Dfix
  0      <- Dfix
  0      -> s_strsave
  0        -> malloc
  0        <- malloc
  0      <- s_strsave
  0      -> set
  0        -> malloc
  0        <- malloc
  0      <- set
  0      -> set1
  0        -> tglob
  0        <- tglob
  0      <- set1
  0      -> setq
  0        -> s_strcmp
  0        <- s_strcmp
...

Der Provider pid kann nur auf bereits laufende Prozesse angewendet werden. Mit der Makrovariable $target (siehe Kapitel 15Scripting) und den dtrace-Optionen -c und -p lassen sich gewünschte Prozesse erzeugen und fassen (grab) und mit DTrace instrumentieren. Mit dem folgenden D-Skript können Sie beispielsweise die Verteilung der von einem bestimmten Subjektprozess ausgeführten libc-Aufrufe ermitteln:

pid$target:libc.so::entry
{
	@[probefunc] = count();
}

Um die Verteilung derartiger vom Befehl date(1) ausgeführter Aufrufe zu ermitteln, speichern Sie das Skript in der Datei libc.d und führen folgenden Befehl aus:


# dtrace -s libc.d -c date
dtrace: script 'libc.d' matched 2476 probes
Fri Jul 30 14:08:54 PDT 2004
dtrace: pid 109196 has exited

  pthread_rwlock_unlock                                             1
  _fflush_u                                                         1
  rwlock_lock                                                       1
  rw_write_held                                                     1
  strftime                                                          1
  _close                                                            1
  _read                                                             1
  __open                                                            1
  _open                                                             1
  strstr                                                            1
  load_zoneinfo                                                     1

...
  _ti_bind_guard                                                   47
  _ti_bind_clear                                                   94

Ablaufverfolgung beliebiger Anweisungen

Mit dem Provider pid können beliebige Anweisungen in beliebigen Benutzerfunktionen verfolgt werden. Dazu erzeugt der Provider pid nach Bedarf für jede Anweisung in einer Funktion einen Prüfpunkt. Der Name jedes Prüfpunkt entspricht dem Versatz der entsprechenden Anweisung in der Funktion, ausgedrückt durch eine Hexadezimalzahl. Um beispielsweise einen Prüfpunkt für die Anweisung an Versatz 0x1c in der Funktion foo des Moduls bar.so des Prozesses mit der PID 123 zu aktivieren, könnten Sie den folgenden Befehl eingeben:


# dtrace -n pid123:bar.so:foo:1c

Wenn Sie alle Prüfpunkte in der Funktion foo, einschließlich des Prüfpunkts für jede Anweisung, aktivieren möchten, können Sie den folgenden Befehl verwenden:


# dtrace -n pid123:bar.so:foo:

Dieser Befehl stellt eine äußerst leistungsfähige Technik zum Debuggen und Analysieren von Benutzeranwendungen dar. Seltene Fehler sind mitunter nicht leicht zu erkennen und zu beheben, da sie sich nur schwer reproduzieren lassen. Häufig kann ein Problem erst nach dem Auftreten einer Störung identifiziert werden - zu spät, um den Codepfad zu rekonstruieren. Das folgende Beispiel zeigt, wie sich durch Kombination des Providers pid mit spekulativer Ablaufverfolgung (siehe Kapitel 13Spekulative Ablaufverfolgung) jede Anweisung in einer Funktion verfolgen und das Problem somit lösen lässt.


Beispiel 33–2 errorpath.d: Ablaufverfolgung des Pfads bei Fehler in Benutzerfunktionsaufruf

pid$1::$2:entry
{
	self->spec = speculation();
	speculate(self->spec);
	printf("%x %x %x %x %x", arg0, arg1, arg2, arg3, arg4);
}

pid$1::$2:
/self->spec/
{
	speculate(self->spec);
}

pid$1::$2:return
/self->spec && arg1 == 0/
{
	discard(self->spec);
	self->spec = 0;
}

pid$1::$2:return
/self->spec && arg1 != 0/
{
	commit(self->spec);
	self->spec = 0;
}

Die Ausführung von errorpath.d erzeugt eine Ausgabe wie in folgendem Beispiel:


# ./errorpath.d 100461 _chdir
dtrace: script './errorpath.d' matched 19 probes
CPU     ID                    FUNCTION:NAME
  0  25253                     _chdir:entry 81e08 6d140 ffbfcb20 656c73 0
  0  25253                     _chdir:entry
  0  25269                         _chdir:0
  0  25270                         _chdir:4
  0  25271                         _chdir:8
  0  25272                         _chdir:c
  0  25273                        _chdir:10
  0  25274                        _chdir:14
  0  25275                        _chdir:18
  0  25276                        _chdir:1c
  0  25277                        _chdir:20
  0  25278                        _chdir:24
  0  25279                        _chdir:28
  0  25280                        _chdir:2c
  0  25268                    _chdir:return