Jak stosować strace?

273

Kiedyś kolega powiedział mi, że ostatnią opcją, gdy nie udało się debugować wszystkiego w Linuksie, było użycie strace .

Próbowałem poznać naukę stojącą za tym dziwnym narzędziem, ale nie jestem guru administratora systemu i tak naprawdę nie uzyskałem rezultatów.

Więc,

  • Co to dokładnie jest i co robi?
  • Jak iw jakich przypadkach należy go stosować?
  • Jak należy rozumieć i przetwarzać dane wyjściowe?

Krótko mówiąc , jak to działa?

e-satis
źródło
2
strace -p <pid> powie ci, co dzieje się teraz z twoim programem ... szybko i łatwo niż GDB
ernesto
1
Osobiście uważam, man straceże jest bardzo łatwy do odczytania i przydatny. (PS nie wiedział wczoraj o strace i nie jest ekspertem od Linuksa)
Alexander Malakhov
1
„strace jest śledzeniem wywołań systemowych” - pokazuje po prostu, jakie funkcje jądra są wywoływane (wraz z argumentami) w wyniku działania twojego programu.
Pithikos,

Odpowiedzi:

184

Przegląd Strace Strace
może być postrzegane jako lekki debugger. Pozwala programistom / użytkownikom szybko dowiedzieć się, jak program wchodzi w interakcje z systemem operacyjnym. Odbywa się to poprzez monitorowanie połączeń i sygnałów systemowych.

Korzysta
dobrze, gdy nie masz kodu źródłowego lub nie chcesz, abyś naprawdę go przejrzał.
Przydatny także dla własnego kodu, jeśli nie masz ochoty otwierać GDB, ale chcesz zrozumieć interakcje zewnętrzne.

Dobre małe wprowadzenie
Natknąłem się na to wprowadzenie, aby użyć strace innego dnia: strace hello world

John Mulder
źródło
A co jeśli użyjesz czegoś poniżej warstwy, która monitoruje strace?
Pacerier
W takim przypadku @Pacerier sprawdź ltrace stackoverflow.com/a/52012215/5884955
prosti
Doskonale nadaje się do debugowania programów niskiego poziomu, które istnieją tylko / głównie w celu wykonywania interesujących wywołań systemowych lub eksperymentowania z nowymi opcjami wywołań systemowych, aby zobaczyć, co robi Twój system operacyjny. Zasadniczo oszczędza to kłopotów z pisaniem kodu rejestrowania / sprawdzania błędów dla jednorazowych eksperymentów. (Lub jeśli piszesz w asm lub coś, gdzie istnieje duża szansa, że ​​przypadkowo przekazałeś niewłaściwe argumenty lub nawet numer telefonu.) Strace jest znacznie szybsze niż GDB, ponieważ wyszukuje dla ciebie kody errno, np. -EFAULT(Ups, tylko do odczytu bufor) lub -ENOENT(ups, uruchomiono z niewłaściwego katalogu, w którym ścieżka względna nie działała).)
Peter Cordes
62

Krótko mówiąc, strace śledzi wszystkie wywołania systemowe wydane przez program wraz z ich kodami powrotu. Pomyśl o takich rzeczach, jak operacje na plikach / gniazdach i o wiele bardziej niejasne.

Jest to najbardziej przydatne, jeśli masz pewną praktyczną znajomość języka C, ponieważ tutaj wywołania systemowe dokładniej oznaczałyby standardowe wywołania biblioteki C.

Powiedzmy, że twój program to / usr / local / bin / cough. Po prostu użyj:

strace /usr/local/bin/cough <any required argument for cough here>

lub

strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>

zapisać w „pliku_wyjściowym”.

Wszystkie dane wyjściowe strace przejdą do stderr (uwaga, sama objętość często prosi o przekierowanie do pliku). W najprostszych przypadkach Twój program przerwie działanie z błędem i będziesz mógł zobaczyć, gdzie są jego ostatnie interakcje z systemem operacyjnym w wyniku strace.

Więcej informacji powinno być dostępnych w:

