Вопрос

Коллега однажды сказал мне, что последний вариант, когда в Linux ничего не удалось отладить, — это использовать след.

Я пытался изучить научную основу этого странного инструмента, но я не гуру системного администратора и особых результатов не добился.

Так,

  • Что это такое и что оно делает?
  • Как и в каких случаях его следует использовать?
  • Как следует понимать и обрабатывать выходные данные?

Вкратце, простыми словами, как эта штука работает?

Это было полезно?

Решение

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

Использование
Подходит, когда у вас нет исходного кода или вы не хотите утруждаться его изучением.
Кроме того, это полезно для вашего собственного кода, если вы не хотите открывать GDB, а просто заинтересованы в понимании внешнего взаимодействия.

Хорошее небольшое введение
Буквально на днях я столкнулся с этим вступлением для использования strace: Привет, мир!

Другие советы

Проще говоря, strace отслеживает все системные вызовы программы вместе с их кодами возврата.Подумайте о таких вещах, как операции с файлами/сокетами и о многих других непонятных вещах.

Это наиболее полезно, если у вас есть некоторые практические знания C, поскольку здесь системные вызовы точнее будут означать стандартные вызовы библиотеки C.

Допустим, ваша программа /usr/local/bin/cough.Просто используйте:

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

или

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

для записи в «out_file».

Весь вывод strace будет поступать на стандартный поток stderr (будьте осторожны, из-за его большого объема часто требуется перенаправление в файл).В простейших случаях ваша программа прервется с ошибкой, и вы сможете увидеть, где и где ее последнее взаимодействие с ОС, в выводе strace.

Дополнительная информация должна быть доступна по адресу:

man strace

strace перечисляет все системные вызовы выполняется процессом, к которому он применяется.Если вы не знаете, что означают системные вызовы, вы не сможете извлечь из них большую пользу.

Тем не менее, если ваша проблема связана с файлами, путями или значениями среды, запуск strace в проблемной программе и перенаправление вывода в файл, а затем поиск этого файла для строки пути/файла/окружения может помочь вам увидеть, что представляет собой ваша программа. на самом деле пытаясь сделать что-то отличное от того, чего вы от этого ожидали.

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

  • Программа foo, похоже, зашла в тупик и перестала отвечать на запросы.Это может быть целью для GDB;однако у нас не всегда был исходный код, а иногда мы имели дело со скриптовыми языками, которые было сложно запустить под отладчиком.В этом случае вы запускаете strace для уже работающей программы и получаете список выполняемых системных вызовов.Это особенно полезно, если вы исследуете клиент-серверное приложение или приложение, взаимодействующее с базой данных.
  • Выясняем, почему программа работает медленно.В частности, мы только что перешли на новую распределенную файловую систему, и пропускная способность новой системы была очень низкой.Вы можете указать strace с опцией '-T', которая сообщит вам, сколько времени было потрачено на каждый системный вызов.Это помогло определить, почему файловая система замедляет работу.

Пример анализа с использованием strace см. в моем ответе на этот вопрос.

Я постоянно использую strace для устранения проблем с разрешениями.Техника выглядит следующим образом:

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

Где gnome-calculator — это команда, которую вы хотите запустить.

strace -tfp PID будет отслеживать системные вызовы процесса PID, поэтому мы можем отлаживать/отслеживать состояние нашего процесса/программы.

Strace можно использовать как инструмент отладки или как примитивный профилировщик.

Как отладчик, вы можете видеть, как вызывались, выполнялись заданные системные вызовы и что они возвращали.Это очень важно, поскольку позволяет увидеть не только то, что программа не удалась, но и ПОЧЕМУ программа дала сбой.Обычно это просто результат плохого кодирования, не учитывающего все возможные результаты программы.В других случаях это просто жестко закодированные пути к файлам.Без strace вы сможете догадаться, что, где и как пошло не так.С помощью strace вы получаете разбивку системного вызова, обычно просто просмотр возвращаемого значения говорит вам о многом.

Профилирование — еще одно применение.Вы можете использовать его для определения времени выполнения каждого системного вызова индивидуально или в совокупности.Хотя этого может быть недостаточно для решения ваших проблем, это, по крайней мере, значительно сузит список потенциальных подозреваемых.Если вы видите много пар fopen/close в одном файле, вы, вероятно, без необходимости открываете и закрываете файлы при каждом выполнении цикла вместо того, чтобы открывать и закрывать их вне цикла.

Ltrace — близкий родственник strace, тоже очень полезный.Вы должны научиться различать, где находится ваше узкое место.Если общее время выполнения составляет 8 секунд, а на системные вызовы вы тратите всего 0,05 секунды, то трассировка программы не принесет вам особой пользы, проблема в вашем коде, что обычно является логической проблемой, или программе действительно нужно бежать так долго.

Самая большая проблема с strace/ltrace — чтение их вывода.Если вы не знаете, как выполняются вызовы или, по крайней мере, имена системных вызовов/функций, вам будет сложно расшифровать их значение.Знание того, что возвращают функции, также может быть очень полезным, особенно для различных кодов ошибок.Хотя расшифровывать их сложно, иногда они действительно возвращают жемчужину знаний;однажды я увидел ситуацию, когда у меня закончились иноды, но не закончилось свободное место, поэтому все обычные утилиты не выдали мне никаких предупреждений, я просто не мог создать новый файл.Чтение кода ошибки из вывода strace указало мне правильное направление.

