Главная >> Команды >> Команда strace в Linux

Команда 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

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

имя_системного_вызова (параметр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

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

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

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

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

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

pidof dd

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

sudo strace -p 31796

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

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

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

sudo strace -e trace=stat nautilus

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

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

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

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

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

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

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

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

sudo strace -e fault=uname uname

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

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

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

strace -P /proc/cpuinfo lscpu

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

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

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

sudo strace -c nautilus

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

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

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

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

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

strace -t uname

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

strace -tt uname

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

strace -ttt uname

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

strace -ttt -T uname

Выводы

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

Creative Commons License
Статья распространяется под лицензией Creative Commons ShareAlike 4.0 при копировании материала ссылка на источник обязательна .

5 комментариев к “Команда strace в Linux”

  1. Какие есть еще системные утилиты для диагностики неисправности, и анализа работы программ? И если можете сделайте статейки на них. Еще интересуют программы для анализа трафика - НЕ Wireshark. Есть GUI версии программ ?
    Спасибо.

    Ответить
    • D,

      Самое банальное - запуск программы из консоли. Возможно, она в терминал вывалит диагностическую информацию, среди которой будут и ошибки. Это же (и еще кое-что) можно и в journalctl посмотреть.

      Саму программу имеет смысл запускать в режиме дебага. Имею в виду, что бывают "специальные" ключи (наподобие -v у ssh), которые дают более подробный вывод, они в man'е, и/ или в конфиге выставить, чтобы она писала лог с максимальной подробностью, в какой-либо файл (у вебсерверов это есть). Ну и смотреть этот файл, как вариант, через tail -F в режиме реального времени.
      Если же сам что-то менял и где-то неочевидно накосячил при установке/ настройке, то можно и пакет банально переставить, если сервис не успел развернуть 🙂

      Иногда имеет смысл посмотреть через ldd (и выставление LD_DEBUG=all), что за библиотеки нужны софтине, и нашла ли она их.

      Помимо strace есть еще куча подобного софта (для диагностики и профилирования), типа ftrace и ltrace. Несколько отдельно можно выделить gdb - это отладчик, но тут все даже несколько менее тривиально, чем с strace, это скорее инструмент для тех, кто сам пишет софт, а не пытается "заткнуть дырки" (баги) в неработающей системе. Так что да, strace и gdb это несколько тяжелая артиллерия зачастую, порой все гораздо проще и решается чтением логов. Увидев сообщения об ошибках, имеет смысл их обдумать, а если мыслей нет - хотя бы загуглить.

      Если интересует более широко - анализ работы всей системы, что в общем-то включает и работу отдельных программ, то никто не отменял top и кипу других утилит.
      А вообще, вопросы производительности просто ОЧЕНЬ круто рассматривает Брендан Грегг.
      http://www.brendangregg.com/USEmethod/use-linux.html

      Для анализа трафика в реальном времени - tcpdump. Неясно чем Wireshark не угодил, работает почти так же, тот же захват трафика, навешивание фильтров, только еще куча всяких фенечек и собственно GUI, который вы хотите. Если интересует статистика, то можно логировать через тот же iptables.
      Если статистика, но более серьезно... то это уже скорее область сетевого железа, с их netflow и пр.

      Ответить
  2. Это конечно здорово примитивы выкладывать. А на не самое очевидное, например echo или cd не решились замахнуться?

    Ответить
  3. Андрей, наверно, задал вопрос не о работе этих команд, а о их трассировке. Они встроенные. Так просто не трассируются. Нужно пробовать что-то типа
    strace /bin/bash -c 'cd /tmp'

    Ответить

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