man strace
bltxd
źródło
36

strace wyświetla wszystkie wywołania systemowe wykonane przez proces, do którego jest zastosowany. Jeśli nie wiesz, co oznaczają wywołania systemowe, nie będziesz w stanie uzyskać z tego dużego przebiegu.

Niemniej jednak, jeśli twój problem dotyczy plików lub ścieżek lub wartości środowiska, uruchomienie śledzenia w problematycznym programie i przekierowanie danych wyjściowych do pliku, a następnie grepowanie tego pliku dla ciągu ścieżki / pliku / env może pomóc ci zobaczyć, co twój program naprawdę próbuje rób, w odróżnieniu od tego, czego się spodziewałeś.

Asaf Bartow
źródło
7
A w przypadku nietrywialnych programów jest to często jak picie z węża gaśniczego, więc masz wyciętą pracę za przejrzenie wyników ...
dmckee --- były moderator kotek
17
strace <prog_name>do śledzenia programu. strace -o <out_file> <prog_name>
wypisać
8
strace prog 2> & 1 | grep ^ open \ (
eisbaw
10
Lub po prostu: strace -e open myprogLUB dla wszystkich wywołań systemowych związanych z plikami:strace -e file myprog
Amit Naidu
17

Strace wyróżnia się jako narzędzie do badania systemów produkcyjnych, w których nie można sobie pozwolić na uruchomienie tych programów w trybie debuggera. W szczególności zastosowaliśmy strace w następujących dwóch sytuacjach:

  • Program foo wydaje się być w impasie i przestał reagować. Może to być celem gdb; jednak nie zawsze mieliśmy kod źródłowy lub czasami mieliśmy do czynienia z językami skryptowymi, które nie były łatwe do uruchomienia w debuggerze. W takim przypadku uruchamiasz strace na już działającym programie i otrzymujesz listę wywołań systemowych. Jest to szczególnie przydatne, jeśli badasz aplikację klient / serwer lub aplikację, która współdziała z bazą danych
  • Badanie, dlaczego program jest wolny. W szczególności właśnie przenieśliśmy się do nowego rozproszonego systemu plików i nowa przepustowość systemu była bardzo wolna. Możesz określić strace za pomocą opcji „-T”, która powie ci, ile czasu spędzono w każdym wywołaniu systemowym. Pomogło to ustalić, dlaczego system plików powoduje spowolnienie.

Przykład analizy za pomocą strace znajduje się w mojej odpowiedzi na to pytanie .

terson
źródło
15

Cały czas używam strace do debugowania problemów z uprawnieniami. Technika wygląda następująco:

$ strace -e trace=open,stat,read,write gnome-calculator

Gdzie gnome-calculatorjest polecenie, które chcesz uruchomić.

Jeff Sheffield
źródło
8

strace -tfp PID będzie monitorował wywołania systemowe procesu PID, dzięki czemu możemy debugować / monitorować status naszego procesu / programu.

Leslie Zhu
źródło
6

Strace może być używany jako narzędzie do debugowania lub jako prymitywny profiler.

Jako debugger możesz zobaczyć, jak dane wywołania systemowe były wywoływane, wykonywane i co zwracają. Jest to bardzo ważne, ponieważ pozwala zobaczyć nie tylko, że program się nie powiódł, ale DLACZEGO program się nie powiódł. Zwykle wynika to z kiepskiego kodowania, które nie uchwyciło wszystkich możliwych wyników programu. Innym razem są to po prostu zakodowane ścieżki do plików. Bez strachu możesz zgadnąć, co poszło nie tak, gdzie i jak. Dzięki strace otrzymujesz awarię wywołania systemowego, zwykle samo spojrzenie na wartość zwracaną wiele mówi.

Profilowanie to kolejne zastosowanie. Możesz go użyć do wykonania każdego połączenia systemowego osobno lub jako agregację. Chociaż może to nie wystarczyć do rozwiązania problemów, przynajmniej znacznie zawęzi listę potencjalnych podejrzanych. Jeśli widzisz wiele par fopen / close w jednym pliku, prawdopodobnie niepotrzebnie otwierasz i zamykasz pliki przy każdym wykonaniu pętli, zamiast otwierać i zamykać ją poza pętlą.

Ltrace jest bliskim kuzynem Strace'a, również bardzo przydatnym. Musisz nauczyć się odróżniać, gdzie jest twoje wąskie gardło. Jeśli całkowite wykonanie wynosi 8 sekund, a Ty spędzasz tylko 0,05 sekundy na wywołaniach systemowych, wówczas uruchomienie programu nie przyniesie Ci wiele dobrego, problem tkwi w kodzie, co jest zwykle problemem logicznym, lub program faktycznie potrzebuje tak długo biegać.

Największym problemem ze strace / ltrace jest odczyt ich wyników. Jeśli nie wiesz, jak są wykonywane wywołania lub przynajmniej nazwy wywołań systemowych / funkcji, trudno będzie odczytać ich znaczenie. Wiedza na temat zwracanych funkcji może być również bardzo korzystna, szczególnie w przypadku różnych kodów błędów. Chociaż rozszyfrowanie jest uciążliwe, czasami naprawdę zwracają perłę wiedzy; kiedy zobaczyłem sytuację, w której skończyły mi się i-węzły, ale nie zabrakło wolnego miejsca, więc wszystkie zwykłe narzędzia nie dały mi żadnego ostrzeżenia, po prostu nie mogłem utworzyć nowego pliku. Odczytanie kodu błędu z wyjścia strace wskazało mi właściwy kierunek.

Marcin
źródło
4

Strace to narzędzie, które informuje, w jaki sposób aplikacja współpracuje z systemem operacyjnym.

Odbywa się to poprzez informowanie o tym, jakie system operacyjny wywołuje twoja aplikacja i jakie parametry wywołuje.

Na przykład widzisz pliki, które program próbuje otworzyć, i niezależnie od tego, czy połączenie się powiedzie.

Za pomocą tego narzędzia można debugować różnego rodzaju problemy. Na przykład, jeśli aplikacja mówi, że nie może znaleźć biblioteki, o której wiesz, że masz zainstalowaną, strace powie ci, gdzie aplikacja szuka tego pliku.

A to tylko wierzchołek góry lodowej.

Luka Marinko
źródło
to jest bardzo precyzyjne.
prosti
4

Strace jest dobrym narzędziem do nauki, w jaki sposób program wykonuje różne wywołania systemowe (żądania do jądra), a także raportuje te, które się nie powiodły, wraz z wartością błędu związaną z tym niepowodzeniem. Nie wszystkie awarie są błędami. Na przykład kod, który próbuje wyszukać plik, może otrzymać błąd ENOENT (brak takiego pliku lub katalogu), ale może to być dopuszczalny scenariusz w logice kodu.

Dobrym przykładem użycia strace jest debugowanie warunków wyścigu podczas tworzenia pliku tymczasowego. Na przykład program, który może tworzyć pliki przez dołączenie identyfikatora procesu (PID) do określonego łańcucha, może napotykać problemy w scenariuszach wielowątkowych. [PID + TID (identyfikator procesu + identyfikator wątku) lub lepsze wywołanie systemowe, takie jak mkstemp, naprawi to].

Jest także dobry do debugowania awarii. Może ci się przydać ten (mój) artykuł o awariach strace i debugowania .

mohit
źródło
4

Minimalny możliwy do uruchomienia przykład

Jeśli pojęcie nie jest jasne, istnieje prostszy przykład, którego nie widziałeś, który to wyjaśnia.

W tym przypadku przykładem jest niezależny zestaw Linux x86_64 (bez libc) hello world:

przywitania

.text
.global _start
_start:
    /* write */
    mov $1, %rax    /* syscall number */
    mov $1, %rdi    /* stdout */
    mov $msg, %rsi  /* buffer */
    mov $len, %rdx  /* buffer len */
    syscall

    /* exit */
    mov $60, %rax   /* exit status */
    mov $0, %rdi    /* syscall number */
    syscall
msg:
    .ascii "hello\n"
len = . - msg

GitHub w górę .

Złóż i uruchom:

as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out

Wyprowadza oczekiwane:

hello

Teraz użyjmy strace na tym przykładzie:

env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log

Używamy:

strace.log teraz zawiera:

execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6)                  = 6
exit(0)                                 = ?
+++ exited with 0 +++

