Libtree : un ldd qui explique sous forme d’arbre la découverte des bibliothèques
(github.com/haampie)- libtree est un outil qui transforme la sortie de
ldden arbre et explique comment les bibliothèques partagées sont trouvées, ou pourquoi elles sont introuvables - La sortie par défaut masque certaines dépendances standard ; avec
-v,-vvet-vvv, on peut afficher progressivement les bibliothèques masquées ainsi que les dépendances des bibliothèques déjà rencontrées --pathou-paffiche les chemins au lieu des sonames, et--max-depthpermet de limiter la profondeur de l’exploration récursive- L’installation est possible via les binaires précompilés v3.1.1, Fedora/RHEL/CentOS, Ubuntu 22.04+ et GNU Guix
- La compilation depuis les sources nécessite un compilateur C compatible C99 ; avec
make, l’utilisation deLDFLAGS=-staticest recommandée
Ce que fait libtree
- libtree est un outil qui transforme
ldden une représentation arborescente - Il explique comment les bibliothèques partagées sont trouvées, ou pourquoi leur emplacement ne peut pas être déterminé
- Le README inclut une capture d’écran
doc/screenshot.png
Options de sortie
- La sortie par défaut n’affiche pas certaines dépendances standard
- Une sortie plus détaillée se contrôle avec les options de verbosité
libtree -v: affiche les bibliothèques ignorées par défautlibtree -vv: affiche aussi les dépendances des bibliothèques ignorées par défautlibtree -vvv: affiche aussi les dépendances des bibliothèques déjà rencontrées
- L’option
--pathou-paffiche les chemins au lieu des sonames- Exemple :
libtree -p $(which tar)
- Exemple :
--max-depthlimite la profondeur de récursion
Méthodes d’installation
- Binaires précompilés pour la v3.1.1 : fournit des binaires précompilés pour Linux
- Sur Fedora / RHEL / CentOS, l’installation se fait avec
dnf- Pour RHEL et ses distributions dérivées, activez d’abord
epel-release dnf install libtree-ldd
- Pour RHEL et ses distributions dérivées, activez d’abord
- Sur Ubuntu 22.04+, l’installation se fait avec
apt-get install libtree - Sur GNU Guix, l’installation se fait avec
guix install libtree - Une ancienne version v2.0.0 est également disponible
Compiler depuis les sources
libtreenécessite un compilateur C compatible C99- La procédure de compilation de base consiste à cloner le dépôt puis à exécuter
makegit clone https://github.com/haampie/libtree.gitcd libtreemake
- Avec
make, l’utilisation deLDFLAGS=-staticest recommandée - Le README propose aussi, dans une section repliable séparée, une commande d’installation rapide non sécurisée qui récupère
libtree.caveccurlpuis le compile
2 commentaires
Commentaires sur Hacker News
Cet outil reprend-il lui aussi le comportement inattendu de
ldd, qui finit par exécuter une partie des bibliothèques inspectées ?https://catonmat.net/ldd-arbitrary-code-execution
lddvieilles d’environ 5 ans ou plus n’exécutent plus le binaire cibleRéférence : https://manpages.debian.org/unstable/manpages/ldd.1.en.html#...
En pratique, il semble parser directement les fichiers ELF et parser aussi les dépendances récursivement, ce qui est plutôt élégant
objdump, on peut afficher les données exactement telles qu’elles sont encodées dans le fichier ELFY compris la liste des bibliothèques que vdso ira chercher
Il existe un outil similaire, lddtree
https://github.com/gentoo/pax-utils/tree/master
Devoir suivre récursivement les dépendances manquantes avec
lddest assez pénibleDonc ça ressemble à une bonne amélioration, et je compte l’essayer la prochaine fois que je tomberai sur un
not foundambiguEn gros, c’est la version Linux CLI de depends.exe
Mieux vaut utiliser https://github.com/lucasg/Dependencies à la place. Ce n’est pas totalement à jour non plus, mais…
Si vous avez installé Visual Studio et choisi
x64/x86 build tools (latest)dans l’installateur, lancerdumpbin /dependentsdepuis le VS Developer Command Prompt reste l’option la plus fiable[1] https://www.dependencywalker.com/
Pour ceux qui se demandent à quoi correspondent les couleurs, je n’ai rien trouvé dans la manpage ni le README
Magenta : présent dans la liste d’exclusion, affiché uniquement avec
-v[v[v]]Bleu : élément déjà vu, ce qui permet de repérer les dépendances qui apparaissent plusieurs fois
Que signifie exactement « pourquoi une bibliothèque est trouvée ou non » ? Elle est soit dans
LD_LIBRARY_PATH, soit elle n’y est pas, non ?Rien qu’avec la capture d’écran, je ne vois pas bien ce que ça veut dire
Il existe plusieurs mécanismes de recherche de répertoires : chemin système, runpath, rpath,
LD_LIBRARY_PATH, etc.Les bibliothèques sont généralement liées sous un nom court comme
foo.so, mais elles peuvent aussi être liées dynamiquement via leur chemin completD’ailleurs, il vaut généralement mieux éviter de définir
LD_LIBRARY_PATHquand on le peut. Ce n’est pas toujours possible, mais une fois défini, il passe tout en haut de la priorité de recherche pour chaque exécution. Même si quelque chose est lié dynamiquement avec le chemin complet d’une bibliothèque,LD_LIBRARY_PATHpasse avant et aplatit complètement le mécanisme de rechercheLD_LIBRARY_PATHL’idée du titre, c’est que libtree permet de retrouver facilement le chemin depuis l’exécutable jusqu’à toutes les dépendances directes et indirectes. L’un des usages est d’aider à comprendre les problèmes de dépendances manquantes
En pratique, si vous utilisez un système de paquets, il est peu probable qu’il manque des dépendances, donc vous utiliserez sans doute libtree pour d’autres raisons
LD_LIBRARY_PATHou pas » : il y a aussi RPATH, évalué au chargement pour chaque bibliothèqueLe point plus général, c’est que les dépendances forment un graphe, qu’on peut représenter comme un arbre. Il est utile de savoir quelle bibliothèque a entraîné l’impossibilité d’en trouver une autre
LD_LIBRARY_PATH. Le chargeur prend aussi en compte plusieurs autres sourcesDans une configuration normale, cela repose sur une combinaison des champs ELF habituels de chaque binaire chargé et d’autres chemins connus du chargeur
Sur un système avec plusieurs versions d’une même bibliothèque, ou plusieurs bibliothèques portant le même nom, dépendre de
LD_LIBRARY_PATHpeut être très myope. Le chargeur parcourt les chemins deLD_LIBRARY_PATHdans l’ordre pour chaque binaire et choisit la première bibliothèque correspondante. À moins d’avoir défini un chemin de priorité plus élevée autrement, ce n’est peut-être pas la bibliothèque réellement voulue, ce qui peut provoquer des erreurs inattendues à l’exécutionUne meilleure approche consiste à définir RPATH vers l’emplacement de la bibliothèque requise par ce binaire
Si l’environnement et les réglages RPATH ne sont pas cohérents, plusieurs versions d’une même bibliothèque peuvent même être chargées simultanément. Cet outil aide à voir s’il y a un problème, et pourquoi
LD_LIBRARY_PATHComme cet outil repose sur
ldd, il interprétera probablement aussiDYLD_LIBRARY_PATH,DYLD_FALLBACK_FRAMEWORK_PATH,DYLD_FALLBACK_LIBRARY_PATH,@executable_path,@loader_path,@rpathVraiment utile. En général, je regarde les sections avec
readelfpour comprendre quelles sont les exigences réellesLD_DEBUG=libs, ce n’est pas suffisant ?Je ne sais pas si c’est un bug, mais dans l’exemple de vim,
lddet libtree affichent des bibliothèques différentesPar exemple,
linux-vdso.so.1apparaît tout en haut dansldd, mais pas du tout dans libtreelinux-vdso.so.1n’est pas une vraie bibliothèque qu’on peut trouver quelque part dans le système de fichiers, et elle n’est pas non plus référencée dans le fichier ELF, donc libtree ne peut pas la connaîtreÀ la place, le noyau la mappe automatiquement dans l’espace d’adressage d’un processus nouvellement démarré. C’est une optimisation pour éviter le surcoût des appels système dans des fonctions comme
gettimeofday. Référence : https://man7.org/linux/man-pages/man7/vdso.7.htmlSur NixOS, j’avais écrit un petit script bancal qui lançait
lddrécursivement pour comprendre ce qu’il fallait inclure afin d’exécuter des binaires closed sourceSi je dois refaire ça un jour, j’essaierai probablement cet outil
Ça a l'air bien !!