diff options
Diffstat (limited to 'misplays.c')
-rw-r--r-- | misplays.c | 372 |
1 files changed, 168 insertions, 204 deletions
@@ -1,10 +1,7 @@ -#include <errno.h> #include <signal.h> +#include <stdio.h> #include <stdlib.h> -#include <string.h> #include <sys/ptrace.h> -#include <sys/wait.h> -#include <linux/ptrace.h> #include <unistd.h> #include <capstone/capstone.h> @@ -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 <pid>\n", argv[0]); - return 1; + fprintf(stderr, "Usage: %s <pid | cmdline>\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 <errno.h> +//#include <signal.h> +//#include <string.h> +//#include <sys/ptrace.h> +//#include <sys/wait.h> +//#include <linux/ptrace.h> + +// //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; |