Die Ablaufverfolgung des Stacks eines Prozess-Threads zum Zeitpunkt der Aktivierung eines bestimmten Prüfpunkts gibt häufig sehr gründlich Aufschluss über ein Problem. Die Aktion ustack() dient zur Ablaufverfolgung des Stacks eines Benutzer-Threads. Wenn beispielsweise ein Prozess, der zahlreiche Dateien öffnet, gelegentlich beim open(2)-Systemaufruf scheitert, können Sie mit der Aktion ustack() den Codepfad ermitteln, der den fehlgeschlagenen open() ausführt:
syscall::open:entry /pid == $1/ { self->path = copyinstr(arg0); } syscall::open:return /self->path != NULL && arg1 == -1/ { printf("open for '%s' failed", self->path); ustack(); }
Dieses Skript veranschaulicht auch die Verwendung der Makrovariable $1, die den Wert des ersten in der dtrace(1M)-Befehlszeile angegebenen Operanden annimmt:
# dtrace -s ./badopen.d 31337 dtrace: script './badopen.d' matched 2 probes CPU ID FUNCTION:NAME 0 40 open:return open for '/usr/lib/foo' failed libc.so.1`__open+0x4 libc.so.1`open+0x6c 420b0 tcsh`dosource+0xe0 tcsh`execute+0x978 tcsh`execute+0xba0 tcsh`process+0x50c tcsh`main+0x1d54 tcsh`_start+0xdc |
Die Aktion ustack() zeichnet Programmzählerwerte (PC) für den Stack auf und dtrace(1M) löst diese PC-Werte anhand der Symboltabellen des Prozesses in Symbolnamen auf. Kann dtrace einen PC-Wert nicht in ein Symbol auflösen, wird der Wert als Hexadezimalzahl ausgegeben.
Wenn ein Prozess bereits vor der Formatierung der ustack()-Daten für die Ausgabe vorhanden ist oder mit kill abgebrochen wird, kann dtrace die PC-Werte im Stack-Protokoll unter Umständen nicht in Symbolnamen umwandeln und ist gezwungen, sie als Hexadezimalzahlen anzuzeigen. Um diese Einschränkung zu umgehen, übergeben Sie -dtrace mit der Option -c oder p gezielt einen Prozess. Ausführliche Informationen zu diesen und anderen Optionen finden Sie in Kapitel 14Das Dienstprogramm dtrace(1M). Sind Prozess-ID oder Befehl im Voraus nicht bekannt, lässt sich die Einschränkung auch mit folgendem D-Programm umgehen:
/* * This example uses the open(2) system call probe, but this technique * is applicable to any script using the ustack() action where the stack * being traced is in a process that may exit soon. */ syscall::open:entry { ustack(); stop_pids[pid] = 1; } syscall::rexit:entry /stop_pids[pid] != 0/ { printf("stopping pid %d", pid); stop(); stop_pids[pid] = 0; }
Das obige Skript hält einen Prozess kurz vor dessen Beendigung an, wenn die Aktion ustack() auf einen Thread in diesem Prozess angewendet wurde. Diese Technik gewährleistet, dass der Befehl dtrace in der Lage ist, die PC-Werte in symbolische Namen aufzulösen. Beachten Sie, dass der Wert von stop_pids[pid], nachdem er zum Löschen der dynamischen Variable benutzt wurde, 0 beträgt. Denken Sie daran, angehaltene Prozesse mit dem Befehl prun(1) wieder zum Laufen zu bringen. Anderenfalls sammeln sich auf dem System zahlreiche angehaltene Prozesse an.