strace
Der Shell-Befehl strace zeichnet die Systemaufrufe eines laufenden Anwendungsprogramms bzw. eines Prozesses auf.
Der Befehl ist nur unter Linux vorhanden. Unter Solaris und FreeBSD gibt es stattdessen den Befehl truss.
Konzept
strace protokolliert detailliert sämtliche Abläufe an der Schnittstelle zwischen einem Programm und dem Kernel. Der Kernel bietet seine Leistungen (u. a. die Zuteilung von Rechenzeit) den Prozessen über Systemaufrufe an (u. a. "open()", "close()", "read()" und "write()"). Unter Unix und Linux ist die C-Standard-Bibliothek Libc dafür zuständig, die Systemaufrufe im Userspace bereitzustellen. Andere Bibliotheken und alle Programme müssen über diese Programmierschnittstelle gehen, wenn sie mit dem Betriebssystem, der Hardware oder anderen Prozessen kommunizieren und Daten austauschen wollen. Jeder Prozess setzt im Laufe seines Lebens eine Vielzahl von Systemaufrufen ab. strace gibt darüber Auskunft, ob diese Aufrufe gelingen oder nicht und welche Daten der Kernel und der Prozess dabei austauschen.
---------------------------- | Anwendungsprogramm | ------------------------ | | weitere Bibliotheken | | ---------------------------- | Libc | ---------------------------- <-- Ansatzpunkt von strace | Linux-Kernel | ---------------------------- | Hardware | ----------------------------
strace eignet sich so für mehrere Aufgaben:
Aufgabe | Frage |
---|---|
Debugging eigener und fremder Programme, notfalls auch ohne Zugang zum Quelltext. | Warum arbeitet das Programm nicht so, wie es soll? |
Kennenlernen von Systemaufrufen und gängigen Programmiertechniken. | Wie funktioniert das Zusammenspiel von Programm und Betriebssystem? |
Performance-Untersuchungen, besonders bei Closed Source-Software. | Warum läuft das Programm so langsam? |
Optionen
Option | Beschreibung |
---|---|
-f | Anzeige auch aller Kindprozesse. |
-o file | Protokollierung der Ausgabe von strace in die Datei "file". |
-p <PID> | Anzeige von Informationen zum bereits laufenden Prozess mit der PID "<PID>". |
-v | Mehr Informationen. |
Verwendung
Anzeige der vom Programm "free" aufgerufenen Systemfunktionen (um die Speicherauslastung des Systems zu ermitteln und anschliessend anzuzeigen).
$ strace free
Anzeige der vom Programm "free" geöffneten Dateien. Dabei wird die Ausgabe auf die Funktion "open" eingeschränkt.
$ strace -e trace=open free
Anzeige der vom Programm "free" geöffneten und geschlossenen Dateien. Dabei wird die Ausgabe auf die Funktionen "open" und "close" eingeschränkt.
$ strace -e trace=open,close free
Anzeige der dateirelevanten Informationen bei der Ausführung des Programms "free".
$ strace -e trace=file free
Anzeige der prozessverwaltungsbezogenen Informationen bei der Ausführung des Programms "free".
$ strace -e trace=process free
Anzeige der netzwerkspezifischen Informationen bei der Ausführung des Programms "free".
$ strace -e trace=network free
Aufzeichnung der Funktionsaufrufe der Anwendung "S99siaddae" in der Datei "/tmp/file".
$ strace -o /tmp/file /opt/lib/sisis/siadmin/etc/S99siaddae start
Aufzeichnung der Funktionsaufrufe der Anwendung "S99siaddae" in der Datei "/tmp/file".
$ strace -o /tmp/file /opt/lib/sisis/siadmin/etc/S99siaddae start
Aufzeichnung der Funktionsaufrufe von PID 28756.
$ strace -p 28756
Anzeige einer Tabelle der von Prozess 28756 geöffneten Dateien.
$ lsof -p 28756
Ausgabe der Funktionsaufrufe von Befehl "xyz" in die Datei "file".
$ strace -so -o file xyz
Beispiele
Beobachtung des Shell-Befehls "date"
$ ldd $(which date) linux-gate.so.1 => (0x00fd1000) librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x00929000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00614000) libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00474000) /lib/ld-linux.so.2 (0x00abb000)
Nach Aufruf von "strace date" ist zu sehen, dass die Programmdatei "/bin/date" über einen Systemaufruf von "execve()" gestartet wird. Der Kernel überträgt dem Program Loader die Aufgabe, für das Laden der benötigten Systembibliotheken zu sorgen - "date" benötigt nur die Bibliothek "libc.so.6", also die Glibc - das kann auch das Programm ldd herausfinden.
$ strace date
execve("/bin/date", ["date"], [/* 41 vars */]) = 0 brk(0) = 0x98bf000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7776000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=83275, ...}) = 0 mmap2(NULL, 83275, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7761000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/cmov/librt.so.1", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\30\0\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0644, st_size=30684, ...}) = 0 mmap2(NULL, 33364, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x441000 mmap2(0x448000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6) = 0x448000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0000m\1\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1405508, ...}) = 0 mmap2(NULL, 1415592, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x531000 mprotect(0x684000, 4096, PROT_NONE) = 0 mmap2(0x685000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x153) = 0x685000 mmap2(0x688000, 10664, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x688000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/cmov/libpthread.so.0", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 J\0\0004\0\0\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=117086, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7760000 mmap2(NULL, 98792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x218000 mmap2(0x22d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14) = 0x22d000 mmap2(0x22f000, 4584, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x22f000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb775f000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb775f6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0x22d000, 4096, PROT_READ) = 0 mprotect(0x685000, 8192, PROT_READ) = 0 mprotect(0x448000, 4096, PROT_READ) = 0 mprotect(0x8057000, 4096, PROT_READ) = 0 mprotect(0xd2a000, 4096, PROT_READ) = 0 munmap(0xb7761000, 83275) = 0 set_tid_address(0xb775f728) = 10712 set_robust_list(0xb775f730, 0xc) = 0 futex(0xbf9a4310, FUTEX_WAKE_PRIVATE, 1) = 0 futex(0xbf9a4310, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, bf9a4320) = -1 EAGAIN (Resource temporarily unavailable) rt_sigaction(SIGRTMIN, {0x21c410, [], SA_SIGINFO}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {0x21c8f0, [], SA_RESTART|SA_SIGINFO}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM_INFINITY}) = 0 uname({sys="Linux", node="kanzler", ...}) = 0 brk(0) = 0x98bf000 brk(0x98e0000) = 0x98e0000 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory) open("/usr/share/locale/locale.alias", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7775000 read(3, "# Locale name alias data base.\n#"..., 4096) = 2570 read(3, "", 4096) = 0 close(3) = 0 munmap(0xb7775000, 4096) = 0 open("/usr/lib/locale/de_CH.utf8/LC_IDENTIFICATION", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=353, ...}) = 0 mmap2(NULL, 353, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7775000 close(3) = 0 open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=26048, ...}) = 0 mmap2(NULL, 26048, PROT_READ, MAP_SHARED, 3, 0) = 0xb776e000 close(3) = 0 futex(0x687a8c, FUTEX_WAKE_PRIVATE, 2147483647) = 0 open("/usr/lib/locale/de_CH.utf8/LC_MEASUREMENT", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0 mmap2(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776d000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_TELEPHONE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=49, ...}) = 0 mmap2(NULL, 49, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776c000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_ADDRESS", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0 mmap2(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776b000 open("/usr/lib/locale/de_CH.utf8/LC_NAME", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0 mmap2(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776a000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_PAPER", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0 mmap2(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7769000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_MESSAGES", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7768000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_MONETARY", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=294, ...}) = 0 mmap2(NULL, 294, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7767000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_COLLATE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=1170770, ...}) = 0 mmap2(NULL, 1170770, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7641000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_TIME", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=2382, ...}) = 0 mmap2(NULL, 2382, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7766000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_NUMERIC", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7765000 close(3) = 0 open("/usr/lib/locale/de_CH.utf8/LC_CTYPE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=256484, ...}) = 0 mmap2(NULL, 256484, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7602000 close(3) = 0 clock_gettime(CLOCK_REALTIME, {1290902570, 373229098}) = 0 open("/etc/localtime", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0 fstat64(3, {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7601000 read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\0"..., 4096) = 1892 _llseek(3, -28, [1864], SEEK_CUR) = 0 read(3, "\nCET-1CEST,M3.5.0,M10.5.0/3\n", 4096) = 28 close(3) = 0 munmap(0xb7601000, 4096) = 0 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7601000 write(1, "Son Nov 28 01:02:50 CET 2010\n", 29Son Nov 28 01:02:50 CET 2010 ) = 29 close(1) = 0 munmap(0xb7601000, 4096) = 0 close(2) = 0 exit_group(0) = ?
Weblinks
Herausgeber | Sprache | Webseitentitel | Anmerkungen |
---|---|---|---|
Wikipedia | eng | stracewbm | Enzyklopädischer Artikel |