NOMBRE¶
ptrace - rastreo de un proceso
SINOPSIS¶
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request petición, pid_t
pid, void *direc, void *datos);
DESCRIPCIÓN¶
La llamada al sistema
ptrace proporciona un medio por el que un proceso
padre puede observar y controlar la ejecución de otro proceso y examinar
y cambiar su imagen de memoria y registros. Se usa principalmente en la
implementación de depuración con puntos de ruptura y en el rastreo
de llamadas al sistema.
El padre puede inicar un rastreo llamando a
fork(2) haciendo que el hijo
restultante realice un PTRACE_TRACEME, seguido (normalmente) por un
exec(3). Alternativamente, el padre puede comenzar a rastrear un
proceso existente usando PTRACE_ATTACH.
Mientras está siendo rastreado, el hijo se detendrá cada vez que
reciba una señal, aun cuando la señal se haya ignorado. (La
excepción es SIGKILL que tiene su efecto habitual.) El padre será
informado en su siguiente
wait(2) y puede inspeccionar y modificar el
proceso hijo mientras está parado. A continuación, el padre puede
hacer que el hijo continúe, ignorando opcionalmente la señal
recibida (o incluso entregando una señal distinta en su lugar). Cuando el
padre termina de rastrear, puede terminar el hijo con PTRACE_KILL o hace que
se continúe ejecutando en un modo normal sin rastreo mediante
PTRACE_DETACH.
El valor del argumento
petición determina la acción a realizar:
- PTRACE_TRACEME
- Indica que este proceso va a ser rastreado por su padre.
Cualquier señal (excepto SIGKILL) entregada a este proceso hará
que se pare y su padre será informado mediante wait.
También, cualquier llamada posterior a exec realizada por este
proceso hará que se le envíe un SIGTRAP, dando al padre la
posibilidad de obtener el control antes de que el nuevo programa comience
su ejecución. Probablemente, un proceso no debería hacer esta
petición si su padre no está esperando para rastrearlo. (
pid, direc y datos se ignoran.)
La petición anterior la usa sólo el proceso hijo. El resto las usa
sólo el padre. En las siguientes peticiones,
pid indica el proceso
hijo sobre el que se actuará. Para peticiones distintas de PTRACE_KILL,
el proceso hijo debe estar parado.
- PTRACE_PEEKTEXT, PTRACE_PEEKDATA
- Lee una palabra de la posición direc.
- PTRACE_PEEKUSER
- Lee una palabra en el desplazamiento direc del
área USER del hijo, que contiene los registros y otra
información sobre el proceso (vea <linux/user.h> y
<sys/user.h>). La palabra se devuelve como resultado de la llamada
ptrace. Típicamente, el desplazamiento debe está alineado
en una frontera de palabra, aunque esto podría variar en cada
arquitectura. ( datos se ignora).
- PTRACE_POKETEXT, PTRACE_POKEDATA
- Copia una palabra de la posición datos a la
posición direc de la memoria del hijo. Como antes, las dos
peticiones son actualmente equivalentes.
- PTRACE_POKEUSER
- Copia una palabra de la posición datos al
desplazamiento direc en el área USER del hijo. Al igual
que antes, el desplazamiento debe estar típicamente alineado en una
frontera de palabra. Para conservar la integridad del núcleo, algunas
modificaciones al área USER se encuentran deshabilitadas.
- PTRACE_GETREGS, PTRACE_GETFPREGS
- Copia los registros de propósito general o de punto
flotante del hijo, respectivamente, a la posición datos del
padre. Vea <linux/user.h> para obtener información sobre el
formato de estos datos. ( direc se ignora.)
- PTRACE_SETREGS, PTRACE_SETFPREGS
- Copia los registros de propósito general o de punto
flotante del hijo, respectivamente, desde la posición datos
del padre. Al igual que para PTRACE_POKEUSER, alguna modificaciones de los
registros de propósito general pueden estar deshabilitadas. (
direc se ignora.)
- PTRACE_CONT
- Reinicia el proceso hijo parado. Si datos no es cero
y tampoco SIGSTOP se interpreta como una señal que se entregará
al hijo. En otro caso, no se entrega ninguna señal. Así, por
ejemplo, el padre puede controlar si una señal enviada al hijo es
entregada o no. ( direc se ignora.)
- PTRACE_SYSCALL, PTRACE_SINGLESTEP
- Reinicia el proceso hijo parado al igual que PTRACE_CONT
pero prepara al hijo para que se pare en la siguiente entrada a o salida
de una llamda al sistema o tras la ejecución de una única
intrucción, respectivamente. (Como es usual, el hijo también se
detendrá al recibir una señal). Desde la perspectiva del padre,
el hijo aparecerá como si se hubiera detenido al recibir una
señal SIGTRAP. Por lo que, por ejemplo, para PTRACE_SYSCALL, la idea
es inspeccionar los argumentos de la llamada al sistema en la primera
parada, realizar a continuación otra PTRACE_SYSCALL e inspeccionar
los valores devueltos por la llamada al sistema cuando se detenga la
segunda vez. ( direc se ignora.)
- PTRACE_KILL
- Envía al hijo una señal SIGKILL para que
termine. ( direc y datos se ignoran.)
- PTRACE_ATTACH
- Ata al proceso especificado en pid,
convirtiéndolo en un "hijo" rastreado. El hijo se comporta
como si hubiera realizado un PTRACE_TRACEME. El proceso actual realmente
se convierte en el padre del proceso hijo para la mayoría de
propósitos (por ejemplo, recibirá notificación de los
eventos del hijo y aparecerá en la salida de ps(1) como padre
del hijo), pero un getppid(2) por parte del hijo todavía
devolverá el pid del padre original. Al hijo se le envía un
SIGSTOP pero, necesariamente, no tiene por qué haberse parado cuando
esta llamada haya terminado. Use wait para esperar a que el hijo se
pare. ( direc y datos se ignoran.)
- PTRACE_DETACH
- Reinicia el hijo parado al igual que PTRACE_CONT pero
primero lo desata del proceso, deshaciendo el efecto de reparentesco de
PTRACE_ATTACH y los efectos de PTRACE_TRACEME. Aunque quizás no sea
intencionado, bajo Linux un proceso rastreado puede ser desatado de esta
manera sin tener en cuenta qué método se usó para iniciar
el rastreo. ( direc is ignored.)
OBSERVACIONES¶
Aunque los argumentos de
ptrace se interpretan según el prototipo
dado, GNU libc declara actualmente
ptrace como una función en la
que sólo el argumento
petición tiene sentido. Esto significa
que se pueden omitir los argumentos del final innecesarios, aunque al hacerlo
así se hace uso de comportamiento de
gcc(1) sin documentar.
init(8), el proceso con PID 1, no puede ser rastreado.
La disposición de los contenidos de memoria y del área USER son
bastante específicos del sistema operativo (y la arquitectura).
El tamaño de una "palabra" viene determinado por la variante del
sistema operativo (por ejemplo, para un Linux de 32 bits es de 32 bits, etc.)
El rastreo provoca unas pocas diferencias sutiles en la semántica de los
procesos rastreados. Por ejemplo, si se ata un proceso con PTRACE_ATTACH, su
padre original ya no puede recibir notificaciones mediante
wait cuando
se detiene y no hay forma de que el nuevo padre pueda simular de forma
efectiva esta notificación.
Esta página documenta la forma en que funciona actualmente la llamada
ptrace en Linux. Su comportamiento difiere notablemente en otros Unix.
En cualquier caso, el uso
ptrace es altamente específico del
sistema operativo (y la arquitectura).
La página de manual de SunOS describe
ptrace como "única y
arcaica", que lo es. La interfaz de depuración basada en el sistema
de ficheros virtual "proc" presente en Solaris 2 implementa un
superconjunto de la funcionalidad de
ptrace de forma más potente y
uniforme.
VALOR DEVUELTO¶
En caso de éxito, las peticiones PTRACE_PEEK* devuelven los datos
solicitados, mientras que las otras peticiones devuelven cero. En caso de
error, todas las peticiones devuelven -1 y a
errno(3) se le asigna un
valor apropiado. Ya que el valor devuelto por una petición PTRACE_PEEK*
con éxito puede ser -1, el invocador debe comprobar
errno
después de tales peticiones para determinar si hubo error o no.
ERRORES¶
- EPERM
- El proceso indicado no puede ser rastreado. Esto
podría deberse a que el padre no tiene suficientes privilegios. Los
procesos que no son del root no pueden rastrear procesos a los que no
pueden enviar señales o programas en ejecución setuid/setgid por
razones obvias. Alternativamente, puede que el proceso ya se esté
rastreando o ser el proceso init (pid 1).
- ESRCH
- El proceso especificado no existe o el invocador no lo
está rastreando actualmente o no está parado (para peticiones
que necesiten que lo esté).
- EIO
- Petición no es válida o se ha intentado
leer de o escribir en una área inválida de la memoria del padre
o del hijo, o se ha producido una violación en la alineación de
palabra o se ha especificado una señal inválida durante una
petición de reinicio.
- EFAULT
- Se ha intentado leer de o escribir en una área
inválida de la memoria del padre o del hijo, probablemente porque el
área no estaba asignada o no era accesible. Desafortunadamente, en
Linux, diferentes versiones de este fallo devolverán EIO o EFAULT de
forma más o menos arbitraria.
SVr4, SVID EXT, AT&T, X/OPEN, BSD 4.3
VÉASE TAMBIÉN¶
gdb(1),
strace(1),
execve(2),
fork(2),
signal(2),
wait(2),
exec(3)