Я переношу отладчик «pi» («инспектор процессов») в Linux и работаю над кодом для fork/exec дочернего процесса, чтобы проверить его. Я следую стандартной процедуре (я полагаю), но ожидание висит. «hang» — это процедура, которая выполняет работу, аргумент «cmd» — это имя двоичного файла (a.out) для трассировки:
int Hostfunc::hang(char *cmd){
char *argv[10], *cp;
int i;
Localproc *p;
struct exec exec;
struct rlimit rlim;
i = strlen(cmd);
if (++i > sizeof(procbuffer)) {
i = sizeof(procbuffer) - 1;
procbuffer[i] = 0;
}
bcopy(cmd, procbuffer, i);
argv[0] = cp = procbuffer;
for(i = 1;;) {
while(*cp && *cp != ' ')
cp++;
if (!*cp) {
argv[i] = 0;
break;
} else {
*cp++ = 0;
while (*cp == ' ')
cp++;
if (*cp)
argv[i++] = cp;
}
}
hangpid = fork();
if (!hangpid){
int fd, nfiles = 20;
if(getrlimit(RLIMIT_NOFILE, &rlim))
nfiles = rlim.rlim_cur;
for( fd = 0; fd < nfiles; ++fd )
close(fd);
open("/dev/null", 2);
dup2(0, 1);
dup2(0, 2);
setpgid(0, 0);
ptrace(PTRACE_TRACEME, 0, 0, 0);
execvp(argv[0], argv);
exit(0);
}
if (hangpid < 0)
return 0;
p = new Localproc;
if (!p) {
kill(9, hangpid);
return 0;
}
p->sigmsk = sigmaskinit();
p->pid = hangpid;
if (!procwait(p, 0)) {
delete p;
return 0;
}
if (p->state.state == UNIX_BREAKED)
p->state.state = UNIX_HALTED;
p->opencnt = 0;
p->next = phead;
phead = p;
return hangpid;
}
Я вставил 'abort()', чтобы поймать ненулевой возврат из ptrace, но этого не происходит. Вызов 'raise' кажется обычной практикой, но беглый взгляд на код gdb показывает, что он там не используется. В любом случае на результат это не влияет. procwait выглядит следующим образом:
int Hostfunc::procwait(Localproc *p, int flag){
int tstat;
int cursig;
again:
if (p->pid != waitpid(p->pid, &tstat, (flag&WAIT_POLL)? WNOHANG: 0))
return 0;
if (flag & WAIT_DISCARD)
return 1;
if (WIFSTOPPED(tstat)) {
cursig = WSTOPSIG(tstat);
if (cursig == SIGSTOP)
p->state.state = UNIX_HALTED;
else if (cursig == SIGTRAP)
p->state.state = UNIX_BREAKED;
else {
if (p->state.state == UNIX_ACTIVE &&
!(p->sigmsk&bit(cursig))) {
ptrace(PTRACE_CONT, p->pid, 1, cursig, 0);
goto again;
}
else {
p->state.state = UNIX_PENDING;
p->state.code = cursig;
}
}
} else {
p->state.state = UNIX_ERRORED;
p->state.code = WEXITSTATUS(tstat) & 0xFFFF;
}
return 1;
}
«waitpid» в «procwait» просто зависает. Если я запущу программу с приведенным выше кодом и запущу «ps», я увижу, что «pi» разветвлено, но еще не вызвало exec, потому что в командной строке все еще «pi», а не имя двоичный файл, который я разветвляю. Я обнаружил, что если я удаляю «поднять», «пи» все еще висит, но «ps» теперь показывает, что разветвленная программа имеет имя проверяемого двоичного файла, что предполагает, что она выполнила exec.
Итак, насколько я вижу, я следую задокументированным процедурам, чтобы взять под контроль разветвленный процесс, но он не работает.
Ноэль Хант
raise()
в этой версии кода. Обратите внимание, чтоwaitpid
вернется только тогда, когда дочерний процесс остановится, и, поскольку код стоит, я не вижу ничего, что могло бы его остановить. Когда вы надеялись, что это остановится? - person Nate Eldredge   schedule 25.06.2020