Przy tak minimalnym przykładzie każdy znak wyjściowy jest oczywisty:

  • execvewiersz: pokazuje sposób stracewykonania hello.out, w tym argumenty CLI i środowisko, zgodnie z dokumentacją wman execve

  • writelinia: pokazuje wykonane przez nas wywołanie systemowe zapisu. 6jest długością łańcucha "hello\n".

    = 6jest zwracaną wartością wywołania systemowego, która zgodnie z dokumentacją man 2 writejest liczbą zapisanych bajtów.

  • exitlinia: pokazuje wykonane przez nas wywołanie systemowe wyjścia. Nie ma wartości zwracanej, ponieważ program został zamknięty!

Bardziej złożone przykłady

Zastosowanie strace ma oczywiście na celu sprawdzenie, które wywołania systemowe faktycznie wykonują złożone programy, aby pomóc w debugowaniu / optymalizacji programu.

Warto zauważyć, że większość wywołań systemowych, które możesz napotkać w Linuksie, ma opakowania glibc, wiele z nich z POSIX .

Wewnętrznie owijki glibc używają mniej więcej takiego wbudowania: Jak wywołać wywołanie systemowe za pomocą sysenter w zestawie wbudowanym?

Następnym przykładem, który powinieneś przestudiować, jest POSIX writehello world:

