PTRACE(2)

NOM
ptrace - Suivre un processus

SYNOPSIS
#include <sys/ptrace.h>

long ptrace(enum __ptrace_request requête, 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.

Le père peut démarrer un suivi en appelant fork(2) et que le fils créé fasse un PTRACE_TRACEME,suivi(engénéral)parun 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 requête indique précisément l'action à entreprendre.

PTRACE_TRACEME
    Le processus en cours va être suivi par son père. Le parent doit être en attente de suivi du fils. 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,cequidonneaupè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. (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,lefilsdoitêtrearrêté.

PTRACE_PEEKTEXT, PTRACE_PEEKDATA
    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. (data est ignoré).

PTRACE_PEEKUSER
    Lire un mot à l'adresse addr dans l'espace USER du fils, qui contient les registres et diverses informations sur le processus (voir <linux/user.h> et <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 (data est ignoré).

PTRACE_POKETEXT, PTRACE_POKEDATA
    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.

PTRACE_POKEUSER
    Copier un mot depuis l'emplacement data de la mémoire du père vers l'emplacement addr dans l'espace USER 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 sont interdites.

PTRACE_GETREGS, PTRACE_GETFPREGS
    Copier les registres généraux ou du processeur en virgule flottante, vers l'adresse data du père. Voir <linux/user.h> pour les détails sur le format des données (addr est ignoré).

PTRACE_GETSIGINFO (depuis Linux 2.3.99-pre6)
    Obtenir l'information sur le signal qui a provoqué l'arrêt. Copier une structure siginfo_t (voir sigaction(2)) du fils vers data du père. (addr est ignoré.)

PTRACE_SETREGS, PTRACE_SETFPREGS
    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_POKEUSR, certaines modifications sont interdites. (addr est ignoré).

PTRACE_SETSIGINFO (depuis Linux 2.3.99-pre6)
    Configurer l'information du signal. Copie une structure siginfo_t de l'emplacement data du père vers le fils. Cela n'affectera que les signaux qui auraient été normalement délivrés au fils et étaient capturés par le traceur. Il peut être difficile de dire ces signaux normaux à partir de signaux synthétiques générés par ptrace() lui-même. (addr
     est ignoré.)

PTRACE_SETOPTIONS (depuis Linux 2.4.6 ;
    voir BOGUES pour des remarques) Configure les options ptrace pour data du père. (addr est ignoré.) data est interprété comme un masque de bits d'options qui sont spécifiées par les attributs suivants :

    PTRACE_O_TRACESYSGOOD (depuis Linux 2.4.6)
        Lors de la délivrance de déroutements syscall, mettre à 1 le bit 7 dans le numéro de signal (c'est-à-dire, délivrer SIGTRAP | 0x80) . Le traceur peut ainsi indiquer plus facilement la différence entre les déroutements normaux et ceux provoqués par un syscall. (PTRACE_O_TRACESYSGOOD peut ne pas fonctionner sur toutes les architectures.)

    PTRACE_O_TRACEFORK (depuis Linux 2.5.46)
        Arrêter le fils au prochain appel fork(2) avec SIGTRAP | PTRACE_EVENT_FORK << 8 et démarrer automatiquement le suivi du nouveau processus « forké » qui démarrera avec un SIGSTOP. Le PID du nouveau processus peut être obtenu avec PTRACE_GETEVENTMSG.

    PTRACE_O_TRACEVFORK (depuis Linux 2.5.46)
        Arrêter le fils au prochain appel vfork(2) avec SIGTRAP | PTRACE_EVENT_VFORK << 8 et démarrer automatiquement le suivi du nouveau processus « vforké » qui démarrera avec un SIGSTOP. Le PID du nouveau processus peut être obtenu avec PTRACE_GETEVENTMSG.

    PTRACE_O_TRACECLONE (depuis Linux 2.5.46)
        Arrêter le fils au prochain appel clone(2) avec SIGTRAP | PTRACE_EVENT_CLONE << 8 et démarrer automatiquement le suivi du nouveau processus « cloné » qui démarrera avec un SIGSTOP. Le PID du nouveau processus peut être obtenu avec PTRACE_GETEVENTMSG. Cette option peut ne pas attraper les appels clone(2) dans tous les cas. Si le fils appelle clone(2) avec l'attribut CLONE_VFORK, PTRACE_EVENT_VFORK sera délivré à la place si PTRACE_O_TRACEVFORK est positionné ; autrement, si le fils appelle clone(2) avec le signal de sortie configuré à SIGCHLD, PTRACE_EVENT_FORK sera délivré si PTRACE_O_TRACEFORK est positionné.

    PTRACE_O_TRACEEXEC (depuis Linux 2.5.46)
        Arrêter le fils au prochain appel execve(2) avec SIGTRAP | PTRACE_EVENT_EXEC << 8.

    PTRACE_O_TRACEVFORKDONE (depuis Linux 2.5.60)
        Arrêter le fils à la fin du prochain appel vfork(2) avec SIGTRAP | PTRACE_EVENT_VFORK_DONE << 8.

    PTRACE_O_TRACEEXIT (depuis Linux 2.5.60)
        Arrêter le fils à la sortie avec SIGTRAP | PTRACE_EVENT_EXIT << 8. L'état de sortie du fils peut être obtenu avec PTRACE_GETEVENTMSG. Cet arrêt sera effectué plutôt pendant le processus de sortie lorsque les registres sont encore disponibles, permettant au traceur de voir où survient la sortie, alors que la notification de sortie normale est effectuée après que le processus ait achevé sa sortie. Bien que le contexte soit disponible, le traceur ne peut pas empêcher la sortie d'arriver à ce moment-là.

PTRACE_GETEVENTMSG (depuis Linux 2.5.46)
    Obtenir un message (sous la forme d'un unsigned long) d'un événement ptrace qui vient juste d'arriver, le mettre à l'emplacement data du père. Pour PTRACE_EVENT_EXIT, c'est l'état de sortie du fils. Pour PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK et PTRACE_EVENT_CLONE, c'est le 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é.)

PTRACE_CONT
    Redémarrer le processus fils arrêté. Si data n'est pas 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é).

PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP (depuis Linux 2.6.14)
    Pour PTRACE_SYSEMU, continuer et s'arrêter au prochain syscall qui ne sera pas exécuté. Pour PTRACE_SYSEMU_SINGLESTEP, faire la même chose mais en pas-à-pas s'il n'y a pas de syscall. Cet appel est utilisé par des programmes comme « User Mode Linux » qui veulent émuler tous les syscall du fils (addr et data sont ignorés ; pas supporté sur toutes les architectures.)

PTRACE_SYSCALL, PTRACE_SINGLESTEP
    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. (add est ignoré).

PTRACE_KILL
    Envoyer au fils un signal SIGKILL pour le terminer. (addr et data sont ignorés).

PTRACE_ATTACH
    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).

PTRACE_DETACH
    Relancer un processus fils comme avec PTRACE_CONT, en commençant pas le détacher, ce qui rétablit sa parenté originale. 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

EBUSY
    (i386 seulement) Il y a eu une erreur lors de l'allocation ou de la libération d'un registre de débogage.

EFAULT
    Tentative de lire ou écrire dans une zone mémoire invalide du processus ou du père. Malheureusement sous Linux, certaines variantes de cette erreur déclencheront EIO ou EFAULT plus ou moins arbitrairement.

EINVAL
    Une tentative a été faite d'utiliser une option invalide

EIO La requête 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.

EPERM
    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).

ESRCH
    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 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.

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 du signal. Cela signifie que le parent ne peut pas effectuer un ptrace(PTRACE_CONT) avec un signal ou ptrace(PTRACE_KILL). On peut utiliser kill(2) avec un signal SIGKILL plutôt que de tuer le processus fils après 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 sur-ensemble des fonctionnalités de ptrace() de manière plus puissante et plus uniforme.

BOGUES
Sur les hôtes avec des en-têtes noyau 2.6, PTRACE_SETOPTIONS est déclarée avec une valeur différente que celle du noyau 2.4. Cela conduit à ce que les applications compilées avec un tel en-tête ne peuvent pas s'exécuter sur les noyaux 2.4. Cela peut être contourné en redéfinissant PTRACE_SETOPTIONS à PTRACE_OLDSETOPTIONS, si elle est définie.

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

TRADUCTION

Ce document est une traduction réalisée par Christophe Blaess <http://www.blaess.fr/christophe/> le 12 octobre 1996 et révisée le 23 décembre 2007.

L'équipe de traduction a fait le maximum pour réaliser une adaptation française de qualité. La version anglaise la plus à jour de ce document est toujours consultable via la commande : « LANG=C man 2 ptrace ». N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute erreur dans cette page de manuel.