summaryrefslogtreecommitdiffstats
path: root/misplays.c
diff options
context:
space:
mode:
Diffstat (limited to 'misplays.c')
-rw-r--r--misplays.c392
1 files changed, 226 insertions, 166 deletions
diff --git a/misplays.c b/misplays.c
index 8f6e0ee..1ccf3d3 100644
--- a/misplays.c
+++ b/misplays.c
@@ -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;
}