Strace — это инструмент, который сообщает вам, как ваше приложение взаимодействует с вашей операционной системой.

Он делает это, сообщая вам, какие системные вызовы ОС использует ваше приложение и с какими параметрами оно их вызывает.

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

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

И это лишь верхушка айсберга.

strace — хороший инструмент для изучения того, как ваша программа выполняет различные системные вызовы (запросы к ядру), а также сообщает о тех из них, которые потерпели неудачу, вместе со значением ошибки, связанной с этим сбоем.Не все сбои являются ошибками.Например, код, который пытается найти файл, может получить ошибку ENOENT (Нет такого файла или каталога), но это может быть приемлемым сценарием в логике кода.

Одним из хороших вариантов использования strace является отладка условий гонки во время создания временного файла.Например, программа, которая может создавать файлы, добавляя идентификатор процесса (PID) к некоторой заранее заданной строке, может столкнуться с проблемами в многопоточных сценариях.[PID+TID (идентификатор процесса + идентификатор потока) или лучший системный вызов, такой как mkstemp, исправит это].

Это также хорошо для отладки сбоев.Вы можете найти эта (моя) статья о strace и отладке сбоев полезный.

Мне понравились некоторые ответы, где это написано strace проверяет, как вы взаимодействуете с операционной системой.

Это именно то, что мы можем видеть.Система звонит.Если вы сравните strace и ltrace разница более очевидна.

$>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

С другой стороны, есть ltrace который отслеживает функции.

$>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

Хотя я несколько раз проверял руководства, я не нашел происхождения названия. strace но, скорее всего, это трассировка системного вызова, поскольку это очевидно.

Есть три важных замечания, о которых стоит сказать. strace.

Примечание 1:Обе эти функции strace и ltrace используют системный вызов ptrace.Так ptrace системный вызов – это, по сути, то, как strace работает.

Системный вызов PTRACE () предоставляет средство, с помощью которого один процесс («Трасер») может наблюдать и контролировать выполнение другого процесса («Трейсее»), а также изучить и изменить память и регистры Трейси.Он используется в первую очередь для реализации отладки точки останова и отслеживания системных вызовов.

Заметка 2:Существуют различные параметры, которые вы можете использовать с strace, с strace может быть очень многословным.мне нравится экспериментировать с -c это похоже на краткое изложение вещей.На основе -c вы можете выбрать один системный вызов, например -e trace=open где вы увидите только этот звонок.Это может быть интересно, если вы проверяете, какие файлы будут открыты во время отслеживаемой команды.И, конечно же, вы можете использовать grep для той же цели, но учтите, что вам нужно перенаправить вот так 2>&1 | grep etc чтобы понять, что файлы конфигурации используются при вводе команды.

Заметка 3:Я считаю это очень важным замечанием.Вы не ограничены конкретной архитектурой. strace поразит вас, поскольку он может отслеживать двоичные файлы различной архитектуры.enter image description here

Минимальный работоспособный пример

Если концепция не ясна, есть более простой пример, который вы еще не видели, который объясняет ее.

В данном случае примером является автономная сборка Linux x86_64 (без libc) hello world:

привет.С

.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 апстрим.

Собираем и запускаем:

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

Выводит ожидаемое:

hello

Теперь давайте воспользуемся strace в этом примере:

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

Мы используем:

strace.log теперь содержит:

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

В таком минимальном примере каждый символ вывода очевиден:

  • execve линия:покажи покажи strace казнен hello.out, включая аргументы CLI и среду, как описано в man execve

  • write линия:показывает системный вызов записи, который мы сделали. 6 длина строки "hello\n".

    = 6 — это возвращаемое значение системного вызова, которое, как описано в man 2 write количество записанных байт.

  • exit линия:показывает системный вызов выхода, который мы сделали.Возвращаемого значения нет, так как программа завершилась!

Более сложные примеры

Применение strace, конечно же, предназначено для того, чтобы увидеть, какие системные вызовы на самом деле выполняют сложные программы, чтобы помочь отладить/оптимизировать вашу программу.

Примечательно, что большинство системных вызовов, с которыми вы, вероятно, столкнетесь в Linux, имеют обертки glibc. многие из них из POSIX.

Внутри оболочки glibc используют встроенную ассемблерную сборку примерно так: Как вызвать системный вызов через sysenter во встроенной сборке?

Следующий пример, который вам следует изучить, — это POSIX. write Привет, мир:

main.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

Скомпилируйте и запустите:

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

На этот раз вы увидите, что перед этим glibc выполняет несколько системных вызовов. main чтобы настроить приятную среду для main.

Это связано с тем, что сейчас мы используем не отдельную программу, а более распространенную программу glibc, которая обеспечивает функциональность libc.

Затем, в каждом конце, strace.log содержит:

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

Итак, мы приходим к выводу, что write Функция POSIX, как ни удивительно, использует Linux write системный вызов.

Мы также наблюдаем, что return 0 приводит к exit_group позвонить вместо exit.Ха, я не знал об этом!Вот почему strace это так круто. man exit_group затем объясняет:

Этот системный вызов эквивалентен выходу(2), за исключением того, что он завершает не только вызывающий поток, но и все потоки в группе потоков вызывающего процесса.

А вот еще пример, где я изучал, какой системный вызов dlopen использует: https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

Протестировано в Ubuntu 16.04, GCC 6.4.0, ядре Linux 4.4.0.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top