Un collègue m'a dit une fois que la dernière option lorsque tout ne pouvait pas déboguer sous Linux était d'utiliser strace .
J’ai essayé d’apprendre les bases scientifiques de cet étrange outil, mais je ne suis pas un gourou de l’administration système et je n’ai pas vraiment obtenu de résultats.
Alors,
En bref, en mots simples , comment ça marche?
Vue d'ensemble de Strace
strace peut être vu comme un débogueur léger. Il permet à un programmeur/utilisateur de savoir rapidement comment un programme interagit avec le système d'exploitation. Pour cela, il surveille les appels et les signaux du système.
Utilisations
Idéal si vous n'avez pas de code source ou si vous ne voulez pas être dérangé pour le parcourir.
En outre, utile pour votre propre code si vous ne souhaitez pas ouvrir GDB, mais êtes simplement intéressé à comprendre les interactions externes.
Une bonne petite introduction
Je suis tombé sur cette introduction pour utiliser strace l’autre jour: strace hello world
En termes simples, strace trace tous les appels système émis par un programme avec leurs codes de retour. Pensez à des choses telles que les opérations de fichier/socket et bien d’autres plus obscures.
Il est très utile d’avoir une connaissance pratique de C, car les appels système correspondraient plus précisément aux appels de bibliothèque C standard.
Disons que votre programme est/usr/local/bin/cough. Utilisez simplement:
strace /usr/local/bin/cough <any required argument for cough here>
ou
strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>
écrire dans 'out_file'.
Toutes les sorties strace iront sur stderr (attention, son volume même demande souvent une redirection vers un fichier). Dans les cas les plus simples, votre programme abandonnera avec une erreur et vous pourrez voir où se trouvent ses dernières interactions avec le système d'exploitation dans la sortie strace.
Plus d'informations devraient être disponibles avec:
man strace
strace répertorie tous les appels système effectués par le processus auquel il est appliqué. Si vous ne savez pas ce que les appels système signifient, vous ne pourrez pas en utiliser beaucoup.
Néanmoins, si votre problème concerne des fichiers, des chemins ou des valeurs d’environnement, exécuter strace sur le programme qui pose problème et rediriger la sortie vers un fichier, puis insérer ce fichier dans votre chaîne path/file/env peut vous aider à voir ce que votre programme est en fait essayer de faire, par opposition à ce que vous espériez.
Strace est un outil d’investigation des systèmes de production dans lequel vous ne pouvez pas vous permettre d’exécuter ces programmes sous un débogueur. En particulier, nous avons utilisé strace dans les deux situations suivantes:
Pour un exemple d'analyse utilisant strace, voir ma réponse à cette question .
J'utilise strace tout le temps pour résoudre les problèmes d'autorisation. La technique va comme ceci:
$ strace -e trace=open,stat,read,write gnome-calculator
Où gnome-calculator
est la commande à exécuter.
strace -tfp PID surveillera les appels système du processus PID, nous pourrons ainsi déboguer/surveiller l'état de notre processus/programme.
Strace peut être utilisé comme outil de débogage ou comme profileur primitif.
En tant que débogueur, vous pouvez voir comment les appels système donnés ont été appelés, exécutés et ce qu’ils renvoient. Ceci est très important, car il vous permet de voir non seulement qu'un programme a échoué, mais POURQUOI un programme a échoué. Habituellement, c'est simplement parce que le codage moche ne permet pas de saisir tous les résultats possibles d'un programme. D'autres fois, il ne s'agit que de chemins codés en dur vers les fichiers. Sans effort, vous devez deviner ce qui ne va pas, où et comment. Avec strace, vous obtenez une ventilation d'un appel système, généralement, le simple fait de regarder une valeur de retour en dit long.
Le profilage est un autre usage. Vous pouvez l'utiliser pour chronométrer l'exécution de chaque appel système individuellement ou globalement. Cela ne suffira peut-être pas à résoudre vos problèmes, mais au moins, cela réduira considérablement la liste des suspects potentiels. Si vous voyez beaucoup de paires fopen/close sur un seul fichier, vous ouvrez et fermez probablement inutilement les fichiers à chaque exécution d'une boucle, au lieu de l'ouvrir et de la fermer en dehors d'une boucle.
Ltrace est le cousin proche de Strace, également très utile. Vous devez apprendre à différencier l'endroit où se trouve votre goulot d'étranglement. Si une exécution totale est de 8 secondes et que vous ne consacrez que 0,05 seconde aux appels système, le traçage du programme ne vous fera pas beaucoup de bien, le problème provient de votre code, qui est généralement un problème de logique, ou le programme a réellement besoin prendre ce temps pour courir.
Le plus gros problème avec strace/ltrace est leur lecture. Si vous ne savez pas comment les appels sont passés, ou du moins les noms d'appels système/fonctions, il sera difficile de déchiffrer le sens. Savoir ce que les fonctions renvoient peut également être très utile, en particulier pour différents codes d'erreur. Bien qu'il soit difficile à déchiffrer, ils renvoient parfois vraiment une perle de savoir; une fois que j’ai vu une situation où j’ai manqué d’inodes, mais pas d’espace libre, tous les utilitaires habituels ne me donnaient aucun avertissement, je ne pouvais tout simplement pas créer un nouveau fichier. La lecture du code d'erreur de la sortie de strace m'a orienté dans la bonne direction.
strace est un bon outil pour apprendre comment votre programme effectue différents appels système (demandes au noyau) et indique également ceux qui ont échoué, ainsi que la valeur d'erreur associée à cet échec. Tous les échecs ne sont pas des bugs. Par exemple, un code qui tente de rechercher un fichier peut générer une erreur ENOENT (aucun fichier ou répertoire de ce type), mais cela peut constituer un scénario acceptable dans la logique du code.
Un bon cas d'utilisation de strace consiste à déboguer des conditions de concurrence pendant la création de fichiers temporaires. Par exemple, un programme susceptible de créer des fichiers en ajoutant l'ID de processus (PID) à une chaîne prédéfinie peut être confronté à des problèmes dans des scénarios multithreads. [Un PID + TID (ID de processus + ID de thread) ou un meilleur appel système tel que mkstemp résoudra ce problème].
C'est également bon pour le débogage des accidents. Vous pouvez trouver cet article (mon article) sur strace et les plantages de débogage utile.
Strace est un outil qui vous explique comment votre application interagit avec votre système d'exploitation.
Pour ce faire, il vous indique le système d’exploitation appelé par votre application et les paramètres qu’elle appelle.
Ainsi, par exemple, vous voyez les fichiers que votre programme essaie d'ouvrir et vous réussissez si l'appel échoue.
Vous pouvez résoudre toutes sortes de problèmes avec cet outil. Par exemple, si l'application déclare ne pas pouvoir trouver la bibliothèque sur laquelle vous savez que vous avez installé, strace vous dira où l'application cherche ce fichier.
Et ce n’est que la partie visible de l’iceberg.
Exemple minimal exécutable
Si un concept n'est pas clair, voici un exemple plus simple que vous n'avez pas vu et qui l'explique.
Dans ce cas, cet exemple est le monde hello Linux x86_64 Assembly autoportant (sans libc):
bonjour.S
.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
Assemblez et courez:
as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out
Sortie attendue:
hello
Maintenant, utilisons strace sur cet exemple:
env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log
Nous utilisons:
env -i ASDF=qwer
pour contrôler les variables d'environnement: https://unix.stackexchange.com/questions/48994/how-to-run-a-program-in-a--clean-environment- in-bash-s999 -v
pour afficher des informations plus complètes sur les journauxstrace.log
contient maintenant:
execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6) = 6
exit(0) = ?
+++ exited with 0 +++
Avec un exemple aussi minime, chaque caractère de la sortie est évident:
execve
ligne: montre comment strace
a exécuté hello.out
, y compris les arguments de la CLI et l'environnement, comme indiqué à l'adresse man execve
write
ligne: affiche l'appel système d'écriture que nous avons effectué. 6
est la longueur de la chaîne "hello\n"
.
= 6
est la valeur de retour de l'appel système qui, comme indiqué dans man 2 write
, correspond au nombre d'octets écrits.
exit
ligne: affiche l'appel système de sortie que nous avons effectué. Il n'y a pas de valeur de retour, puisque le programme a arrêté!
Exemples plus complexes
Bien sûr, l’application de strace permet de savoir quels appels système sont réellement effectués par des programmes complexes afin de vous aider à déboguer/optimiser votre programme.
Notamment, la plupart des appels système que vous êtes susceptible de rencontrer sous Linux ont des wrappers glibc, , souvent issus de POSIX .
En interne, les wrappers glibc utilisent inline Assembly plus ou moins comme ceci: Comment appeler un appel système via sysenter in inline assembly?
Le prochain exemple que vous devriez étudier est un monde POSIX write
hello:
principal c
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *msg = "hello\n";
write(1, msg, 6);
return 0;
}
Compiler et exécuter:
gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Cette fois-ci, vous constaterez que glibc effectue une série d'appels système avant main
pour configurer un environnement Nice pour main.
En effet, nous n’utilisons plus de programme autonome, mais plutôt un programme glibc plus courant, permettant la fonctionnalité libc.
Ensuite, à chaque fin, strace.log
contient:
write(1, "hello\n", 6) = 6
exit_group(0) = ?
+++ exited with 0 +++
Nous concluons donc que la fonction write
POSIX utilise, surprise !, l'appel système Linux write
.
Nous observons également que return 0
conduit à un appel exit_group
au lieu de exit
. Ha, je ne savais pas à propos de celui-ci! C'est pourquoi strace
est si cool. man exit_group
explique ensuite:
Cet appel système est équivalent à exit (2), sauf qu'il met fin non seulement au thread appelant, mais à tous les threads du groupe de threads du processus appelant.
Et voici un autre exemple où j’ai étudié l’appel système dlopen
utilisé: https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to -load-libraries-in-linux/462710 # 462710
Testé sous Ubuntu 16.04, GCC 6.4.0, noyau Linux 4.4.0.
J'ai aimé certaines des réponses où il est écrit strace
vérifie votre interaction avec votre système d'exploitation.
C'est exactement ce que nous pouvons voir. Le système appelle. Si vous comparez strace
et ltrace
, la différence est plus évidente.
$>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
D'autre part, il existe ltrace
qui trace les fonctions.
$>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
Bien que j’ai vérifié les manuels plusieurs fois, je n’ai pas trouvé l’origine du nom strace
, mais il s’agit probablement d’une trace d’appel système, car elle est évidente.
Il y a trois notes plus importantes à dire à propos de strace
.
Remarque 1: Ces deux fonctions strace
et ltrace
utilisent l'appel système ptrace
. Ainsi, l'appel système ptrace
correspond effectivement au fonctionnement de strace
.
L'appel système ptrace () fournit un moyen par lequel un processus (le "traceur") peut observer et contrôler l'exécution d'un autre processus (le "suivi"), et examiner et modifier la mémoire et les registres du suivi. Il est principalement utilisé pour implémenter le débogage des points d'arrêt et le suivi des appels système.
Remarque 2: Il existe différents paramètres que vous pouvez utiliser avec strace
, car strace
peut être très détaillé. J'aime expérimenter avec -c
qui est comme un résumé des choses. En fonction de -c
, vous pouvez sélectionner un appel système tel que -e trace=open
où vous ne verrez que cet appel. Cela peut être intéressant si vous examinez les fichiers qui seront ouverts lors de la commande que vous tracez. Et bien sûr, vous pouvez utiliser grep
dans le même but, mais notez que vous devez rediriger comme ceci 2>&1 | grep etc
pour comprendre que les fichiers de configuration sont référencés lors de l'exécution de la commande.
Note 3: Je trouve cette note très importante. Vous n'êtes pas limité à une architecture spécifique. strace
vous épatera, car il peut tracer des binaires de différentes architectures.