Chcę użyć ptrace
, aby sprawdzić, jakie wywołania systemowe program zrodził się w moim programie. Zacząłem od this tutorial, jak to wyjaśniono w odpowiedzi na moją previous question. I zmodyfikowany kod poprzez dostosowanie go do platformy używam (SLES 11 64 bit) i umieścić razem następujący kod testowy, który wypisuje każdy system nazywamy zrodził proces sprawia:Korzystanie z ptrace z aplikacji wielowątkowych
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
run();
}
return 0;
}
To działa bardzo dobrze : wypisuje identyfikator wywołań systemowych tworzonych przez program (w rzeczywistości wypisuje je dwa razy, raz przy wejściu i raz dla wyjścia, ale teraz to nie ma znaczenia). Jednak mój program musi wykonywać inne czynności poza sprawdzaniem wywołań systemowych, dlatego postanowiłem przenieść sprawdzanie do osobnego wątku (bardziej mi odpowiada C++ niż C, więc zrobiłem to w C++, ale ja nie myśl, że to ma znaczenie). Oczywiście w tym najstarszym programie, rozpoczynam tylko wątek, a następnie dołączam do niego.
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
#include <boost/thread.hpp>
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
boost::thread t(run);
t.join();
}
return 0;
}
Tym razem pojawia się komunikat o błędzie:
Child process id = 24682.
Got event from 24682.
ptrace: No such process
dlaczego tak jest? Próbowałem szukać odpowiedzi, ale niczego takiego nie znalazłem. Zauważyłem, że ptrace
nie będzie śledzić wątków rozpoczętych przez proces potomny, ale jest to kolejna rzecz, z którą należy sobie poradzić później. Czy to możliwe, aby sprawdzić proces potomny z innego termo?
Inną dziwną rzeczą jest to, że w mojej prawdziwej aplikacji robię zasadniczo to samo (ale z dużo bardziej skomplikowanego kontekstu: klasy, muteksy itp.) I otrzymuję inny rodzaj błędu. Zamiast ptrace
powraca z błędem, wait
nie zwraca nawet dla wywołań systemowych w procesie potomnym (a proces potomny nawet się nie zatrzymuje). Z drugiej strony, wait
działa zgodnie z oczekiwaniami, gdy proces potomny zostanie zakończony.
Posiadanie dedykowanego wątku mój proces pomógł. – petersohn