Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Представьте, что у вас есть рентгеновский аппарат для программ в Linux. Вы можете видеть каждое их движение, каждый «вздох» и каждую ошибку в реальном времени. Больше не нужно гадать, почему приложение зависло, куда оно пытается записать данные или почему оно отказывается запускаться.

Всё это возможно с помощью одной мощной команды — strace. Это ваш шпионский бинокль, направленный в самое сердце операционной системы. Она показывает все системные вызовы, которые программа отправляет ядру.

Хотите узнать, к каким файлам обращается программа? Какие сетевые порты она использует? Какие ошибки система возвращает ей в ответ? Strace даст вам все ответы.

Вы не только увидите, что программа делает, но и поймёте, как она это делает. Вы сможете подключиться к уже запущенному процессу, фильтровать только нужные операции или собрать подробную статистику по времени выполнения.

Мы покажем вам, как за несколько секунд диагностировать сложные проблемы, которые часами не поддавались анализу через логи. Готовы стать настоящим детективом в мире Linux? Тогда начинаем!


В операционной системе и используемых в ней программах иногда возникают ошибки, причину которых очень сложно понять, анализируя файлы журналов и сообщения об ошибках. Но и для таких ситуаций в Linux есть средства. За процессом работы любой из программ можно проследить, наблюдая системные вызовы, которые использует программа.

С помощью системных вызовов можно понять, к каким файлам обращается программа, какие сетевые порты она использует, какие ресурсы ей нужны, а также какие ошибки возвращает ей система. Это помогает разобраться в особенностях работы программы и лучше понять причину ошибки. За всё это отвечает команда strace Linux. В сегодняшней статье мы разберёмся, что она из себя представляет и как ею пользоваться.


Содержание статьи

Команда strace Linux

Как я уже сказал, команда strace показывает все системные вызовы программы, которые та отправляет к системе во время выполнения, а также их параметры и результат выполнения. Но при необходимости можно подключиться и к уже запущенному процессу. Перед тем, как перейти к практике, разберём опции утилиты и её синтаксис:

$ strace опции команда аргументы

В самом простом варианте strace запускает переданную команду с её аргументами и выводит в стандартный поток ошибок все системные вызовы команды. Давайте разберём опции утилиты, с помощью которых можно управлять её поведением:

  • -i - выводить указатель на инструкцию во время выполнения системного вызова;
  • -k - выводить стек вызовов для отслеживаемого процесса после каждого системного вызова;
  • -o - выводить всю информацию о системных вызовах не в стандартный поток ошибок, а в файл;
  • -q - не выводить сообщения о подключении о отключении от процесса;
  • -qq - не выводить сообщения о завершении работы процесса;
  • -r - выводить временную метку для каждого системного вызова;
  • -s - указать максимальный размер выводимой строки, по умолчанию 32;
  • -t - выводить время суток для каждого вызова;
  • -tt - добавить микросекунды;
  • -ttt - добавить микросекунды и количество секунд после начала эпохи Unix;
  • -T - выводить длительность выполнения системного вызова;
  • -x - выводить все не ASCI-строки в шестнадцатеричном виде;
  • -xx - выводить все строки в шестнадцатеричном виде;
  • -y - выводить пути для файловых дескрипторов;
  • -yy - выводить информацию о протоколе для файловых дескрипторов;
  • -c - подсчитывать количество ошибок, вызовов и время выполнения для каждого системного вызова;
  • -O - добавить определённое количество микросекунд к счетчику времени для каждого вызова;
  • -S - сортировать информацию выводимую при опции -c. Доступны поля time, calls, name и nothing. По умолчанию используется time;
  • -w - суммировать время между началом и завершением системного вызова;
  • -e - позволяет отфильтровать только нужные системные вызовы или события;
  • -P - отслеживать только системные вызовы, которые касаются указанного пути;
  • -v - позволяет выводить дополнительную информацию, такую как версии окружения, статистику и так далее;
  • -b - если указанный системный вызов обнаружен, трассировка прекращается;
  • -f - отслеживать также дочерние процессы, если они будут созданы;
  • -ff - если задана опция -o, то для каждого дочернего процесса будет создан отдельный файл с именем имя_файла.pid.
  • -I - позволяет блокировать реакцию на нажатия Ctrl+C и Ctrl+Z;
  • -E - добавляет переменную окружения для запускаемой программы;
  • -p - указывает pid процесса, к которому следует подключиться;
  • -u - запустить программу, от имени указанного пользователя.

Вы знаете основные опции strace, но чтобы полноценно ею пользоваться, нужно ещё разобраться с системными вызовами, которые используются чаще всего. Мы не будем рассматривать все, а только основные. Многие из них вы уже и так знаете, потому что они называются так же, как и команды в терминале:

  • fork - создание нового дочернего процесса;
  • read - попытка читать из файлового дескриптора;
  • write - попытка записи в файловый дескриптор;
  • open - открыть файл для чтения или записи;
  • close - закрыть файл после чтения или записи;
  • chdir - изменить текущую директорию;
  • execve - выполнить исполняемый файл;
  • stat - получить информацию о файле;
  • mknod - создать специальный файл, например, файл устройства или сокет;

А теперь разберём примеры strace Linux.

Примеры использования Strace

1. Запуск программы

Самый простой способ запуска утилиты - просто передать ей в параметрах имя команды или исполняемый файл программы, которую мы хотим исследовать. Например, uname:

