From d070fde6478431c71fb4a55e783a577439c7cb99 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Thu, 20 Jul 2023 14:55:13 -0400 Subject: Multithread version 1 Signed-off-by: Malfurious --- misplays.c | 261 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 171 insertions(+), 90 deletions(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 8f6e0ee..a1f11a4 100644 --- a/misplays.c +++ b/misplays.c @@ -1,7 +1,9 @@ +#include #include #include #include #include +#include #include #include @@ -15,6 +17,9 @@ static PANEL *left, *right; static struct console cons; static int mode = 0; +PANEL *consolepan; + +/* static void describe_status(struct tracee *_dbg, PANEL *pan) { struct tracee dbg = *_dbg; int status = dbg.status; @@ -85,9 +90,10 @@ static void describe_status(struct tracee *_dbg, PANEL *pan) { } } } +*/ -static void list_breakpoints(struct tracee *dbg, PANEL *pan) { - struct list *breaks = &dbg->breaks; +static void list_breakpoints(struct thread *dbg, PANEL *pan) { + struct list *breaks = &dbg->proc->breakpoints; if (breaks->head != breaks->end) { pprintw(pan, "---\n"); @@ -98,7 +104,7 @@ static void list_breakpoints(struct tracee *dbg, PANEL *pan) { } } -static void describe_states(struct tracee *dbg, PANEL *pan) { +static void describe_states(struct thread *dbg, PANEL *pan) { struct list *states = &dbg->states; for (struct state *s = states->head; s != states->end; s = s->next) { pprintw(pan, "%c", (s == dbg->state ? '#' : '-')); @@ -106,7 +112,7 @@ static void describe_states(struct tracee *dbg, PANEL *pan) { pprintw(pan, "\n"); } -static void dump_registers(struct tracee *dbg, PANEL *pan) { +static void dump_registers(struct thread *dbg, PANEL *pan) { struct user_regs_struct *regs = &dbg->state->regs; pprintw(pan, "rax = 0x%016llx\n", regs->rax); pprintw(pan, "rbx = 0x%016llx\n", regs->rbx); @@ -119,7 +125,7 @@ static void dump_registers(struct tracee *dbg, PANEL *pan) { pprintw(pan, "rip = 0x%016llx\n", regs->rip); } -static void dump_stack(struct tracee *dbg, PANEL *pan) { +static void dump_stack(struct thread *dbg, PANEL *pan) { unsigned long sp = dbg->state->regs.rsp; for (size_t i = 0; i < 16; i++, sp += 8) { unsigned long word = *(unsigned long *)deref(dbg, sp,sizeof(unsigned long)); @@ -127,7 +133,17 @@ static void dump_stack(struct tracee *dbg, PANEL *pan) { } } -static void disasm(struct tracee *dbg, PANEL *pan) { +static int rip_visited(struct thread *th, unsigned long rip) { + struct list *states = &th->states; + for (struct state *s = states->head; s != states->end; s = s->next) { + if (rip == s->regs.rip) { + return 1; + } + } + return 0; +} + +static void disasm(struct thread *dbg, PANEL *pan) { csh handle; cs_insn *insn; @@ -139,11 +155,29 @@ static void disasm(struct tracee *dbg, PANEL *pan) { const uint8_t *code = deref(dbg, address, codez); insn = cs_malloc(handle); - for (size_t i = 0; i < 16; i++) { + for (size_t i = 0; i < 32; i++) { if (!cs_disasm_iter(handle, &code, &codez, &address, insn)) { break; } + if (dbg->stopped) { + if (insn->address == dbg->state->regs.rip) { + pattron(pan, COLOR_PAIR(1)); + } else if (is_breakpoint(dbg->proc, insn->address)) { + pattron(pan, COLOR_PAIR(3)); + } else if (rip_visited(dbg, insn->address)) { + pattron(pan, COLOR_PAIR(2)); + } + } pprintw(pan, "0x%"PRIx64":\t%s %s\n", insn->address, insn->mnemonic, insn->op_str); + if (dbg->stopped) { + if (insn->address == dbg->state->regs.rip) { + pattroff(pan, COLOR_PAIR(1)); + } else if (is_breakpoint(dbg->proc, insn->address)) { + pattroff(pan, COLOR_PAIR(3)); + } else if (rip_visited(dbg, insn->address)) { + pattroff(pan, COLOR_PAIR(2)); + } + } } cs_free(insn, 1); @@ -151,13 +185,14 @@ static void disasm(struct tracee *dbg, PANEL *pan) { } } -static void info_update(struct tracee *dbg, PANEL *pan) { +static void info_update(struct thread *dbg, PANEL *pan) { pclear(pan); - pprintw(pan, "PID: %li\n", (long)dbg->id); - if (!dbg->stopped) { - pprintw(pan, "Process is running...\n"); - } else { - describe_status(dbg, pan); + pprintw(pan, "TID: %li\n", (long)dbg->id); + //if (!dbg->stopped) { + // pprintw(pan, "Thread is running...\n"); + //} else { + //describe_status(dbg, pan); + pprintw(pan, "%s (%i)\n", dbg->status, dbg->signal); list_breakpoints(dbg, pan); describe_states(dbg, pan); dump_registers(dbg, pan); @@ -165,52 +200,68 @@ static void info_update(struct tracee *dbg, PANEL *pan) { dump_stack(dbg, pan); pprintw(pan, "---\n"); disasm(dbg, pan); - } + //} } -static void layout(void) { +static void layout(struct process *proc, struct thread *th) { int w = COLS/2; - reset_panel(left, LINES-1, w, 0, 0); - reset_panel(right, LINES-1, COLS-w, 0, w); + reset_panel(left, LINES-2, w, 1, 0); + reset_panel(right, LINES-2, COLS-w, 1, w); + + clear(); + attron(COLOR_PAIR(1)); + struct list *threads = &proc->threads; + for (struct thread *t = threads->head; t != threads->end; t = t->next) { + if (t == th) { + printw("**"); + } + printw("%li (%s)", (long)t->id, t->status); + if (t == th) { + printw("**"); + } + printw(" "); + } + attroff(COLOR_PAIR(1)); + //refresh(); +} + +static void wait_all_threads(struct process *proc) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + dbg_wait(th, 1); + } } int main(int argc, char **argv) { - if (argc < 3) { - fprintf(stderr, "Usage: %s \n", argv[0]); + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } + //getchar(); + cursinit(); left = newpan(0, 0, 0, 0); right = newpan(0, 0, 0, 0); - layout(); - console_init(&cons); + consolepan = right; - argv[argc] = NULL; - struct tracee dbg; - if (dbg_new_process(&dbg, argv+2, &cons)) { - pprintw(right, "Failed to start child\n"); - } + struct process proc; + struct thread *th; - unsigned long stop = strtoul(argv[1], NULL, 0); - if (stop != 0) { - struct breakpoint *b = xmalloc(sizeof(*b)); - b->address = stop; - b->stack = 0; - b->enabled = -1; - b->active = 0; - list_insert(dbg.breaks.end, b); - dbg_cont(&dbg, PTRACE_CONT); + pid_t pid = strtoul(argv[1], NULL, 0); + if (dbg_process(&proc, pid, 0)) { + pprintw(right, "failed to attach process\n"); } + th = proc.threads.head; + int quit = 0; while (!quit) { - //if (dbg.stopped == NULL) { - dbg_wait(&dbg); - //} + wait_all_threads(&proc); console_update(&cons, right); - info_update(&dbg, left); + info_update(th, left); + layout(&proc, th); cursupdate(); int ch = getch(); @@ -218,7 +269,7 @@ int main(int argc, char **argv) { if (mode == 0) { switch (ch) { case KEY_RESIZE: - layout(); + layout(&proc, th); break; case 'q': quit = 1; @@ -228,60 +279,92 @@ int main(int argc, char **argv) { console_enter(&cons, right); break; case 'j': - if (dbg.stopped) { - if (dbg.state != dbg.states.tail) { - dbg.state = dbg.state->next; + dbg_stepin(th); + /* + if (dbg->stopped) { + if (dbg->state != dbg->states.tail) { + dbg->state = dbg->state->next; } else { - dbg_stepover(&dbg); - } - } - break; - case 'k': - if (dbg.stopped) { - if (dbg.state != dbg.states.head) { - dbg.state = dbg.state->prev; - } - } - break; - case 'l': - if (dbg.stopped) { - if (dbg.state != dbg.states.tail) { - //dbg.state = dbg.state->next; - } else { - dbg_stepin(&dbg); + dbg_stepover(dbg); } } + */ break; + //case 'k': + // if (dbg->stopped) { + // if (dbg->state != dbg->states.head) { + // dbg->state = dbg->state->prev; + // } + // } + // break; + //case 'l': + // if (dbg->stopped) { + // if (dbg->state != dbg->states.tail) { + // //dbg.state = dbg.state->next; + // } else { + // dbg_stepin(dbg); + // } + // } + // break; //case 'h': // if (dbg.stopped) { // dbg_stepout(&dbg); // } // break; - case 'g': - if (dbg.stopped) { - dbg.state = dbg.states.head; - } - break; - case 'G': - if (dbg.stopped) { - dbg.state = dbg.states.tail; - } - break; - case 's': - if (dbg.stopped) { - dbg_cont(&dbg, PTRACE_SYSCALL); - } - break; + //case 'g': + // if (dbg->stopped) { + // dbg->state = dbg->states.head; + // } + // break; + //case 'G': + // if (dbg->stopped) { + // dbg->state = dbg->states.tail; + // } + // break; + //case 's': + // if (dbg->stopped) { + // dbg_cont(dbg, PTRACE_SYSCALL); + // } + // break; case 'c': - if (dbg.stopped) { - dbg_cont(&dbg, PTRACE_CONT); - } + dbg_cont(th, PTRACE_CONT); break; case 'p': - if (!dbg.stopped) { - tgkill(dbg.id, dbg.id, SIGSTOP); - } + dbg_intr(th); break; + case 't': + do { + th = th->next; + } while (th == proc.threads.end); + break; + case 'T': + do { + th = th->prev; + } while (th == proc.threads.end); + break; + //case 'd': + // if (dbg->stopped) { + // while (dbg->breaks.head != dbg->breaks.end) { + // struct breakpoint *b = dbg->breaks.head; + // list_remove(b); + // free(b); + // } + // } + // break; + //case 'D': + // if (dbg->stopped) { + // if (ptrace(PTRACE_DETACH, dbg->id, NULL, NULL) < 0) { + // pprintw(right, "PTRACE_DETACH: %s\n", strerror(errno)); + // } + // struct tracee *rm = dbg; + // do { + // dbg = dbg->next; + // } while (dbg == tracees.end); + // list_remove(rm); + // dbg_free(rm); + // free(rm); + // } + // break; case ':': mvprintw(LINES-1, 0, ":"); curs_set(TRUE); @@ -293,25 +376,22 @@ int main(int argc, char **argv) { noecho(); timeout(25); clear(); - refresh(); + //refresh(); char *t = cmd; - struct breakpoint *b = xmalloc(sizeof(*b)); - b->enabled = 1; - b->active = 0; + int en = 1; if (t[0] == '!') { - b->enabled = -1; + en = -1; t++; } - b->address = strtoul(t, NULL, 0); - b->stack = 0; - list_insert(dbg.breaks.end, b); + unsigned long addr = strtoul(t, NULL, 0); + add_breakpoint(&proc, addr, 0, 0, en); break; } } else { switch (ch) { case KEY_RESIZE: - layout(); + layout(&proc, th); break; case 0x1b: mode = 0; @@ -326,6 +406,7 @@ int main(int argc, char **argv) { } } + dbg_detach(&proc); endwin(); return 0; } -- cgit v1.2.3 From b4abda51217101ceffd19c3d403e40781e15dcec Mon Sep 17 00:00:00 2001 From: Malfurious Date: Tue, 19 Sep 2023 11:02:03 -0400 Subject: Multithread version 2 Signed-off-by: Malfurious --- misplays.c | 372 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 168 insertions(+), 204 deletions(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index a1f11a4..4fec040 100644 --- a/misplays.c +++ b/misplays.c @@ -1,10 +1,7 @@ -#include #include +#include #include -#include #include -#include -#include #include #include @@ -12,85 +9,33 @@ #include "console.h" #include "debugger.h" #include "helpers.h" +#include "list.h" static PANEL *left, *right; -static struct console cons; -static int mode = 0; -PANEL *consolepan; - -/* -static void describe_status(struct tracee *_dbg, PANEL *pan) { - struct tracee dbg = *_dbg; - int status = dbg.status; - struct ptrace_syscall_info info; - - if (WIFEXITED(status)) { - pprintw(pan, "exited with code: %u\n", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - pprintw(pan, "terminated by signal: %s\n", strsignal(WTERMSIG(status))); - } else { - unsigned long msg; - if (ptrace(PTRACE_GETEVENTMSG, dbg.id, NULL, &msg) < 0) { - perror("PTRACE_GETEVENTMSG"); - } - - if (WIFSTOPPED(status)) { - switch (status >> 8) { - case ((PTRACE_EVENT_VFORK << 8) | SIGTRAP): - pprintw(pan, "child vfork()'d to: %lu\n", msg); - break; - case ((PTRACE_EVENT_FORK << 8) | SIGTRAP): - pprintw(pan, "child fork()'d to: %lu\n", msg); - break; - case ((PTRACE_EVENT_CLONE << 8) | SIGTRAP): - pprintw(pan, "child clone()'d to: %lu\n", msg); - break; - case ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP): - pprintw(pan, "finished vfork\n"); - break; - case ((PTRACE_EVENT_EXEC << 8) | SIGTRAP): - pprintw(pan, "child exec()'d from: %lu\n", msg); - break; - case ((PTRACE_EVENT_EXIT << 8) | SIGTRAP): - pprintw(pan, "exiting with code: %lu\n", msg); - break; - case ((PTRACE_EVENT_STOP << 8) | SIGTRAP): - pprintw(pan, "child stopped\n"); - break; - case ((PTRACE_EVENT_SECCOMP << 8) | SIGTRAP): - pprintw(pan, "child seccomp event\n"); - break; - - case (SIGTRAP | 0x80): - ptrace(PTRACE_GET_SYSCALL_INFO, dbg.id, sizeof(info), &info); - pprintw(pan, "child entering syscall: %llu (%llx, %llx, %llx, %llx, %llx, %llx)\n", - info.entry.nr, - info.entry.args[0], - info.entry.args[1], - info.entry.args[2], - info.entry.args[3], - info.entry.args[4], - info.entry.args[5]); - break; +static pid_t parse_pid(const char *nptr) { + char *endptr; + pid_t pid = strtoul(nptr, &endptr, 0); + return (*endptr ? 0 : pid); +} - case SIGSTOP: - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - pprintw(pan, "child group-stopped\n"); - break; +static pid_t dofork(char **argv, struct console *cons) { + pid_t pid = fork(); + if (pid < 0) { + return -1; + } - default: - pprintw(pan, "received signal: %s\n", strsignal(WSTOPSIG(status))); - break; - } - } else { - pprintw(pan, "child stop event unrecognized\n"); - } + if (pid == 0) { + console_configslave(cons); + close_range(STDERR_FILENO+1, ~0U, CLOSE_RANGE_UNSHARE); + setpgid(0, 0); + raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); + execvp(argv[0], argv); + exit(EXIT_FAILURE); } + + return pid; } -*/ static void list_breakpoints(struct thread *dbg, PANEL *pan) { struct list *breaks = &dbg->proc->breakpoints; @@ -148,7 +93,7 @@ static void disasm(struct thread *dbg, PANEL *pan) { cs_insn *insn; if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) { - perror("capstone open"); + //perror("capstone open"); } else { uint64_t address = dbg->state->regs.rip; size_t codez = 128; @@ -185,83 +130,97 @@ static void disasm(struct thread *dbg, PANEL *pan) { } } -static void info_update(struct thread *dbg, PANEL *pan) { +static void info_update(struct thread *th, PANEL *pan) { pclear(pan); - pprintw(pan, "TID: %li\n", (long)dbg->id); - //if (!dbg->stopped) { - // pprintw(pan, "Thread is running...\n"); - //} else { - //describe_status(dbg, pan); - pprintw(pan, "%s (%i)\n", dbg->status, dbg->signal); - list_breakpoints(dbg, pan); - describe_states(dbg, pan); - dump_registers(dbg, pan); - pprintw(pan, "---\n"); - dump_stack(dbg, pan); - pprintw(pan, "---\n"); - disasm(dbg, pan); - //} + pprintw(pan, "TID: %li\n", (long)th->id); + pprintw(pan, "%s (%i)\n", th->status, th->signal); + list_breakpoints(th, pan); + describe_states(th, pan); + dump_registers(th, pan); + pprintw(pan, "---\n"); + dump_stack(th, pan); + pprintw(pan, "---\n"); + disasm(th, pan); +} + +static void wait_all_threads(struct list *processes) { + for (struct process *proc = processes->head; proc != processes->end; proc = proc->next) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + dbg_wait(th, 0); + } + } } -static void layout(struct process *proc, struct thread *th) { +static void layout(struct list *processes, struct thread *th) { int w = COLS/2; reset_panel(left, LINES-2, w, 1, 0); reset_panel(right, LINES-2, COLS-w, 1, w); clear(); attron(COLOR_PAIR(1)); - struct list *threads = &proc->threads; - for (struct thread *t = threads->head; t != threads->end; t = t->next) { - if (t == th) { - printw("**"); - } - printw("%li (%s)", (long)t->id, t->status); - if (t == th) { - printw("**"); + + for (struct process *proc = processes->head; proc != processes->end; proc = proc->next) { + struct list *threads = &proc->threads; + for (struct thread *t = threads->head; t != threads->end; t = t->next) { + if (t == th) { + printw("**"); + } + printw("%li (%s)", (long)t->id, t->status); + if (t == th) { + printw("**"); + } + printw(" "); } - printw(" "); } - attroff(COLOR_PAIR(1)); - //refresh(); -} -static void wait_all_threads(struct process *proc) { - struct list *threads = &proc->threads; - for (struct thread *th = threads->head; th != threads->end; th = th->next) { - dbg_wait(th, 1); - } + attroff(COLOR_PAIR(1)); } int main(int argc, char **argv) { if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; + fprintf(stderr, "Usage: %s \n", argv[0]); + return EXIT_FAILURE; } - //getchar(); + getchar(); - cursinit(); - left = newpan(0, 0, 0, 0); - right = newpan(0, 0, 0, 0); + struct console cons = {0}; console_init(&cons); - consolepan = right; - struct process proc; - struct thread *th; + struct list processes = {0}; + struct thread *th = NULL; + list_init(&processes); - pid_t pid = strtoul(argv[1], NULL, 0); - if (dbg_process(&proc, pid, 0)) { - pprintw(right, "failed to attach process\n"); + int child = 0; + pid_t pid = parse_pid(argv[1]); + argv[argc] = NULL; + + if (pid == 0) { + pid = dofork(argv+1, &cons); + child = 1; + } + + struct process *proc = dbg_attach(pid, child); + if (!proc) { + fprintf(stderr, "Failed to attach to process %li\n", (long)pid); + return EXIT_FAILURE; } + list_insert(processes.end, proc); + th = proc->threads.head; - th = proc.threads.head; + cursinit(); + left = newpan(0, 0, 0, 0); + right = newpan(0, 0, 0, 0); + layout(&processes, th); int quit = 0; + int mode = 0; while (!quit) { - wait_all_threads(&proc); + wait_all_threads(&processes); + layout(&processes, th); console_update(&cons, right); info_update(th, left); - layout(&proc, th); cursupdate(); int ch = getch(); @@ -269,7 +228,7 @@ int main(int argc, char **argv) { if (mode == 0) { switch (ch) { case KEY_RESIZE: - layout(&proc, th); + layout(&processes, th); break; case 'q': quit = 1; @@ -279,53 +238,30 @@ int main(int argc, char **argv) { console_enter(&cons, right); break; case 'j': - dbg_stepin(th); - /* - if (dbg->stopped) { - if (dbg->state != dbg->states.tail) { - dbg->state = dbg->state->next; - } else { - dbg_stepover(dbg); - } + dbg_step(th, 1); + break; + case 'k': + dbg_pets(th); + break; + case 'l': + dbg_step(th, 0); + break; + case 'h': + /* todo: step out */ + break; + case 'g': + if (th->stopped) { + th->state = th->states.head; + } + break; + case 'G': + if (th->stopped) { + th->state = th->states.tail; } - */ break; - //case 'k': - // if (dbg->stopped) { - // if (dbg->state != dbg->states.head) { - // dbg->state = dbg->state->prev; - // } - // } - // break; - //case 'l': - // if (dbg->stopped) { - // if (dbg->state != dbg->states.tail) { - // //dbg.state = dbg.state->next; - // } else { - // dbg_stepin(dbg); - // } - // } - // break; - //case 'h': - // if (dbg.stopped) { - // dbg_stepout(&dbg); - // } - // break; - //case 'g': - // if (dbg->stopped) { - // dbg->state = dbg->states.head; - // } - // break; - //case 'G': - // if (dbg->stopped) { - // dbg->state = dbg->states.tail; - // } - // break; - //case 's': - // if (dbg->stopped) { - // dbg_cont(dbg, PTRACE_SYSCALL); - // } - // break; + case 's': + dbg_cont(th, PTRACE_SYSCALL); + break; case 'c': dbg_cont(th, PTRACE_CONT); break; @@ -333,38 +269,19 @@ int main(int argc, char **argv) { dbg_intr(th); break; case 't': + proc = th->proc; do { th = th->next; - } while (th == proc.threads.end); + } while (th == proc->threads.end); + layout(&processes, th); break; case 'T': + proc = th->proc; do { th = th->prev; - } while (th == proc.threads.end); - break; - //case 'd': - // if (dbg->stopped) { - // while (dbg->breaks.head != dbg->breaks.end) { - // struct breakpoint *b = dbg->breaks.head; - // list_remove(b); - // free(b); - // } - // } - // break; - //case 'D': - // if (dbg->stopped) { - // if (ptrace(PTRACE_DETACH, dbg->id, NULL, NULL) < 0) { - // pprintw(right, "PTRACE_DETACH: %s\n", strerror(errno)); - // } - // struct tracee *rm = dbg; - // do { - // dbg = dbg->next; - // } while (dbg == tracees.end); - // list_remove(rm); - // dbg_free(rm); - // free(rm); - // } - // break; + } while (th == proc->threads.end); + layout(&processes, th); + break; /* todo: next/prev process bindings */ case ':': mvprintw(LINES-1, 0, ":"); curs_set(TRUE); @@ -376,24 +293,27 @@ int main(int argc, char **argv) { noecho(); timeout(25); clear(); - //refresh(); + layout(&processes, th); char *t = cmd; int en = 1; if (t[0] == '!') { en = -1; t++; + } else if (t[0] == '#') { + en = 0; + t++; } - unsigned long addr = strtoul(t, NULL, 0); - add_breakpoint(&proc, addr, 0, 0, en); + unsigned long address = strtoul(t, NULL, 0); + add_breakpoint(th->proc, address, 0, 0, en); break; } } else { switch (ch) { case KEY_RESIZE: - layout(&proc, th); + layout(&processes, th); break; - case 0x1b: + case KEY_ESCAPE: mode = 0; console_leave(&cons, right); break; @@ -406,7 +326,51 @@ int main(int argc, char **argv) { } } - dbg_detach(&proc); + dbg_detach(th->proc); /* todo: detach all procs */ endwin(); - return 0; + return EXIT_SUCCESS; } + + + + + + + + + + + + + + +//#include +//#include +//#include +//#include +//#include +//#include + +// //case 'd': +// // if (dbg->stopped) { +// // while (dbg->breaks.head != dbg->breaks.end) { +// // struct breakpoint *b = dbg->breaks.head; +// // list_remove(b); +// // free(b); +// // } +// // } +// // break; +// //case 'D': +// // if (dbg->stopped) { +// // if (ptrace(PTRACE_DETACH, dbg->id, NULL, NULL) < 0) { +// // pprintw(right, "PTRACE_DETACH: %s\n", strerror(errno)); +// // } +// // struct tracee *rm = dbg; +// // do { +// // dbg = dbg->next; +// // } while (dbg == tracees.end); +// // list_remove(rm); +// // dbg_free(rm); +// // free(rm); +// // } +// // break; -- cgit v1.2.3 From 5e20ea14800abaa62b15fcf2bb8462e5661ffdc7 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Mon, 25 Sep 2023 14:50:50 -0400 Subject: Display installed status of breakpoints Signed-off-by: Malfurious --- misplays.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 4fec040..0910012 100644 --- a/misplays.c +++ b/misplays.c @@ -43,7 +43,7 @@ static void list_breakpoints(struct thread *dbg, PANEL *pan) { pprintw(pan, "---\n"); for (struct breakpoint *bp=breaks->head; bp!=breaks->end; bp=bp->next) { - pprintw(pan, "0x%lx ", bp->address); + pprintw(pan, "0x%lx (%c) ", bp->address, (bp->installed ? '*' : ' ')); } pprintw(pan, "\n"); } -- cgit v1.2.3 From 41945242524f9ecc795138fdb5beb31362f7826a Mon Sep 17 00:00:00 2001 From: Malfurious Date: Thu, 28 Sep 2023 15:05:51 -0400 Subject: dbg_realcont for testing purposes Signed-off-by: Malfurious --- misplays.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 0910012..272a60a 100644 --- a/misplays.c +++ b/misplays.c @@ -265,6 +265,9 @@ int main(int argc, char **argv) { case 'c': dbg_cont(th, PTRACE_CONT); break; + case 'C': + dbg_realcont(th); + break; case 'p': dbg_intr(th); break; -- cgit v1.2.3 From 888c7ed10d7d82079c7266f4899c1c6f0c805832 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Thu, 28 Sep 2023 15:36:11 -0400 Subject: Display name of pending signal Signed-off-by: Malfurious --- misplays.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 272a60a..62d89e7 100644 --- a/misplays.c +++ b/misplays.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -133,7 +134,7 @@ static void disasm(struct thread *dbg, PANEL *pan) { static void info_update(struct thread *th, PANEL *pan) { pclear(pan); pprintw(pan, "TID: %li\n", (long)th->id); - pprintw(pan, "%s (%i)\n", th->status, th->signal); + pprintw(pan, "%s (%i: %s)\n", th->status, th->signal, strsignal(th->signal)); list_breakpoints(th, pan); describe_states(th, pan); dump_registers(th, pan); -- cgit v1.2.3 From f9584d0417ed8d3fc72d9dcb297b1738fef2d00c Mon Sep 17 00:00:00 2001 From: Malfurious Date: Thu, 28 Sep 2023 15:40:40 -0400 Subject: setpgid is redundant with setsid and causes an error Signed-off-by: Malfurious --- misplays.c | 1 - 1 file changed, 1 deletion(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 62d89e7..da15a30 100644 --- a/misplays.c +++ b/misplays.c @@ -29,7 +29,6 @@ static pid_t dofork(char **argv, struct console *cons) { if (pid == 0) { console_configslave(cons); close_range(STDERR_FILENO+1, ~0U, CLOSE_RANGE_UNSHARE); - setpgid(0, 0); raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); execvp(argv[0], argv); exit(EXIT_FAILURE); -- cgit v1.2.3 From cca59c4d757c99df14978d1778b6be562dd886cd Mon Sep 17 00:00:00 2001 From: Malfurious Date: Fri, 29 Sep 2023 18:48:41 -0400 Subject: Workaround SIGSTOP on child process startup The debugger design prefers to use PTRACE_SEIZE instead of PTRACE_ATTACH, due to the simpler thread control semantics that are available. However, to utilize the same featureset for forked processes, we can no longer use PTRACE_TRACEME to guarantee that the child becomes a tracee before it execs into the target program. Manually raising SIGSTOP to act as a synchronization point is problematic for a couple reasons: - We need to detect whether the special SIGSTOP was or was not yet encountered by the time our debugger module attaches and interrupts the thread. This complicates the dance of input controls to ensure we are at the exec (and nowhere else) when the real user takes over the controls. - The injection of an extra signal circumvents the benefits we hope to leverage by using the PTRACE_SEIZE semantics. We can no longer assume that all incoming signals are genuine. For the time being, sleep in the newly forked child for the scheduler delay period. This is not bullet-proof, but tends to allow the debugger module enough time to actually seize the thread before anything interesting happens. At this point a single dbg_cont() will cause the child to arrive and stop at the user's exec. Signed-off-by: Malfurious --- misplays.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index da15a30..2f0ce8f 100644 --- a/misplays.c +++ b/misplays.c @@ -27,9 +27,10 @@ static pid_t dofork(char **argv, struct console *cons) { } if (pid == 0) { + usleep(100000); console_configslave(cons); close_range(STDERR_FILENO+1, ~0U, CLOSE_RANGE_UNSHARE); - raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); + //raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); execvp(argv[0], argv); exit(EXIT_FAILURE); } @@ -209,6 +210,10 @@ int main(int argc, char **argv) { list_insert(processes.end, proc); th = proc->threads.head; + if (child) { + dbg_cont(th, PTRACE_CONT); + } + cursinit(); left = newpan(0, 0, 0, 0); right = newpan(0, 0, 0, 0); -- cgit v1.2.3 From 46f72be263cf29688f684e90f2e149e5c911016b Mon Sep 17 00:00:00 2001 From: Malfurious Date: Mon, 2 Oct 2023 03:18:21 -0400 Subject: Multithread version 3 Signed-off-by: Malfurious --- misplays.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 2f0ce8f..815e045 100644 --- a/misplays.c +++ b/misplays.c @@ -44,7 +44,10 @@ static void list_breakpoints(struct thread *dbg, PANEL *pan) { pprintw(pan, "---\n"); for (struct breakpoint *bp=breaks->head; bp!=breaks->end; bp=bp->next) { - pprintw(pan, "0x%lx (%c) ", bp->address, (bp->installed ? '*' : ' ')); + pprintw(pan, "0x%lx (%c) (%i) ", + bp->address, + (bp->installed ? '*' : ' '), + bp->hits); } pprintw(pan, "\n"); } @@ -108,7 +111,7 @@ static void disasm(struct thread *dbg, PANEL *pan) { if (dbg->stopped) { if (insn->address == dbg->state->regs.rip) { pattron(pan, COLOR_PAIR(1)); - } else if (is_breakpoint(dbg->proc, insn->address)) { + } else if (get_breakpoint(dbg->proc, insn->address)) { pattron(pan, COLOR_PAIR(3)); } else if (rip_visited(dbg, insn->address)) { pattron(pan, COLOR_PAIR(2)); @@ -118,7 +121,7 @@ static void disasm(struct thread *dbg, PANEL *pan) { if (dbg->stopped) { if (insn->address == dbg->state->regs.rip) { pattroff(pan, COLOR_PAIR(1)); - } else if (is_breakpoint(dbg->proc, insn->address)) { + } else if (get_breakpoint(dbg->proc, insn->address)) { pattroff(pan, COLOR_PAIR(3)); } else if (rip_visited(dbg, insn->address)) { pattroff(pan, COLOR_PAIR(2)); @@ -211,7 +214,7 @@ int main(int argc, char **argv) { th = proc->threads.head; if (child) { - dbg_cont(th, PTRACE_CONT); + dbg_cont(th); } cursinit(); @@ -243,13 +246,13 @@ int main(int argc, char **argv) { console_enter(&cons, right); break; case 'j': - dbg_step(th, 1); + dbg_stepover(th); break; case 'k': - dbg_pets(th); + dbg_stepback(th); break; case 'l': - dbg_step(th, 0); + dbg_stepin(th); break; case 'h': /* todo: step out */ @@ -265,13 +268,10 @@ int main(int argc, char **argv) { } break; case 's': - dbg_cont(th, PTRACE_SYSCALL); + dbg_syscall(th); break; case 'c': - dbg_cont(th, PTRACE_CONT); - break; - case 'C': - dbg_realcont(th); + dbg_cont(th); break; case 'p': dbg_intr(th); @@ -313,7 +313,8 @@ int main(int argc, char **argv) { t++; } unsigned long address = strtoul(t, NULL, 0); - add_breakpoint(th->proc, address, 0, 0, en); + struct breakpoint *b = add_breakpoint(th->proc, address); + b->enabled = en; break; } } else { -- cgit v1.2.3 From 66db439988aa07828593aac109f5690bb48f2dc9 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Fri, 6 Oct 2023 04:55:18 -0400 Subject: Independent thread control refactor Signed-off-by: Malfurious --- misplays.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 815e045..c064f75 100644 --- a/misplays.c +++ b/misplays.c @@ -149,10 +149,7 @@ static void info_update(struct thread *th, PANEL *pan) { static void wait_all_threads(struct list *processes) { for (struct process *proc = processes->head; proc != processes->end; proc = proc->next) { - struct list *threads = &proc->threads; - for (struct thread *th = threads->head; th != threads->end; th = th->next) { - dbg_wait(th, 0); - } + dbg_sync(proc); } } -- cgit v1.2.3 From 5bb0dfbdb6c0dc1f4a4f0e28393619469a1d4851 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Sat, 7 Oct 2023 02:26:08 -0400 Subject: Tweak SCHEDULER_DELAY for use with installing breakpoints Signed-off-by: Malfurious --- misplays.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index c064f75..e30cc2c 100644 --- a/misplays.c +++ b/misplays.c @@ -27,7 +27,7 @@ static pid_t dofork(char **argv, struct console *cons) { } if (pid == 0) { - usleep(100000); + usleep(10000); console_configslave(cons); close_range(STDERR_FILENO+1, ~0U, CLOSE_RANGE_UNSHARE); //raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); -- cgit v1.2.3 From 0991376bb2c94dc1e2dc85015de6b7e3767247b5 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Sat, 7 Oct 2023 03:28:38 -0400 Subject: Add orig_rax to register display Signed-off-by: Malfurious --- misplays.c | 1 + 1 file changed, 1 insertion(+) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index e30cc2c..6391d98 100644 --- a/misplays.c +++ b/misplays.c @@ -63,6 +63,7 @@ static void describe_states(struct thread *dbg, PANEL *pan) { static void dump_registers(struct thread *dbg, PANEL *pan) { struct user_regs_struct *regs = &dbg->state->regs; + pprintw(pan, "orig_rax = 0x%016llx\n", regs->orig_rax); pprintw(pan, "rax = 0x%016llx\n", regs->rax); pprintw(pan, "rbx = 0x%016llx\n", regs->rbx); pprintw(pan, "rcx = 0x%016llx\n", regs->rcx); -- cgit v1.2.3 From e68b37e4f8af8051ab3ac55b49a742a46b98081b Mon Sep 17 00:00:00 2001 From: Malfurious Date: Sat, 7 Oct 2023 03:32:24 -0400 Subject: Enable user creation of thread-specific breakpoints Signed-off-by: Malfurious --- misplays.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index 6391d98..cda2abb 100644 --- a/misplays.c +++ b/misplays.c @@ -303,16 +303,21 @@ int main(int argc, char **argv) { char *t = cmd; int en = 1; + pid_t tid = 0; if (t[0] == '!') { en = -1; t++; } else if (t[0] == '#') { en = 0; t++; + } else if (t[0] == '@') { + tid = th->id; + t++; } unsigned long address = strtoul(t, NULL, 0); struct breakpoint *b = add_breakpoint(th->proc, address); b->enabled = en; + b->tid = tid; break; } } else { -- cgit v1.2.3 From 574d5a2c4f07bed91d9682e4f48e655e88e37498 Mon Sep 17 00:00:00 2001 From: Malfurious Date: Mon, 9 Oct 2023 16:31:56 -0400 Subject: Implement support for PTRACE_EVENT_FORK and ui Signed-off-by: Malfurious --- misplays.c | 115 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 56 deletions(-) (limited to 'misplays.c') diff --git a/misplays.c b/misplays.c index cda2abb..1ccf3d3 100644 --- a/misplays.c +++ b/misplays.c @@ -160,9 +160,17 @@ static void layout(struct list *processes, struct thread *th) { reset_panel(right, LINES-2, COLS-w, 1, w); clear(); - attron(COLOR_PAIR(1)); for (struct process *proc = processes->head; proc != processes->end; proc = proc->next) { + if (th->proc == proc) { + attron(COLOR_PAIR(1)); + printw("{ "); + } else { + attron(COLOR_PAIR(4)); + printw("{ "); + attroff(COLOR_PAIR(4)); + } + struct list *threads = &proc->threads; for (struct thread *t = threads->head; t != threads->end; t = t->next) { if (t == th) { @@ -172,11 +180,22 @@ static void layout(struct list *processes, struct thread *th) { if (t == th) { printw("**"); } - printw(" "); + + if (t->next != threads->end) { + printw(" "); + } } - } - attroff(COLOR_PAIR(1)); + + if (th->proc == proc) { + printw(" } "); + attroff(COLOR_PAIR(1)); + } else { + attron(COLOR_PAIR(4)); + printw(" } "); + attroff(COLOR_PAIR(4)); + } + } } int main(int argc, char **argv) { @@ -276,18 +295,41 @@ int main(int argc, char **argv) { break; case 't': proc = th->proc; - do { - th = th->next; - } while (th == proc->threads.end); + th = th->next; + if (th == proc->threads.end) { + do { + proc = proc->next; + } while (proc == processes.end); + th = proc->threads.head; + } layout(&processes, th); break; case 'T': proc = th->proc; - do { - th = th->prev; - } while (th == proc->threads.end); + th = th->prev; + if (th == proc->threads.end) { + do { + proc = proc->prev; + } while (proc == processes.end); + th = proc->threads.tail; + } layout(&processes, th); - break; /* todo: next/prev process bindings */ + break; + case 'd': + proc = th->proc; + if (proc->child) { + break; + } + if (proc->prev == proc->next) { + break; + } + struct process *del = proc; + do { + proc = proc->next; + } while (proc == processes.end); + th = proc->threads.head; + dbg_detach(del); + break; case ':': mvprintw(LINES-1, 0, ":"); curs_set(TRUE); @@ -338,51 +380,12 @@ int main(int argc, char **argv) { } } - dbg_detach(th->proc); /* todo: detach all procs */ + for (struct process *p = processes.head; p != processes.end; p = p->next) { + struct process *del = p; + p = p->prev; + dbg_detach(del); + } + endwin(); return EXIT_SUCCESS; } - - - - - - - - - - - - - - -//#include -//#include -//#include -//#include -//#include -//#include - -// //case 'd': -// // if (dbg->stopped) { -// // while (dbg->breaks.head != dbg->breaks.end) { -// // struct breakpoint *b = dbg->breaks.head; -// // list_remove(b); -// // free(b); -// // } -// // } -// // break; -// //case 'D': -// // if (dbg->stopped) { -// // if (ptrace(PTRACE_DETACH, dbg->id, NULL, NULL) < 0) { -// // pprintw(right, "PTRACE_DETACH: %s\n", strerror(errno)); -// // } -// // struct tracee *rm = dbg; -// // do { -// // dbg = dbg->next; -// // } while (dbg == tracees.end); -// // list_remove(rm); -// // dbg_free(rm); -// // free(rm); -// // } -// // break; -- cgit v1.2.3