main.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *msg = "hello\n";
    write(1, msg, 6);
    return 0;
}

Skompiluj i uruchom:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

Tym razem zobaczysz, że glibc wykonuje kilka wywołań systemowych, mainaby skonfigurować ładne środowisko dla main.

Wynika to z faktu, że nie używamy teraz programu wolnostojącego, ale bardziej popularnego programu glibc, który umożliwia funkcjonalność libc.

Następnie na każdym końcu strace.logzawiera:

write(1, "hello\n", 6)                  = 6
exit_group(0)                           = ?
+++ exited with 0 +++

Dochodzimy zatem do wniosku, że writefunkcja POSIX używa, niespodzianka ! write, wywołania systemowego Linux .

Obserwujemy również, że return 0prowadzi to do exit_grouppołączenia zamiast exit. Ha, nie wiedziałem o tym! Właśnie dlatego stracejest taki fajny. man exit_groupnastępnie wyjaśnia:

To wywołanie systemowe jest równoważne z exit (2), z tym wyjątkiem, że kończy nie tylko wątek wywołujący, ale wszystkie wątki w grupie wątków procesu wywołującego.

A oto kolejny przykład, w którym badałem, które dlopenwykorzystuje wywołanie systemowe : /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

Testowane w Ubuntu 16.04, GCC 6.4.0, jądro Linuksa 4.4.0.

Ciro Santilli
źródło
2

Oto kilka przykładów tego, jak używam strace do kopania na stronach internetowych. Mam nadzieję, że to jest pomocne.

Sprawdź czas do pierwszego bajtu:

time php index.php > timeTrace.txt

Zobacz, jaki procent działań robi co. Wiele lstati fstatmoże to wskazywać, że nadszedł czas, aby wyczyścić pamięć podręczną:

strace -s 200 -c php index.php > traceLstat.txt

Wysyła a trace.txt, abyś mógł dokładnie zobaczyć, jakie połączenia są wykonywane.

strace -Tt -o Fulltrace.txt php index.php

Użyj tego, aby sprawdzić, czy wszystko wziął między .1do .9sekundy, aby załadować:

cat Fulltrace.txt | grep "[<]0.[1-9]" > traceSlowest.txt

