Bitte oder Registrieren, um Beiträge und Themen zu erstellen.

strace ..... ein Lieblingsprogramm von mir

Was soll ich sagen, es ist und bleibt DAS Lieblingsprogramm von mit. Wann immer ich ein Problem mit irgend einer Software habe, schaue ich mir mit strace an, was das Programm so macht. Wenn man dann den source-Code zur Hand hat könnte es passieren, dass das Problem ruckzuck keines mehr ist.

Ich lernte strace auf der SUN-Sparc kennen und schätzen.

Was kann strace?

strace protokolliert alle Systemaufrufe (syscall) und auch die Aufrufparameter. Damit kann man erkennen, was so innerhalb des Programmes passiert. Aber auch welche Programmsprünge ein Programmierer eingebaut hat.

Das Programm wird bei der Systeminstallation mitinstalliert und ist sofort abrufbereit. Aber Achtung: es werden viele Informationen gesammelt und durch das permanente Unterbrechen des Ablaufes kommt es zu Performanceverlust am mitgetraceten Programm.

Das erste Beispiel

strace ls

Die Ausgabe erfolgt dann auf stderr auf den Bildschirm und schaut so aus.

execve("/usr/bin/ls", ["ls"], 0x7ffebdeb98d0 /* 43 vars */) = 0
brk(NULL)                               = 0x560639e12000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa220e2e000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=134971, ...}) = 0
mmap(NULL, 134971, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa220e0d000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113>1"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=202984, ...}) = 0
mmap(NULL, 210640, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa220dd9000
mmap(0x7fa220de0000, 131072, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7fa220de0000
mmap(0x7fa220e00000, 36864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x27000) = 0x7fa220e00000
mmap(0x7fa220e09000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x30000) = 0x7fa220e09000
mmap(0x7fa220e0b000, 5840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa220e0b000
close(3)       

wollen wir uns jetzt die Daten etwas genauer anschauen.

execve("/usr/bin/ls", ["ls"], 0x7ffebdeb98d0 / 43 vars /) = 0
brk(NULL) = 0x560639e12000

Wenn wir jetzt in den Man-Pages mittels "man execver" nachschauen, dann finden wir das diese Routine zuständig ist für den Start eines Programmes u.a. auch für die Übergabeparameter.

*mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa220e2e000 *

Man mmap diese Funktion verrät uns;

"DESCRIPTION
mmap() creates a new mapping in the virtual address space of the calling
process. The starting address for the new mapping is specified in addr.
The length argument specifies the length of the mapping (which must be
greater than 0)."

Also kurz gesagt man kann damit, Speicherbereiche anfordern Die nächste Routine prüft ob man eine Datei öffnen kann.

"access("/etc/ld.so.preload", R_OK) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)"

Und hier wird es spannend.

Ein Returncode wird ausgegeben. -1 was soviel wie "nicht vorhanden"" bedeutet. Oder für die Gurus ENOENT. Für alle die in den Guru-Status hineinwachsen wollen, denen sei das Kommando "

errno -l

ans Herz gelegt. Das Programm muss allerdings vorher installiert werden

sudo apt install moreutils

erledigt das. Der Returncode wird pro Funktion definiert und gilt für diese eine Funtion. Üblich sind Returncode 0 als OK und beendet. ein Returncode ungleich 0 z.B -1 deutet auf einen Fehler hin. Im Terminal kann man den Returncode über die Variable $? abfragen.

ls /tmp/murksi ; echo " der Returncode = $? "

openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=134971, ...}) = 0

Diese Zeile erzählt uns, dass eine "Datei" geöffnet wurde und die fstat-routine positioniert einen Zeiger auf eine bestimmte Stelle. Wir werden dann in weiterer Folge read, write, fstat Befehle finden gefolgt von mmap und ähnlichem.

Jetzt muss ich noch etwas über die Philosophie von Unix plaudern. Und wenn mich alle würgen, ich bleibe bei meiner Aussage: Linux ist nur ein weiteres Unix. Und mit Unix meine ich jenes, das Ken Thompson und Dennis Ritchie begonnen haben zu entwickelt. Also nicht das Markenzeichen von Novell, SCO oder Sun.

Und wie sagte ein Unix-Entwickler, Kollege und Freund einmal zu mir.... "It's allways a file..... " Und bet strace sieht man es.

Und was bedeutet es gerade bei strace. Memory, Netzwerk, Datenräger alles wird im Kern als "Datei" angesprochen. Selbst der Bildschirm ist eine Datei, ebenso die Tastatur und die Maus.

Dazu muss man wissen, dass beim Öffnen einer Datei ein Filedescriptor vergeben werden. Diese Filedescriptoren gelten pro Prozess und werden beim close zbw. bei Prozessende geschlossen. Daher gibt es im Minumum bei Start einen Prozess 3 Filediscriptoren, 0 oder STDIN für Standard-in (meistens die Tastatur) 1 oder STDOUT für die Ausgabe, (meistens/manchmal der Bildschirm.), 2 oder STDERR als Ausgabe des Error-Protokolls.

Ihr habt sicher schon ein Kommando ähnlich

ls /tmp/murksi 2>/tmp/stderror.txt | grep "mu"

gesehen. Wollen wir uns jetzt anschauen was da passiert: ls wurde nur den Dateinamen anzeigen, wenn es die Datei gibt.

  • gibt es die Datei NICHT wird die Fehlermeldung in die Datei stderret.txt geschrieben.
  • gibt es die Datei, wird die Ausgabe (STDOUT) als Eingabe (STDIN) dem grep-Prozess übergeben. (Pipe - Symbole)
  • Dann erfolgt eine Suche im Programm grep nach dem Begriff "mu" in dieser Liste.

Dieser Vorgang wird duch entsprechenden Syscalls erreicht und da kann strace helfen

So wir haben jetzt ein paar Grundlagen geschaffen, die meisten wissen das alles schon. Dann wollen wir uns um den Aufruf von strace kümmern, damit wir uns an die Stelle Programm-Kern vorarbeiten können.

Es gibt eine Menge an Parameter die man anwenden kann. Die wichtigsten als Übersicht.

  • -o Die Angabe von Path und Datei, und alle Ausgaben werden in diese Datei geschrieben. Aber Achtung das kann viel werden.
  • -p Wenn man eine ProzessID kennt (z.B von top) dann kann man diesen Hintergrundprozess beobachten. Wenn man auch die Kindprozesse beobachten will dann ist die
  • -f Option für die Beobachtung der Kinder notwendig. Damit bekomme ich eine Übersicht was welcher Kindprozess startet/beendet wird.
  • -n gibt die Syscall-Nummer mit aus. Brauchbar wenn man nur etwas sehen oder nicht sehen will.

ansonsten kann ich nur empfehlen, sich die man-page durch zu schauen.

Ach ja für alle, die auch auf anderen Betriebsystemen arbeiten. Unter BSD, Solaris lautet das Programm "truss" auf HP "trusc" und Apple bezeichnet es als dtruss