Scroll to navigation

PTRACE(2) Manuel du programmeur Linux PTRACE(2)

NOM

ptrace - Suivre un processus

SYNOPSIS

#include <sys/ptrace.h>

long ptrace(enum __ptrace_request request, pid_t pid, 
            void *addr, void *data);

DESCRIPTION

L'appel système ptrace() fournit au processus parent un moyen de contrôler l'exécution d'un autre processus et d'éditer son image mémoire. L'utilisation primordiale de cette fonction est l'implémentation de points d'arrêt pour le débogage, et pour suivre les appels système.

Le père peut démarrer un suivi en appelant fork(2) et que le fils créé fasse un PTRACE_TRACEME, suivi (en général) par un exec(3). Autrement, le père peut commencer un suivi sur un processus existant en utilisant PTRACE_ATTACH.

Le processus fils suivi s'arrêtera à chaque fois qu'un signal lui sera délivré, même si le signal est ignoré (à l'exception de SIGKILL qui a les effets habituels). Le père sera prévenu à son prochain wait(2) et pourra inspecter et modifier le processus fils pendant son arrêt. Le parent peut également faire continuer l'exécution de son fils, éventuellement en ignorant le signal ayant déclenché l'arrêt, ou envoyant un autre signal.

Quand le père a fini le suivi, il peut terminer le fils avec PTRACE_KILL ou le faire continuer normalement, non suivi, avec PTRACE_DETACH.

La valeur de l'argument request indique précisément l'action à entreprendre.

Le processus en cours va être suivi par son père. Tout signal (sauf SIGKILL) reçu par le processus l'arrêtera, et le père sera notifié grâce à wait(2). De plus, les appels ultérieurs à execve(2) par ce processus lui enverront SIGTRAP, ce qui donne au père la possibilité de reprendre le contrôle avant que le nouveau programme continue son exécution. Un processus ne doit pas envoyer cette requête si son père n'est pas prêt à le suivre. Dans cette requête pid, addr, et data sont ignorés.

La requête ci-dessus ne sert que dans le processus fils. Les autres ne servent que dans le père. Par la suite, pid précise le fils sur lequel agir. Pour les requêtes autres que PTRACE_KILL, le fils doit être arrêté.

Lire un mot à l'adresse addr dans l'espace mémoire du fils et renvoyer la valeur en résultat de ptrace(). Linux ne sépare pas les espaces d'adressage de code et de données, ainsi ces deux requêtes sont équivalentes. L'argument data est ignoré.
Lire un mot à l'adresse addr dans l'espace USER du fils, qui contient les registres et diverses informations sur le processus (voir <sys/user.h>). La valeur est renvoyée en résultat de ptrace(). En principe, l'adresse doit être alignée sur une frontière de mots, bien que cela varie selon les architectures. Consultez la section NOTES. data est ignoré.
Copier un mot depuis l'adresse data de la mémoire du père vers l'adresse addr de la mémoire du fils. Comme précédemment, les deux requêtes sont équivalentes.
Copier un mot depuis l'emplacement data de la mémoire du père vers l'emplacement addr dans l'espace USER du processus fils. Comme plus haut, les emplacements doivent être alignés sur une frontière de mot. Pour maintenir l'intégrité du noyau, certaines modifications de la zone USER sont interdites.
Copier les registres généraux ou du processeur en virgule flottante, vers l'adresse data du père. Voir <sys/user.h> pour les détails sur le format des données (addr est ignoré).
Récupérer des informations sur le signal qui a causé l'arrêt. Pour ce faire, copier une structure siginfo_t (voir sigaction(2)) du fils à l'adresse data du père. L'argument addr est ignoré.
Remplir les registres généraux ou du processeur en virgule flottante, depuis le contenu de l'adresse data du père. Comme pour PTRACE_POKEUSER certaines modifications sont interdites. (addr est ignoré).
Fixer des informations de signaux. Copier une structure siginfo_t de l'adresse data dans le père vers le fils. Cela n'affecte que les signaux qui auraient dû être délivrés au fils et ont été interceptés à cause de ptrace(). Il peut être difficile de différencier ces signaux normaux des signaux générés par ptrace() lui-même. L'argument addr est ignoré.
Fixe les options de ptrace à partir de l'adresse data dans le père (addr est ignoré). data est interprété comme un masque d'options, qui est construit à partir des drapeaux suivants :
Lors d'un appel système, mettre à 1 le bit 7 du numéro de signal (envoyer SIGTRAP|0x80). Cela permet au processus utilisant ptrace() de faire la différence entre une trappe normale, et une trappe due à un appel système. PTRACE_O_TRACESYSGOOD peut ne pas marcher sur toutes les architectures.
Arrêter le fils au prochain fork(2) avec SIGTRAP | PTRACE_EVENT_FORK << 8 et commencer automatiquement à suivre le nouveau processus créé, qui démarrera avec un signal SIGSTOP. Le PID du nouveau processus peut être récupéré avec PTRACE_GETEVENTMSG.
Arrêter le fils au prochain appel vfork(2) avec SIGTRAP | PTRACE_EVENT_VFORK << 8 et commencer automatiquement à suivre le nouveau processus créé, qui démarrera avec un signal SIGSTOP. Le PID du nouveau processus peut être obtenu avec PTRACE_GETEVENTMSG.
Arrêter le fils au prochain appel clone(2) avec SIGTRAP | PTRACE_EVENT_CLONE << 8 et commencer automatiquement à suivre le nouveau processus cloné, qui démarrera avec un signal SIGSTOP. Le PID du nouveau processus peut être obtenu avec PTRACE_GETEVENTMSG. Cette option peut ne pas intercepter tous les appels clone(2). Si le fils appelle clone(2) avec l'attribut CLONE_VFORK, PTRACE_EVENT_VFORK sera envoyé si PTRACE_O_TRACEVFORK est utilisé. Sinon, si le fils appelle clone(2) avec SIGCHLD comme signal de terminaison, PTRACE_EVENT_FORK sera envoyé si PTRACE_O_TRACEFORK est utilisé.
Arrêter le fils au prochain appel execve(2) avec SIGTRAP | PTRACE_EVENT_EXEC << 8.
Arrêter le fils à la fin du prochain vfork(2) avec SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8.
Arrêter le fils à sa terminaison avec SIGTRAP | PTRACE_EVENT_EXIT << 8. Le code de retour du fils peut être obtenu avec PTRACE_GETEVENTMSG. Cet arrêt sera effectué tôt dans la terminaison du processus, alors que les registres sont toujours disponibles, ce qui permet au processus utilisant ptrace() de voir où la terminaison s'est produite, alors que la notification de terminaison normale a lieu à la fin de cette terminaison. Même si le contexte est disponible, l'appelant ne peut pas empêcher la terminaison du fils.
Récupérer un message (dans un unsigned long) concernant l'événement ptrace qui vient d'arriver, en le plaçant à l'adresse data dans le père. Pour PTRACE_EVENT_EXIT, il s'agit du code de retour du fils. Pour PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK et PTRACE_EVENT_CLONE, il s'agit du PID du nouveau processus. Depuis Linux 2.6.18, le PID du nouveau processus est également disponible pour PTRACE_EVENT_VFORK_DONE. (addr est ignoré.)
Redémarrer le processus fils arrêté. Si data est non nul et autre que SIGSTOP, il est interprété comme un numéro de signal à délivrer au fils; sinon aucun signal n'est délivré. On peut ainsi contrôler si un signal envoyé au fils doit lui être délivré ou non (addr est ignoré).
Redémarrer le processus fils arrêté comme pour PTRACE_CONT, mais en s'arrangeant pour qu'il soit arrêté à la prochaine entrée ou sortie d'un appel système, ou après la prochaine instruction, respectivement. (Le fils sera aussi arrêté par l'arrivée d'un signal). Du point de vue du père, le fils semblera être arrêté par SIGTRAP. Ainsi, pour PTRACE_SYSCALL l'idée est d'inspecter les arguments de l'appel système au premier arrêt puis de faire un autre PTRACE_SYSCALL et d'inspecter la valeur de retour au second arrêt. Le paramètre data est interprété comme pour PTRACE_CONT. (addr est ignoré).
Pour PTRACE_SYSEMU, continuer puis s'arrêter lors du prochain appel système, qui ne sera pas exécuté. Pour PTRACE_SYSEMU_SINGLESTEP, faire la même chose, mais exécuter pas à pas s'il ne s'agit pas d'un appel système. Cette fonction est utilisée par des programmes comme User Mode Linux, qui veulent émuler tous les appels système du fils. Le paramètre data est interprété comme pour PTRACE_CONT. (addr est ignoré ; cet appel n'est pas disponible sur toutes les architectures.)
Envoyer au fils un signal SIGKILL pour le terminer. (addr et data sont ignorés).
Attacher le processus numéro pid, pour le suivre. Le comportement du fils est le même que s'il avait fait un PTRACE_TRACEME. Le processus appelant devient alors le père pour de nombreuses choses (il recevra les notifications d'événements, et sera indiqué comme le père dans un ps(1)). Mais getppid(2) renverra dans le fils le PID du vrai père. Le processus fils va recevoir un SIGSTOP, mais il ne sera peut-être pas stoppé tout de suite, utilisez wait(2) pour attendre son arrêt (addr et data sont ignorés).
Relancer un processus fils comme avec PTRACE_CONT, en commençant par le détacher, ce qui annule les effets de changement de parenté de PTRACE_ATTACH et les effets de PTRACE_TRACEME. Le processus ne sera plus suivi. Bien que cela soit involontaire, sous Linux un processus suivi peut être détaché ainsi quelque soit la méthode employée pour démarrer le suivi. (addr est ignoré).

VALEUR RENVOYÉE

Pour les requêtes PTRACE_PEEK*, ptrace() renvoie la valeur réclamée et zéro pour les autres requêtes, ou -1 en cas d'échec en remplissant errno avec le code d'erreur. Comme la valeur renvoyée par une requête PTRACE_PEEK* peut légitimement être -1, il faut vérifier errno après un tel appel pour vérifier si une erreur s'est produite.

ERREURS

(i386 seulement) Il y a eu une erreur lors de l'allocation ou de la libération d'un registre de débogage.
Tentative de lire ou écrire dans une zone mémoire invalide du processus fils ou du père, probablement parce que la zone n'était pas projetée ou accessible. Malheureusement sous Linux, certaines variantes de cette erreur déclencheront EIO ou EFAULT plus ou moins arbitrairement.
Tentative d'utiliser une option invalide.
La requête request n'est pas valide ou une tentative de lecture ou d'écriture dans une zone invalide de mémoire a eu lieu. Il peut également y avoir un problème d'alignement sur une frontière de mot, ou une tentative de redémarrage en envoyant un signal invalide.
Le processus indiqué ne peut pas être suivi. Cela peut être dû à un manque de privilège du parent (la capacité nécessaire est CAP_SYS_PTRACE). Les processus non-root ne peuvent pas suivre les processus auxquels ils ne peuvent envoyer de signal, ou ceux qui s'exécutent Set-UID/Set-GID. En outre, le processus visé peut être déjà suivi, ou être init(8) (pid 1).
Le processus indiqué n'existe pas, ou n'est pas suivi par l'appelant, ou n'est pas arrêté (pour les requêtes qui en ont besoin).

CONFORMITÉ

SVr4, BSD 4.3.

NOTES

Bien que les arguments de ptrace() soient interprétés comme dans le prototype plus haut, la bibliothèque glibc déclare ptrace comme une fonction variadique où seul l'argument request est fixé. Ceci signifie que les arguments finaux inutiles peuvent être omis, bien que cela utilise un comportement non documenté de gcc(1).

init(8), le processus numéro 1, ne peut pas être suivi.

La disposition du contenu de la mémoire et de la zone USER dépendent du système d'exploitation et de l'architecture. Le décalage fourni et les données renvoyées peuvent ne pas correspondre entièrement avec la définition d'une structure struct user.

La taille d'un mot (« word ») est déterminée par la version du système d'exploitation (par exemple 32 bits pour Linux-32-bits, etc.)

Le suivi peut engendrer des modifications subtiles dans le fonctionnement du processus. Par exemple, si un processus est attaché avec PTRACE_ATTACH, son père original ne peut plus recevoir les notifications avec wait(2) lorsqu'il s'arrête, et il n'y a pas de moyen de simuler cette notification.

Lorsque le parent reçoit un événement avec PTRACE_EVENT_* activé, le fils n'est pas dans la procédure normale de réception de signal. Cela signifie que le parent ne peut pas exécuter ptrace(PTRACE_CONT) avec un signal ou ptrace(PTRACE_KILL). kill(2) avec un signal SIGKILL peut cependant être utilisé pour tuer le processus fils à la réception d'un de ces messages.

Cette page documente le fonctionnement actuel de ptrace() sous Linux. Celui-ci peut varier sensiblement sur d'autres types d'Unix. De toute façon, l'utilisation de ptrace() dépend fortement de l'architecture et du système d'exploitation.

La page de manuel de SunOS décrit ptrace() comme un appel système «unique and arcane », ce qu'il est. Le mécanisme de débogage basé sur le système proc, présent dans Solaris 2 implémente un surensemble des fonctionnalités de ptrace() de manière plus puissante et plus uniforme.

BOGUES

Sur les machines ayant des en-têtes du noyau 2.6, PTRACE_SETOPTIONS est déclaré avec une valeur différente de celle du noyau 2.4. De ce fait, les applications compilées avec ces en-têtes ne peuvent pas s'exécuter sous des noyaux 2.4. Il est possible de contourner cette difficulté en redéfinissant PTRACE_SETOPTIONS à PTRACE_OLDSETOPTIONS, si cette dernière constante est définie.

VOIR AUSSI

gdb(1), strace(1), execve(2), fork(2), signal(2), wait(2), exec(3), capabilities(7)

COLOPHON

Cette page fait partie de la publication 3.23 du projet man-pages Linux. Une description du projet et des instructions pour signaler des anomalies peuvent être trouvées à l'adresse <URL:http://www.kernel.org/doc/man-pages/>.

TRADUCTION

Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a <URL:http://po4a.alioth.debian.org/> par l'équipe de traduction francophone au sein du projet perkamon <URL:http://alioth.debian.org/projects/perkamon/>.

Christophe Blaess <URL:http://www.blaess.fr/christophe/> (1996-2003), Alain Portal <URL:http://manpagesfr.free.fr/> (2003-2006). Julien Cristau et l'équipe francophone de traduction de Debian (2006-2009).

Veuillez signaler toute erreur de traduction en écrivant à <perkamon-l10n-fr@lists.alioth.debian.org>.

Vous pouvez toujours avoir accès à la version anglaise de ce document en utilisant la commande « LC_ALL=C man <section> <page_de_man> ».

30 mars 2009 Linux