strace
Программа не может сама взять ресурсы системы (прочитать файл, выделить память, открыть сокет, отправить пакет и тд), необходим системный вызов (system call).
Категории системных вызовов:
1. Работа с файловой системой (openat, read, write, close, ...)
2. Работа с памятью (mmap, munmap, mremap, ...)
3. Управление процессами (fork, clone, kill, execve, ...)
4. Сеть (bind, connect, listen, accept, ...)
5. Многопоточность (futex, pause, nanosleep, ...)
6. IPC (pipe, shmget, msgsnd, msgrcv, ...)
7. Пользователи и права (getuid, getgid, setuid, ...)
и так далее: сигналы, пространства имён, event loop, ...
Выполнение даже простой программы - набор таких вызовов. Увидеть их можно с помощью strace - мощного диагностического инструмента. Добавляем перед началом команды strace и получаем все подробности. Каждый запрос к системе перехватывается, анализируется и фиксируется всё: сам вызов, аргументы и возвращаемые значения. Важно! Скорость выполнения программы в этом режиме проседает на порядки - в продакшене использовать с осторожностью. Тем не менее, иногда только через трассировку можно понять почему, например, процесс завис:
strace -p 37958 покажет чего именно ждёт указанный PID.
Попробуйте добавить strace перед самыми разными командами: ls, cat, date, who, ...
Очень интрересные вещи можно увидеть.
Прочитаем вывод strace:
strace cat /proc/cpuinfo
execve("/usr/bin/cat", ["cat", "/proc/cpuinfo"], 0x7ffd55c9d688 /* 21 vars */) = 0
brk(NULL) = 0x5564493fb000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd834c61000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=9931, ...}) = 0
mmap(NULL, 9931, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd834c5e000
...
execve - запустилась программа cat (и передала 21 переменную окружения), 0 - успех
brk(NULL) - вопрос про указатель на куче, 0x5564493fb000 - адрес конца кучи
mmap - выделение 8кб памяти (8192 байта), MAP_PRIVATE - приватная не разделяемая память, 0x7fd834c61000 - адрес выделенного блока
ld.so - динамический загрузчик, работа происходит через него
ld.so.cache - бинарный кэш, в котором записано где на диске лежат системные библиотеки
openat - cat попросил ядро открыть файл, ядро вернуло дескриптор 3
(0, 1, 2 — это stdin, stdout, stderr, поэтому следующий свободный — 3) и т.д.
Действий много, лог забит, поэтому важно уметь фильтровать действия по категориям: ключ -e
strace -e openat ping -c1 ya.ru
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libidn2.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libunistring.so.5", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 5
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 5
openat(AT_FDCWD, "/etc/host.conf", O_RDONLY|O_CLOEXEC) = 5
openat(AT_FDCWD, "/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 5
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 5
openat(AT_FDCWD, "/etc/gai.conf", O_RDONLY|O_CLOEXEC) = 5
или несколько: strace -e openat,connect ping -c1 ya.ru