Fix some more kinks in strace.com

This commit is contained in:
Justine Tunney 2022-04-06 12:32:43 -07:00
parent c13142dad2
commit 42fbcff149
2 changed files with 92 additions and 24 deletions

View file

@ -531,8 +531,8 @@ static const struct Errno {
}; };
struct Pid { struct Pid {
struct Pid *next;
int pid; int pid;
uint32_t hash;
bool insyscall; bool insyscall;
struct Syscall *call; struct Syscall *call;
struct Syscall fakecall; struct Syscall fakecall;
@ -541,37 +541,101 @@ struct Pid {
}; };
struct PidList { struct PidList {
struct Pid *head; uint32_t i, n;
struct Pid *p;
}; };
char *ob; // output buffer char *ob; // output buffer
struct Pid *sp; // active subprocess struct Pid *sp; // active subprocess
static uint32_t Hash(uint64_t pid) {
uint32_t hash;
hash = (pid * 6364136223846793005 + 1442695040888963407) >> 32;
if (!hash) hash = 1;
return hash;
}
static struct Pid *GetPid(struct PidList *list, int pid) { static struct Pid *GetPid(struct PidList *list, int pid) {
struct Pid *item; uint32_t i, hash, step;
for (item = list->head; item; item = item->next) { DCHECK_NE(0, pid);
if (item->pid == pid) { DCHECK_LE(list->i, list->n >> 1);
return item; if (list->n) {
} i = 0;
step = 0;
hash = Hash(pid);
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
if (list->p[i].pid == pid) {
return list->p + i;
}
step++;
} while (list->p[i].hash);
} }
return 0; return 0;
} }
static void ReservePid(struct PidList *list, int count) {
size_t i, j, step;
struct PidList old;
DCHECK_LE(list->i, list->n >> 1);
while (list->i + count >= (list->n >> 1)) {
memcpy(&old, list, sizeof(*list));
list->n = list->n ? list->n << 1 : 16;
list->p = calloc(list->n, sizeof(*list->p));
for (i = 0; i < old.n; ++i) {
if (!old.p[i].hash) continue;
step = 0;
do {
j = (old.p[i].hash + step * (step + 1) / 2) & (list->n - 1);
step++;
} while (list->p[j].hash);
list->p[j] = old.p[i];
}
free(old.p);
}
}
static struct Pid *AddPid(struct PidList *list, int pid) { static struct Pid *AddPid(struct PidList *list, int pid) {
struct Pid *item; struct Pid *item;
uint32_t i, hash, step;
DCHECK_NE(0, pid);
DCHECK_LE(list->i, list->n >> 1);
if (!(item = GetPid(list, pid))) { if (!(item = GetPid(list, pid))) {
item = calloc(1, sizeof(struct Pid)); ReservePid(list, 1);
item->pid = pid; hash = Hash(pid);
item->next = list->head; ++list->i;
list->head = item; i = 0;
step = 0;
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
step++;
} while (list->p[i].hash);
list->p[i].hash = hash;
list->p[i].pid = pid;
item = list->p + i;
} }
return item; return item;
} }
static void RemovePid(struct PidList *list, struct Pid *item) { static void RemovePid(struct PidList *list, int pid) {
struct Pid **p = &list->head; uint32_t i, hash, step;
while (*p != item) p = &(*p)->next; DCHECK_NE(0, pid);
*p = item->next; DCHECK_LE(list->i, list->n >> 1);
if (list->n) {
i = 0;
step = 0;
hash = Hash(pid);
do {
i = (hash + step * (step + 1) / 2) & (list->n - 1);
if (list->p[i].pid == pid) {
bzero(list->p + i, sizeof(*list->p));
list->i--;
assert(list->i < 99999);
return;
}
step++;
} while (list->p[i].hash);
}
} }
static ssize_t WriteAll(int fd, const char *p, size_t n) { static ssize_t WriteAll(int fd, const char *p, size_t n) {
@ -668,7 +732,7 @@ static void *PeekData(unsigned long x, size_t size) {
u.word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr); u.word = ptrace(PTRACE_PEEKTEXT, sp->pid, addr);
if (errno) return 0; if (errno) return 0;
p = calloc(1, size); p = calloc(1, size);
memcpy(p, u.buf + offset, 8 - offset); memcpy(p, u.buf + offset, MIN(size, 8 - offset));
for (i = 8 - offset; i < size; i += MIN(8, size - i)) { for (i = 8 - offset; i < size; i += MIN(8, size - i)) {
addr += 8; addr += 8;
errno = 0; errno = 0;
@ -996,7 +1060,9 @@ wontreturn void StraceMain(int argc, char *argv[]) {
exit(1); exit(1);
} }
pidlist.head = 0; pidlist.i = 0;
pidlist.n = 0;
pidlist.p = 0;
sigdfl.sa_flags = 0; sigdfl.sa_flags = 0;
sigdfl.sa_handler = SIG_DFL; sigdfl.sa_handler = SIG_DFL;
@ -1033,17 +1099,19 @@ wontreturn void StraceMain(int argc, char *argv[]) {
for (;;) { for (;;) {
CHECK_NE(-1, (evpid = waitpid(-1, &wstatus, __WALL))); CHECK_NE(-1, (evpid = waitpid(-1, &wstatus, __WALL)));
// prevent rehash in second addpid call
ReservePid(&pidlist, 2);
// we can get wait notifications before fork/vfork/etc. events // we can get wait notifications before fork/vfork/etc. events
sp = AddPid(&pidlist, evpid); sp = AddPid(&pidlist, evpid);
// handle actual exit // handle actual exit
if (WIFEXITED(wstatus)) { if (WIFEXITED(wstatus)) {
kprintf(PROLOGUE " exited with %d%n", sp->pid, WEXITSTATUS(wstatus)); kprintf(PROLOGUE " exited with %d%n", sp->pid, WEXITSTATUS(wstatus));
RemovePid(&pidlist, sp); RemovePid(&pidlist, sp->pid);
free(sp);
sp = 0; sp = 0;
// we exit when the last process being monitored exits // we exit when the last process being monitored exits
if (!pidlist.head) { if (!pidlist.i) {
PropagateExit(wstatus); PropagateExit(wstatus);
} else { } else {
continue; continue;
@ -1054,11 +1122,10 @@ wontreturn void StraceMain(int argc, char *argv[]) {
if (WIFSIGNALED(wstatus)) { if (WIFSIGNALED(wstatus)) {
kprintf(PROLOGUE " exited with signal %s%n", sp->pid, kprintf(PROLOGUE " exited with signal %s%n", sp->pid,
strsignal(WTERMSIG(wstatus))); strsignal(WTERMSIG(wstatus)));
RemovePid(&pidlist, sp); RemovePid(&pidlist, sp->pid);
free(sp);
sp = 0; sp = 0;
// we die when the last process being monitored dies // we die when the last process being monitored dies
if (!pidlist.head) { if (!pidlist.i) {
PropagateTermination(wstatus); PropagateTermination(wstatus);
} else { } else {
continue; continue;

View file

@ -195,7 +195,8 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
o/$(MODE)/tool/net/redbean-demo.com: \ o/$(MODE)/tool/net/redbean-demo.com: \
o/$(MODE)/tool/net/redbean-demo.com.dbg \ o/$(MODE)/tool/net/redbean-demo.com.dbg \
o/$(MODE)/tool/build/symtab.com \ o/$(MODE)/tool/build/symtab.com \
o/$(MODE)/third_party/infozip/zip.com o/$(MODE)/third_party/infozip/zip.com \
tool/net/help.txt
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-demo @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-demo
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-demo/.ape bs=64 count=11 conv=notrunc 2>/dev/null @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-demo/.ape bs=64 count=11 conv=notrunc 2>/dev/null