Как использовать ltrace для трассировки библиотечных вызовов

Интересно исправить те библиотечные ошибки и ошибки, которые вы наблюдаете при установке новой классной программы в Linux? Ознакомьтесь с этой статьей, в которой показано, как использовать ltrace, вооружившись инструментом, необходимым для отладки вызовов библиотек.
Что такое библиотека?
Большинство людей знакомы с файлами .dll/.DLL
(библиотеки динамической компоновки) в Windows. Эквивалентом для Linux является файл .so
, общий объект, который часто называют просто библиотекой.
Библиотека может использоваться приложением, позволяющим этой программе использовать функциональные возможности вне своего программного кода. Например, веб-сервер может захотеть использовать библиотеку дискового ввода-вывода, написанную поставщиком операционной системы или другой третьей стороной. Это способ обмена общими благами и интересами в большинстве, если не во всех, операционных системах.
Библиотеки могут быть загружены либо динамически во время выполнения (например, когда запускается вызывающая программа), либо они могут быть скомпилированы в целевое приложение/двоичный файл. Таким образом, они всегда будут загружаться (независимо от того, используются они или нет), как часть и всякий раз, когда запускается приложение, в котором они скомпилированы/встроены.
Чтобы узнать больше о библиотеках, их зависимостях и инструменте ldd
, вы можете прочитать о том, как работать с зависимостями общих объектов в Linux. Инструмент ldd
— еще один удобный инструмент, который должен быть в любом более продвинутом пользовательском наборе инструментов Linux.
что такое лтрейс?
В Linux есть различные утилиты трассировки, такие как strace для отслеживания системных вызовов и сигналов и traceroute
для отслеживания сетевой маршрутизации. Утилита/инструмент ltrace
отслеживает все вызовы библиотеки.
Если вы читали нашу работу с зависимостями Shared Object (Library) в статье Linux (ссылка указана выше), вы уже видели, как можно узнать, с какими библиотеками связан конкретный двоичный файл, используя ldd
инструмент. Назначение и функциональность ltrace
несколько отличаются; В соответствии с strace
, команда ltrace
отслеживает все библиотечные вызовы, которые делает конкретная программа во время ее выполнения.
Как и в случае с strace
, мы можем запустить программу под (подумайте об этом как об иерархии) ltrace
. Мы просто указываем программу, которую должен запустить ltrace
, в качестве первой опции для ltrace
, и ltrace
запустит эту программу для нас и немедленно начнет (на более высокий уровень) для отслеживания всех обращений к любым (установленным в операционной системе или сторонних) библиотекам.
Он делает это, перехватывая и записывая вызовы динамической библиотеки, сделанные исполняемой программой. Он также будет отслеживать любые сигналы, посылаемые исполняемой программе, очень похоже на strace
(и, при желании, эту функцию можно отключить, указав -b
или аналогичный --no-signals
для ltrace
).
Обратите внимание, что здесь очень важен термин динамический; ltrace
будет отслеживать вызовы к внешним библиотекам (в виде файлов .so
или .a
), т. е. к библиотекам не компилируется напрямую в программу; динамические библиотеки. Таким образом, если у вас есть бинарник со статически (скомпилированными) библиотеками, ltrace
не сможет увидеть/отследить такие внутренние вызовы.
Установка ltrace

Чтобы установить ltrace в свой дистрибутив Linux на основе Debian/Apt (например, Ubuntu и Mint), выполните следующую команду в своем терминале:
sudo apt установить ltrace
Чтобы установить ltrace в ваш дистрибутив Linux на основе RedHat/Yum (например, RHEL, Centos и Fedora), выполните следующую команду в своем терминале:
sudo yum установить ltrace
Использование ltrace
Давайте настроим небольшую тестовую среду:
sudo apt install tar xz-utils
mkdir ~/workspace && cd ~/workspace
touch a b c
Здесь мы установили tar
и xz
, установив xz-utils
(вместо этого вы можете использовать sudo yum install tar xz
, если вы используете Centos/RHEL/Fedora). Затем мы создали каталог ~/workspace
и перешли в него. Затем мы создали три пустых файла с помощью команды touch
, а именно файлы a
, b
и c
.
Давайте начнем со сжатия наших трех файлов в (объединенный tar и сжатый xz) архив archive.tar.xz
, выполняя то же самое под ltrace
и наблюдая за выводом ltrace
:

