Поиск по сайту:

Как использовать 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 с наиболее часто используемыми параметрами.