Zobacz, jakie brakujące pliki lub katalogi złapały strace. Spowoduje to wygenerowanie wielu rzeczy związanych z naszym systemem - jedyne istotne bity dotyczą plików klienta:

strace -vv php index.php 2>&1 | sed -n '/= -1/p' > traceFailures.txt
Kerwin Smith
źródło
1

Podobały mi się niektóre odpowiedzi, w których czytane są informacje na stracetemat interakcji z systemem operacyjnym.

Właśnie to widzimy. System dzwoni. Jeśli porównasz, stracea ltraceróżnica jest bardziej oczywista.

$>strace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         7           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0        11           close
  0.00    0.000000           0        10           fstat
  0.00    0.000000           0        17           mmap
  0.00    0.000000           0        12           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         2           ioctl
  0.00    0.000000           0         8         8 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         9           openat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           prlimit64
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    93        10 total

Z drugiej strony istnieje ltracefunkcja śledzenia.

$>ltrace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 15.52    0.004946         329        15 memcpy
 13.34    0.004249          94        45 __ctype_get_mb_cur_max
 12.87    0.004099        2049         2 fclose
 12.12    0.003861          83        46 strlen
 10.96    0.003491         109        32 __errno_location
 10.37    0.003303         117        28 readdir
  8.41    0.002679         133        20 strcoll
  5.62    0.001791         111        16 __overflow
  3.24    0.001032         114         9 fwrite_unlocked
  1.26    0.000400         100         4 __freading
  1.17    0.000372          41         9 getenv
  0.70    0.000222         111         2 fflush
  0.67    0.000214         107         2 __fpending
  0.64    0.000203         101         2 fileno
  0.62    0.000196         196         1 closedir
  0.43    0.000138         138         1 setlocale
  0.36    0.000114         114         1 _setjmp
  0.31    0.000098          98         1 realloc
  0.25    0.000080          80         1 bindtextdomain
  0.21    0.000068          68         1 opendir
  0.19    0.000062          62         1 strrchr
  0.18    0.000056          56         1 isatty
  0.16    0.000051          51         1 ioctl
  0.15    0.000047          47         1 getopt_long
  0.14    0.000045          45         1 textdomain
  0.13    0.000042          42         1 __cxa_atexit
------ ----------- ----------- --------- --------------------
100.00    0.031859                   244 total

Chociaż kilkakrotnie sprawdzałem instrukcje, nie znalazłem źródła nazwy, straceale jest to prawdopodobnie ślad wywołania systemowego, ponieważ jest to oczywiste.

Istnieją trzy większe uwagi do powiedzenia strace.

Uwaga 1: Obie te funkcje stracei ltracesą za pomocą wywołania systemowego ptrace. Tak więc ptracewywołanie systemowe działa skutecznie strace.

Wywołanie systemowe ptrace () zapewnia środki, za pomocą których jeden proces („tracer”) może obserwować i kontrolować wykonywanie innego procesu („tracee”) oraz badać i zmieniać pamięć i rejestry śledzenia. Służy głównie do implementacji debugowania punktu przerwania i śledzenia połączeń systemowych.

Uwaga 2: Można używać różnych parametrów strace, ponieważ stracemogą być bardzo szczegółowe. Lubię eksperymentować z -cczym jest jak podsumowanie rzeczy. Na podstawie -cmożesz wybrać jedno wywołanie systemowe, tak jak -e trace=opentam, gdzie zobaczysz tylko to połączenie. Może to być interesujące, jeśli sprawdzasz, jakie pliki zostaną otwarte podczas śledzenia polecenia. I oczywiście możesz użyć tego grepdo tego samego celu, ale pamiętaj, że musisz przekierować w ten sposób, 2>&1 | grep etcaby zrozumieć, że pliki konfiguracyjne są przywoływane podczas wydawania polecenia.

Uwaga 3: Uważam tę bardzo ważną notatkę. Nie jesteś ograniczony do konkretnej architektury. stracerozwali cię, ponieważ może śledzić pliki binarne różnych architektur. wprowadź opis zdjęcia tutaj

prosti
źródło