strace uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Как и ожидалось, мы видим список системных вызовов, которые делает утилита, чтобы узнать версию ядра. Синтаксис вывода такой:

имя_системного_вызова (параметр1, параметр2) = результат сообщение

Имя системного вызова указывает, какой именно вызов использовала программа. Для большинства вызовов характерно то, что им нужно передавать параметры, имена файлов, данные и так далее. Эти параметры передаются в скобках. Далее идет знак равенства и результат выполнения. Если всё прошло успешно, то здесь будет  ноль или положительное число. Если же возвращается отрицательное значение, делаем вывод, что произошла ошибка. В таком случае выводится сообщение.

Например, в нашем выводе есть сообщения об ошибке:

openat(AT_FDCWD, "/usr/local/cuda-6.5/lib64/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

Здесь результат выполнения -1 и сообщение говорит, что файл не найден. Но на работу программы это не влияет. Это проблема подключения сторонних библиотек и к этой утилите она не имеет отношения. А основная работа программы выполняется строчкой:

uname({sysname="Linux", nodename="sergiy-pc1", ...}) = 0

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

И здесь ядро вернуло положительный результат.

2. Подключение к запущенной программе

Если программа, которую нам надо отследить, уже запущена, то не обязательно её перезапускать с нашей утилитой. Можно подключиться к ней по ее идентификатору PID. Для тестирования этой возможности запустим утилиту dd, которая будет записывать нули из /dev/zero в файл file1:

dd if=/dev/zero of=~/file1

Теперь узнаем PID нашего процесса, поскольку он такой один, можно воспользоваться pidof, вы же можете использовать ps:

pidof dd

И осталось подключиться к нашему процессу:

sudo strace -p 31796

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

В выводе утилиты мы видим, что она читает данные из одного места с помощью вызова read и записывает в другое через write. Чтобы отсоединится от процесса, достаточно нажать Ctrl+C. Дальше рассмотрим примеры strace Linux для фильтрации данных.

3. Фильтрация системных вызовов

Утилита выводит слишком много данных, и, зачастую, большинство из них нас не интересуют. С помощью опции -e можно применять различные фильтры для более удобного поиска проблемы. Мы можем отобразить только вызовы stat, передав в опцию -e такой параметр trace=stat:

sudo strace -e trace=stat nautilus

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Кроме непосредственно системных вызовов, в качестве параметра для trace можно передавать и такие значения:

  • file - все системные вызовы, которые касаются файлов;
  • process - управление процессами;
  • network - сетевые системные вызовы;
  • signal - системные вызовы, что касаются сигналов;
  • ipc - системные вызовы IPC;
  • desc - управление дескрипторами файлов;
  • memory - работа с памятью программы.

4. Возвращение ошибки

Можно попросить strace вернуть программе ошибку по нужному системному вызову -e, но с параметром fault. Синтаксис конструкции такой:

fault=имя_вызова:error=тип_ошибки:when=количество

С именем вызова всё понятно, тип ошибки, номер ошибки, которую надо вернуть. А с количеством всё немного сложнее. Есть три варианта:

  • цифра - вернуть ошибку только после указанного количества запросов;
  • цифра+ - вернуть ошибку после указанного количества запросов и для всех последующих;
  • цифра+шаг - вернуть ошибку для указанного количества и для последующих с указанным шагом.

Например, сообщим uname, что системного вызова uname не существует:

sudo strace -e fault=uname uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

В выводе видим, что система вернула программе нашу ошибку, а потом та с помощью вызова write говорит пользователю, что узнать версию и название системы невозможно.

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

5. Фильтрация по пути

Если вас интересует не определённый вызов, а все операции с нужным файлом, то можно выполнить фильтрацию по нему с помощью опции -P. Например, меня интересует, действительно ли утилита lscpu обращается к файлу /proc/cpuinfo, чтобы узнать информацию о процессоре:

strace -P /proc/cpuinfo lscpu

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

И в результате мы видим, что действительно обращается. Она открывает его для чтения с помощью вызова openat.

6. Статистика системных вызовов

С помощью опции вы можете собрать статистику для системных вызовов, которые использует программа. Например, сделаем это для nautilus:

sudo strace -c nautilus

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Во время работы утилита ничего выводить не будет. Результат будет рассчитан и выведен, когда вы завершите отладку. В выводе будут такие колонки:

  • time - процент времени от общего времени выполнения системных вызовов;
  • seconds - общее количество секунд, затраченное на выполнение системных вызовов этого типа;
  • calls - количество обращений к вызову;
  • errors - количество ошибок;
  • syscall - имя системного вызова.

Если вы хотите получать эту информацию в режиме реального времени, используйте опцию -C.

7. Отслеживание времени выполнения

Чтобы отображать время выполнения каждого системного вызова, используйте опцию -t:

strace -t uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Можно также отображать микросекунды:

strace -tt uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Или отображать время в формате UNIX:

strace -ttt uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Чтобы добавить время выполнения вызова, добавьте -T:

strace -ttt -T uname

Strace: Как заглянуть внутрь Linux и найти причину любой ошибки

Выводы

В этой статье была рассмотрена команда strace Linux. Как видите, это очень удобный инструмент, который поможет решить множество проблем в вашей системе или на сервере. Мы рассмотрели только основные возможности утилиты, но этого будет вполне достаточно, чтобы начать работать с ней, а более подробную информацию можно найти в официальном руководстве.

Оставить комментарий


Кликните на изображение чтобы обновить код, если он неразборчив