ltrace tar -hcf --xz archive.tar.xz *
Мы видим только небольшое количество продукции. Мы видим, что наша программа завершилась успешно (файл архива был создан), т. е. статус 0
: код выхода 0
всегда означает успех в Linux (хотя программе нужно коды выхода реализованы правильно).
Пока это не очень полезно. Несколько секунд размышлений о том, как здесь будет работать tar
, быстро откроют наш следующий подход. Заядлый читатель, возможно, также понял, что команда tar
внутренне вызовет команду xz
. Опция --xz
, переданная в нашу командную строку tar
, гарантирует, что для сжатия используется программа xz
.
Второстепенный процесс (или третий в общей иерархии), а именно xz
(иерархия: ltrace
> tar
> xz
) будет запускаться tar
при необходимости. Таким образом, нам нужно отслеживать дочерние процессы программы, работающей под управлением ltrace
, то есть tar
. Мы можем сделать это, указав следующую опцию (-f
) для ltrace
:

ltrace -f tar -hcf --xz archive.tar.xz *
Обратите внимание, что важно указать параметр -f
непосредственно после ltrace
, а не позже в командной строке после, например, tar
. Причина в том, что мы хотим указать эту опцию для ltrace
, а не для команды tar
. Все параметры после команды tar
являются параметрами, специфичными для tar
, тогда как -f
— параметром, характерным для ltrace
.
Выход немного интереснее. Мы пока не наблюдаем каких-либо вызовов библиотек (в любой форме), но мы, по крайней мере, видим, что два подпроцесса разветвлены (обратите внимание на exec()
) и что оба подпроцесса завершаются со статусом 0
. Удобный и все хорошо.
Итак, где наши библиотечные звонки? Проверяя tar
и xz
(две программы, которые будут использоваться командой для создания файла архива) с помощью ldd
, мы быстро понимаем, что большинство библиотеки, которые используют обе программы, являются системными библиотеками:

whereis tar
whereis xz
ldd /bin/tar
ldd /usr/bin/xz
Таким образом, мы должны сделать еще один шаг и включить трассировку вызовов системной библиотеки, указав параметр -S
для ltrace
. Этот параметр отключен/отключен по умолчанию, так как вывод будет немного подробным, и, вероятно, предполагается, что системные библиотеки, как правило, намного более стабильны и поэтому не нуждаются в трассировке для начала. Давайте посмотрим.
ltrace -fS tar -hcf --xz archive.tar.xz *
Или, для целей тестирования:

ltrace -fS tar -hcf --xz archive.tar.xz * 2>&1 | head -n10
ltrace -fS tar -hcf --xz archive.tar.xz * 2>&1 | tail -n10
Поскольку вывод был значительным, нам пришлось захватить первую и последнюю десять строк с помощью команд head
и tail
. Чтобы иметь возможность использовать эти команды, нам пришлось перенаправить stderr
на stdout
, используя перенаправление 2>&1
как ltrace
. по умолчанию будет сообщать о stderr
. Если вы хотите узнать больше о перенаправлении, см. Bash Automation и основы создания сценариев (часть 3).
Теперь, когда мы добавили параметр -S
, мы можем видеть все доступные библиотеки. Например, мы видим доступ к /etc/ld.so.preload
. Вывод является последовательным (сверху вниз), поэтому, если между ними есть другие события (разветвление подпроцесса и т. д.), они будут отображаться встроенными в момент их возникновения. Мы также можем добавить параметр -t
для вывода на основе времени:

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