Если у меня есть такой код:
void child() {
do_something();
ptrace(PTRACE_TRACEME, 0, 0, 0);
do_some_other_things();
}
тогда будет do_something()
быть прослеженным родителем?
Я нашел в документации Linux, не было такого. Это только сказало, что это должно быть вызвано в следе.
PTRACE_TRACEME
Укажите, что этот процесс должен отслеживаться его родителем.
процесс, вероятно, не должен делать этот запрос, если его родитель
не ожидает отследить это. (pid, addr и data
игнорируется.)
Увидеть Как работают отладчики, часть 1 для лучшего объяснения, но в итоге, нет, он не будет отслеживать функцию do_something (), пока трассировка не получит сигнал.
В описании ptrace звонить из того же мужчина Вы цитировали:
Процесс может инициировать трассировку, вызывая fork (2) и имея
получающийся ребенок делает
PTRACE_TRACEME, за которым следует (обычно) execve (2). В качестве альтернативы, может начаться один процесс
отслеживание другого процесса с использованием PTRACE_ATTACH или PTRACE_SEIZE.Во время трассировки трассировка будет останавливаться при каждой доставке сигнала, даже если сигнал
игнорируется. (Исключением является SIGKILL, который имеет свой обычный эффект.)
уведомил при следующем вызове waitpid (2) (или об одном из связанных системных вызовов «wait»); этот звонок
вернет значение состояния, содержащее информацию, указывающую причину остановки в
Tracee.
Когда трассировка вызывает exec, она получает сигнал, поэтому останавливается.
Для иллюстрации, программа tracer mainer.c без наворотов:
//mainer.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <unistd.h>
int main(int argc, char ** argv)
{
pid_t child_pid;
char * programname = argv[1];
child_pid = fork();
if (child_pid == 0)
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(programname, programname, NULL);
}
else if (child_pid > 0)
{
int status;
wait(&status);
while (WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child_pid, 0, ®s);
unsigned instr = (PTRACE_PEEKTEXT, child_pid, regs.eip, 0);
printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr);
ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0);
wait(&status);
}
}
}
Когда трассировка нажимает exec, она получит сигнал и передаст управление ожидающему родительскому элементу.
Отслеживание ассемблерной программы, при трассировке C-программы слишком много происходит, чтобы извлечь что-то полезное:
; hello.asm
section .text
global _start
_start:
mov edx,len1
mov ecx,hello1
mov ebx,1
mov eax,4
int 0x80mov edx,len2
mov ecx,hello2
mov ebx,1
mov eax,4
int 0x80
mov eax,1
int 0x80
section .data
hello1 db "Hello",0xA
len1 equ $ - hello1
hello2 db "World",0xA
len2 equ $ - hello2
Запустив это, ./mainer hello
EIP = 0x08048080, instr = 0x00000000
EIP = 0x08048085, instr = 0x00000000
EIP = 0x0804808a, instr = 0x00000000
EIP = 0x0804808f, instr = 0x00000000
EIP = 0x08048094, instr = 0x00000000
Hello
EIP = 0x08048096, instr = 0x00000000
EIP = 0x0804809b, instr = 0x00000000
EIP = 0x080480a0, instr = 0x00000000
EIP = 0x080480a5, instr = 0x00000000
EIP = 0x080480aa, instr = 0x00000000
World
EIP = 0x080480ac, instr = 0x00000000
EIP = 0x080480b1, instr = 0x00000000
Если мы изменим mainer.c так, чтобы дочерний процесс вызывал do_something () до его запуска, результат трассировки будет точно таким же. Это то, как я изменил это, вы можете подтвердить себя, если вам нравится, что результаты совпадают.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <unistd.h>
int do_something(void) //added this function
{
printf("Doing something");
return 0;
}int main(int argc, char ** argv)
{
pid_t child_pid;
char * programname = argv[1];
child_pid = fork();
if (child_pid == 0)
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
do_something(); //added this function call
execl(programname, programname, NULL);
}
else if (child_pid > 0)
{
int status;
wait(&status);
while (WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child_pid, 0, ®s);
unsigned instr = (PTRACE_PEEKTEXT, child_pid, regs.eip, 0);
printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr);
ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0);
wait(&status);
}
}
}
Таким образом, трассировка не остановится, пока не получит сигнал, что происходит при вызове exec, и вызывающие функции не генерируют сигнал для трассировки, но есть другие способы отправить сигнал трассировке и начать трассировку. , хотя они не такие аккуратные, как exec и ждут.
Других решений пока нет …