diff options
Diffstat (limited to 'misplays.c')
-rw-r--r-- | misplays.c | 392 |
1 files changed, 226 insertions, 166 deletions
@@ -1,8 +1,8 @@ #include <signal.h> -#include <stdlib.h> #include <string.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/ptrace.h> -#include <linux/ptrace.h> #include <unistd.h> #include <capstone/capstone.h> @@ -10,95 +10,50 @@ #include "console.h" #include "debugger.h" #include "helpers.h" +#include "list.h" static PANEL *left, *right; -static struct console cons; -static int mode = 0; - -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) { + usleep(10000); + console_configslave(cons); + close_range(STDERR_FILENO+1, ~0U, CLOSE_RANGE_UNSHARE); + //raise(SIGSTOP); // ptrace(PTRACE_TRACEME, 0, NULL, NULL); + execvp(argv[0], argv); + exit(EXIT_FAILURE); } + + return pid; } -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"); for (struct breakpoint *bp=breaks->head; bp!=breaks->end; bp=bp->next) { - pprintw(pan, "0x%lx ", bp->address); + pprintw(pan, "0x%lx (%c) (%i) ", + bp->address, + (bp->installed ? '*' : ' '), + bp->hits); } pprintw(pan, "\n"); } } -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,8 +61,9 @@ 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, "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); @@ -119,7 +75,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,23 +83,51 @@ 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; 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; 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 (get_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 (get_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,66 +135,117 @@ static void disasm(struct tracee *dbg, PANEL *pan) { } } -static void info_update(struct tracee *dbg, PANEL *pan) { +static void info_update(struct thread *th, 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); - 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: %s)\n", th->status, th->signal, strsignal(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) { + dbg_sync(proc); } } -static void layout(void) { +static void layout(struct list *processes, 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(); + + 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) { + printw("**"); + } + printw("%li (%s)", (long)t->id, t->status); + if (t == th) { + printw("**"); + } + + if (t->next != threads->end) { + printw(" "); + } + } + + + 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) { - if (argc < 3) { - fprintf(stderr, "Usage: %s <stop> <command>\n", argv[0]); - return 1; + if (argc < 2) { + fprintf(stderr, "Usage: %s <pid | cmdline>\n", argv[0]); + return EXIT_FAILURE; } - cursinit(); - left = newpan(0, 0, 0, 0); - right = newpan(0, 0, 0, 0); - layout(); + getchar(); + struct console cons = {0}; console_init(&cons); + struct list processes = {0}; + struct thread *th = NULL; + list_init(&processes); + + int child = 0; + pid_t pid = parse_pid(argv[1]); argv[argc] = NULL; - struct tracee dbg; - if (dbg_new_process(&dbg, argv+2, &cons)) { - pprintw(right, "Failed to start child\n"); + + 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; - 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); + if (child) { + dbg_cont(th); } + cursinit(); + left = newpan(0, 0, 0, 0); + right = newpan(0, 0, 0, 0); + layout(&processes, th); + int quit = 0; + int mode = 0; while (!quit) { - //if (dbg.stopped == NULL) { - dbg_wait(&dbg); - //} + wait_all_threads(&processes); + layout(&processes, th); console_update(&cons, right); - info_update(&dbg, left); + info_update(th, left); cursupdate(); int ch = getch(); @@ -218,7 +253,7 @@ int main(int argc, char **argv) { if (mode == 0) { switch (ch) { case KEY_RESIZE: - layout(); + layout(&processes, th); break; case 'q': quit = 1; @@ -228,59 +263,72 @@ 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; - } else { - dbg_stepover(&dbg); - } - } + dbg_stepover(th); break; case 'k': - if (dbg.stopped) { - if (dbg.state != dbg.states.head) { - dbg.state = dbg.state->prev; - } - } + dbg_stepback(th); break; case 'l': - if (dbg.stopped) { - if (dbg.state != dbg.states.tail) { - //dbg.state = dbg.state->next; - } else { - dbg_stepin(&dbg); - } - } + dbg_stepin(th); + break; + case 'h': + /* todo: step out */ break; - //case 'h': - // if (dbg.stopped) { - // dbg_stepout(&dbg); - // } - // break; case 'g': - if (dbg.stopped) { - dbg.state = dbg.states.head; + if (th->stopped) { + th->state = th->states.head; } break; case 'G': - if (dbg.stopped) { - dbg.state = dbg.states.tail; + if (th->stopped) { + th->state = th->states.tail; } break; case 's': - if (dbg.stopped) { - dbg_cont(&dbg, PTRACE_SYSCALL); - } + dbg_syscall(th); break; case 'c': - if (dbg.stopped) { - dbg_cont(&dbg, PTRACE_CONT); - } + dbg_cont(th); break; case 'p': - if (!dbg.stopped) { - tgkill(dbg.id, dbg.id, SIGSTOP); + dbg_intr(th); + break; + case 't': + proc = th->proc; + 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; + th = th->prev; + if (th == proc->threads.end) { + do { + proc = proc->prev; + } while (proc == processes.end); + th = proc->threads.tail; + } + layout(&processes, th); + 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, ":"); @@ -293,27 +341,33 @@ int main(int argc, char **argv) { noecho(); timeout(25); clear(); - refresh(); + layout(&processes, th); char *t = cmd; - struct breakpoint *b = xmalloc(sizeof(*b)); - b->enabled = 1; - b->active = 0; + int en = 1; + pid_t tid = 0; if (t[0] == '!') { - b->enabled = -1; + en = -1; + t++; + } else if (t[0] == '#') { + en = 0; + t++; + } else if (t[0] == '@') { + tid = th->id; t++; } - b->address = strtoul(t, NULL, 0); - b->stack = 0; - list_insert(dbg.breaks.end, b); + unsigned long address = strtoul(t, NULL, 0); + struct breakpoint *b = add_breakpoint(th->proc, address); + b->enabled = en; + b->tid = tid; break; } } else { switch (ch) { case KEY_RESIZE: - layout(); + layout(&processes, th); break; - case 0x1b: + case KEY_ESCAPE: mode = 0; console_leave(&cons, right); break; @@ -326,6 +380,12 @@ int main(int argc, char **argv) { } } + for (struct process *p = processes.head; p != processes.end; p = p->next) { + struct process *del = p; + p = p->prev; + dbg_detach(del); + } + endwin(); - return 0; + return EXIT_SUCCESS; } |