diff options
author | Malfurious <m@lfurio.us> | 2023-10-02 03:18:21 -0400 |
---|---|---|
committer | Malfurious <m@lfurio.us> | 2024-04-24 13:31:08 -0400 |
commit | 46f72be263cf29688f684e90f2e149e5c911016b (patch) | |
tree | 08a36804eed9ce35470504419dd95553760b3ca7 | |
parent | 67a0755a248c9793a1e7a3cf73f4041b2103ebf7 (diff) | |
download | misplays-46f72be263cf29688f684e90f2e149e5c911016b.tar.gz misplays-46f72be263cf29688f684e90f2e149e5c911016b.zip |
Multithread version 3
Signed-off-by: Malfurious <m@lfurio.us>
-rw-r--r-- | debugger.c | 592 | ||||
-rw-r--r-- | debugger.h | 30 | ||||
-rw-r--r-- | misplays.c | 27 |
3 files changed, 330 insertions, 319 deletions
@@ -1,6 +1,9 @@ #include <dirent.h> +#include <elf.h> #include <signal.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/ptrace.h> #include <sys/uio.h> #include <sys/wait.h> @@ -10,60 +13,32 @@ #include "debugger.h" #include "helpers.h" -#define BREAKPOINT_INSN 0xcc - -//struct list global_processes = {0}; -//struct thread *global_thread = NULL; - static const int PTRACE_OPTIONS = PTRACE_O_TRACECLONE | - //PTRACE_O_TRACEEXIT | PTRACE_O_TRACEEXEC | PTRACE_O_TRACESYSGOOD; -static int detect_breakpoint(struct thread *th) { - int check = 0; - int restart = 0; - - struct user_regs_struct regs; - ptrace(PTRACE_GETREGS, th->id, NULL, ®s); - - struct list *breaks = &th->proc->breakpoints; - for (struct breakpoint *b = breaks->head; b != breaks->end; b = b->next) { - if (b->installed) { - if (!check) { - if (regs.rip - 1 == b->address) { - regs.rip--; - ptrace(PTRACE_SETREGS, th->id, NULL, ®s); - check = 1; - b->hits++; - - if (b->stack != 0 && b->stack != regs.rsp) { - restart = 1; - } +static const int PTRACE_CHILD_OPTIONS = PTRACE_OPTIONS | PTRACE_O_EXITKILL; +static const int STOP_ALL_ON_EVENT = 1; +static const useconds_t SCHEDULER_DELAY = 100000; +static const unsigned int BREAKPOINT_INSN = 0xcc; - if (b->tid != 0 && b->tid != th->id) { - restart = 1; - } - - if (!b->enabled) { - restart = 1; - } - } - } - - ///* this needs moved, we have to finish the for-loop - // * to actually know if restart is true or false... */ - //if (b->enabled < 0 && !restart) { - // struct breakpoint *del = b; - // b = b->prev; - // list_remove(del); - // free(del); - //} +static struct thread *thread_by_id(struct process *proc, pid_t id) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + if (th->id == id) { + return th; } } + return NULL; +} - return restart; +static void free_breakpoints(struct process *proc) { + while (proc->breakpoints.head != proc->breakpoints.end) { + struct breakpoint *b = proc->breakpoints.head; + list_remove(b); + free(b); + } } static void install_breakpoints(struct thread *th) { @@ -88,22 +63,51 @@ static void uninstall_breakpoints(struct thread *th) { ptrace(PTRACE_POKETEXT, th->id, b->address, b->text); b->installed = 0; } - if (b->enabled < 0) { - struct breakpoint *del = b; - b = b->next; - list_remove(del); - free(del); + struct thread *t; + if (b->tid == 0 || + ((t = thread_by_id(th->proc, b->tid)) && !t->shouldcont)) { + struct breakpoint *del = b; + b = b->next; + list_remove(del); + free(del); + } } } } -static void free_breakpoints(struct process *proc) { - while (proc->breakpoints.head != proc->breakpoints.end) { - struct breakpoint *b = proc->breakpoints.head; - list_remove(b); - free(b); +static int detect_breakpoint(struct thread *th, int *restart) { + int ret = 0; + *restart = 0; + + struct user_regs_struct regs; + struct iovec ivregs = { ®s, sizeof(regs) }; + ptrace(PTRACE_GETREGSET, th->id, NT_PRSTATUS, &ivregs); + + /* implement with get_breakpoint? */ + struct list *breaks = &th->proc->breakpoints; + for (struct breakpoint *b = breaks->tail; b != breaks->end; b = b->prev) { + if (b->installed && (regs.rip - 1 == b->address)) { + regs.rip--; + ptrace(PTRACE_SETREGSET, th->id, NT_PRSTATUS, &ivregs); + b->hits++; + ret = b->user; + + if (b->stack != 0 && b->stack != regs.rsp) { + *restart = 1; + } + if (b->tid != 0 && b->tid != th->id) { + *restart = 1; + } + if (!b->enabled) { + *restart = 1; + } + + break; + } } + + return ret; } static void free_states(struct thread *th) { @@ -125,155 +129,166 @@ static void free_states(struct thread *th) { th->clearstates = 0; } -static void capture_state_thread(struct thread *th) { - if (th->clearstates) { - free_states(th); - } - - struct state *s = xmalloc(sizeof(*s)); - ptrace(PTRACE_GETREGS, th->id, NULL, &s->regs); - ptrace(PTRACE_GETFPREGS, th->id, NULL, &s->fpregs); - list_init(&s->maps); - - list_insert(th->states.end, s); - th->state = s; +static void capture_state(struct process *proc) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + if (!th->shouldcont) { + if (th->clearstates) { + free_states(th); + } - char mapspath[32], entry[512]; - snprintf(mapspath, sizeof(mapspath), "/proc/%li/maps", (long)th->id); + struct state *s = xmalloc(sizeof(*s)); + struct iovec regs = { &s->regs, sizeof(s->regs) }; + ptrace(PTRACE_GETREGSET, th->id, NT_PRSTATUS, ®s); + list_init(&s->maps); + + list_insert(th->states.end, s); + th->state = s; + + char mapspath[32], entry[512]; + snprintf(mapspath, sizeof(mapspath), "/proc/%li/maps", (long)th->id); + + FILE *maps = fopen(mapspath, "r"); + if (maps) { + while (fgets(entry, sizeof(entry), maps)) { + struct map *m = xmalloc(sizeof(*m)); + sscanf(entry, "%lx-%lx ", &m->start, &m->end); + size_t size = m->end - m->start; + m->data = xmalloc(size); + + struct iovec loc = { m->data, size }; + struct iovec rem = { (void *)m->start, size }; + if (process_vm_readv(th->id, &loc, 1, &rem, 1, 0) < 0) { + free(m->data); + free(m); + continue; + } - FILE *maps = fopen(mapspath, "r"); - if (maps) { - while (fgets(entry, sizeof(entry), maps)) { - struct map *m = xmalloc(sizeof(*m)); - sscanf(entry, "%lx-%lx ", &m->start, &m->end); - size_t size = m->end - m->start; - m->data = xmalloc(size); + list_insert(s->maps.end, m); + } - struct iovec loc = { m->data, size }; - struct iovec rem = { (void *)m->start, size }; - if (process_vm_readv(th->id, &loc, 1, &rem, 1, 0) < 0) { - free(m->data); - free(m); - continue; + fclose(maps); } + } + } +} - list_insert(s->maps.end, m); +static void interrupt_all_threads(struct process *proc) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + if (!th->stopped) { + ptrace(PTRACE_INTERRUPT, th->id, NULL, NULL); + while (!dbg_wait(th, 0)) {} + } + if (STOP_ALL_ON_EVENT) { + th->shouldcont = 0; } + } +} - fclose(maps); +static void continue_all_threads(struct process *proc) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + if (th->id > 0) { + ptrace(PTRACE_CONT, th->id, NULL, th->signal); + th->stopped = 0; + th->signal = 0; + th->cont = 0; + th->shouldcont = 2; + strcpy(th->status, "RUNNING"); + th->clearstates = 1; + } } } -static void capture_state(struct thread *th, int all) { - (void)all; - struct list *threads = &th->proc->threads; - for (struct thread *t = threads->head; t != threads->end; t = t->next) { - if (!t->state) { - capture_state_thread(t); +/* 0: stop 1: singlestep 2: cont 3: syscall */ +/* this is simplified, surely incorrect, and needs updated once testable */ +static void resume_threads(struct process *proc) { + struct list *threads = &proc->threads; + for (struct thread *th = threads->head; th != threads->end; th = th->next) { + if (th->shouldcont) { + install_breakpoints(th); + ptrace(PTRACE_CONT, th->id, NULL, th->signal); + th->stopped = 0; + th->signal = 0; + th->cont = 0; + strcpy(th->status, "RUNNING"); } } - //if (all) { - // struct list *threads = &th->proc->threads; - // for (struct thread *t = threads->head; t != threads->end; t = t->next) { - // capture_state_thread(t); - // } - //} else { - // capture_state_thread(th); - //} } -static struct process *new_process(pid_t pid, int child) { +static struct process *new_process(pid_t id, int child) { struct process *proc = xmalloc(sizeof(*proc)); - proc->id = pid; + proc->id = id; proc->child = child; - list_init(&proc->threads); list_init(&proc->breakpoints); + list_init(&proc->threads); + memset(proc->status, 0, sizeof(proc->status)); return proc; } -static struct thread *new_thread(struct process *proc, pid_t tid) { +static struct thread *new_thread(struct process *proc, pid_t id) { struct thread *th = xmalloc(sizeof(*th)); th->proc = proc; list_init(&th->states); th->state = NULL; th->clearstates = 0; - th->id = tid; + th->id = id; th->stopped = 0; th->signal = 0; th->cont = 0; - th->status = "RUNNING"; + th->shouldcont = 0; + strcpy(th->status, "RUNNING"); return th; } -static int interrupt_all_threads(struct process *proc) { - int stopped = 0; - struct list *threads = &proc->threads; - for (struct thread *th = threads->head; th != threads->end; th = th->next) { - if (!th->stopped) { - ptrace(PTRACE_INTERRUPT, th->id, NULL, NULL); - while (!dbg_wait(th, 1)) {} - stopped = 1; - } - } - return stopped; -} - -void add_breakpoint(struct process *proc, unsigned long address, unsigned long stack, pid_t tid, int enabled) { +struct breakpoint *add_breakpoint(struct process *proc, unsigned long address) { struct breakpoint *b = xmalloc(sizeof(*b)); b->address = address; b->text = 0; b->installed = 0; b->hits = 0; - b->stack = stack; - b->tid = tid; - b->enabled = enabled; + b->user = 1; + b->stack = 0; + b->tid = 0; + b->enabled = 1; list_insert(proc->breakpoints.end, b); + return b; } -int is_breakpoint(struct process *proc, unsigned long address) { +struct breakpoint *get_breakpoint(struct process *proc, unsigned long address) { struct list *breaks = &proc->breakpoints; for (struct breakpoint *b = breaks->head; b != breaks->end; b = b->next) { if (b->address == address) { - return 1; + return b; } } - return 0; + return NULL; } -//int dbg_attach(pid_t pid, int child) { struct process *dbg_attach(pid_t pid, int child) { - //if (global_processes.end == NULL) { - // list_init(&global_processes); - //} - - struct process *proc = new_process(pid, child); - //list_insert(global_processes.end, proc); - - int options = PTRACE_OPTIONS; - if (child) { - options |= PTRACE_O_EXITKILL; - } + const int OPTIONS = (child ? PTRACE_CHILD_OPTIONS : PTRACE_OPTIONS); char taskpath[32]; snprintf(taskpath, sizeof(taskpath), "/proc/%li/task", (long)pid); DIR *taskdir = opendir(taskpath); if (!taskdir) { - dbg_detach(proc); return NULL; } struct dirent *task; + struct process *proc = new_process(pid, child); + while ((task = readdir(taskdir))) { - pid_t id = strtoul(task->d_name, NULL, 0); + pid_t id = strict_strtoul(task->d_name, 0); if (id != 0) { - if (ptrace(PTRACE_SEIZE, id, NULL, options) < 0) { + if (ptrace(PTRACE_SEIZE, id, NULL, OPTIONS) < 0) { closedir(taskdir); dbg_detach(proc); return NULL; } - struct thread *th = new_thread(proc, id); list_insert(proc->threads.end, th); } @@ -281,137 +296,137 @@ struct process *dbg_attach(pid_t pid, int child) { closedir(taskdir); - //global_thread = proc->threads.head; interrupt_all_threads(proc); - capture_state(proc->threads.head, 0); + capture_state(proc); return proc; } -int dbg_detach(struct process *proc) { +void dbg_detach(struct process *proc) { + /* ptrace requires that threads be stopped before calling PTRACE_DETACH. + * In some cases, a blocked thread can possibly have a pending trap which + * would crash the process if encountered after ptracing. We cycle an extra + * continue/interrupt to consume this trap event ourselves before detaching. + * Threads must actually get scheduled for this to be effective, which is + * the reason for the usleep. A better approach is welcome here. */ interrupt_all_threads(proc); - dbg_realcont(proc->threads.head); - usleep(100000); + continue_all_threads(proc); + usleep(SCHEDULER_DELAY); interrupt_all_threads(proc); - uninstall_breakpoints(proc->threads.head); - free_breakpoints(proc); + /* Supplement to PTRACE_O_EXITKILL */ if (proc->child) { kill(proc->id, SIGKILL); } while (proc->threads.head != proc->threads.end) { struct thread *th = proc->threads.head; - if (th->id >= 0) { + if (th->id > 0) { + uninstall_breakpoints(th); ptrace(PTRACE_DETACH, th->id, NULL, th->signal); + th->id = 0; } - free_states(th); - list_remove(th); - free(th); + dbg_free(th); } + free_breakpoints(proc); list_remove(proc); free(proc); - return 0; } -int dbg_wait(struct thread *th, int recursion) { - if (th->id < 0) { +int dbg_free(struct thread *th) { + if (th->id <= 0) { + free_states(th); + list_remove(th); + free(th); + return 0; + } + return -1; +} + +int dbg_wait(struct thread *th, int primary) { + if (th->id <= 0) { return -1; + } else if (th->stopped) { + return 1; } - /* todo: check what happens if we call on an already known - * stopped thread? */ int status; if (waitpid(th->id, &status, __WALL | WNOHANG) <= 0) { return 0; } if (WIFEXITED(status)) { - th->id = -1; + th->id = 0; th->stopped = 1; th->signal = WEXITSTATUS(status); th->cont = 0; - th->status = "EXITED"; + th->shouldcont = 0; + strcpy(th->status, "EXITED"); return 1; } if (WIFSIGNALED(status)) { - th->id = -2; + th->id = 0; th->stopped = 1; th->signal = WTERMSIG(status); th->cont = 0; - th->status = "TERMINATED"; + th->shouldcont = 0; + strcpy(th->status, "TERMINATED"); return 1; } - int stopped; - struct thread *newth; - struct list *threads; - + struct thread *newth; // event thread unsigned long eventmsg; ptrace(PTRACE_GETEVENTMSG, th->id, NULL, &eventmsg); + /* todo: process status messages */ if (WIFSTOPPED(status)) { switch (status >> 8) { /* todo: other ptrace event stops */ case SIGTRAP | (PTRACE_EVENT_CLONE << 8): newth = new_thread(th->proc, eventmsg); list_insert(th->proc->threads.end, newth); - while (!dbg_wait(newth, 1)) {} + while (!dbg_wait(newth, 0)) {} th->stopped = 1; th->signal = 0; th->cont = 0; - th->status = "CLONE EVENT"; + th->shouldcont = 0; + strcpy(th->status, "CLONE"); th->state = NULL; - if (!recursion) { - stopped = interrupt_all_threads(th->proc); + if (primary) { + interrupt_all_threads(th->proc); uninstall_breakpoints(th); - capture_state(th, stopped); + capture_state(th->proc); + resume_threads(th->proc); } return 1; case SIGTRAP | (PTRACE_EVENT_EXEC << 8): - /* eventmsg contains the tid that actually did the execve */ - threads = &th->proc->threads; - for (struct thread *t = threads->head; t != threads->end; t = t->next) { - if (t->id == (pid_t)eventmsg && (pid_t)eventmsg != th->id) { - t->id = -1; - t->stopped = 1; - t->signal = 0; - t->cont = 0; - t->status = "EXITED"; - break; - } + if ((pid_t)eventmsg != th->id) { + newth = thread_by_id(th->proc, eventmsg); + newth->id = 0; + newth->stopped = 1; + newth->signal = 0; + newth->cont = 0; + newth->shouldcont = 0; + strcpy(newth->status, "EXITED"); } th->stopped = 1; th->signal = 0; th->cont = 0; - th->status = "EXEC EVENT"; - th->state = NULL; - - if (!recursion) { - stopped = interrupt_all_threads(th->proc); - uninstall_breakpoints(th); - capture_state(th, stopped); - } - - return 1; - - case SIGTRAP | (PTRACE_EVENT_EXIT << 8): - th->stopped = 1; - th->signal = 0; /* eventmsg has exit code, but would inject sig */ - th->cont = 0; - th->status = "EXIT EVENT"; + th->shouldcont = 0; + strcpy(th->status, "EXECVE"); th->state = NULL; - if (!recursion) { - stopped = interrupt_all_threads(th->proc); + if (primary) { + interrupt_all_threads(th->proc); uninstall_breakpoints(th); - capture_state(th, stopped); + capture_state(th->proc); + resume_threads(th->proc); } return 1; @@ -420,28 +435,30 @@ int dbg_wait(struct thread *th, int recursion) { th->stopped = 1; th->signal = 0; th->cont = 0; - th->status = "STOP EVENT"; - th->state = NULL; + strcpy(th->status, "STOPPED"); - if (!recursion) { - stopped = interrupt_all_threads(th->proc); + if (primary) { + interrupt_all_threads(th->proc); uninstall_breakpoints(th); - capture_state(th, stopped); + capture_state(th->proc); + resume_threads(th->proc); } - return 1; + return th->stopped; case SIGTRAP | 0x80: th->stopped = 1; th->signal = 0; th->cont = 0; - th->status = "SYSCALL EVENT"; + th->shouldcont = 0; + strcpy(th->status, "SYSCALL"); th->state = NULL; - if (!recursion) { - stopped = interrupt_all_threads(th->proc); + if (primary) { + interrupt_all_threads(th->proc); uninstall_breakpoints(th); - capture_state(th, stopped); + capture_state(th->proc); + resume_threads(th->proc); } return 1; @@ -449,52 +466,35 @@ int dbg_wait(struct thread *th, int recursion) { case SIGTRAP: th->stopped = 1; th->signal = 0; - th->status = "STEP/BREAKPOINT"; - - if (th->cont != 0) { - /* gdb this portion. are there race conditions - * that matter?? */ - install_breakpoints(th); - ptrace(th->cont, th->id, NULL, NULL); - th->cont = 0; - th->stopped = 0; - th->status = "RUNNING"; - return 0; - } - - /* todo: Test two threads hitting a breakpoint at - * the same time. */ - int restart = detect_breakpoint(th); - if (!restart) { - th->state = NULL; - } - if (!recursion) { - stopped = interrupt_all_threads(th->proc); - if (!restart) { - uninstall_breakpoints(th); - capture_state(th, stopped); - } - } + int restart; + int bp = detect_breakpoint(th, &restart); + strcpy(th->status, (bp ? "BREAKPOINT" : "STEP")); + //th->shouldcont = (b && b->enabled == 0); + th->shouldcont = (restart ? 2 : 0); - if (restart) { - dbg_cont(th, PTRACE_CONT); - return 0; + if (primary) { + interrupt_all_threads(th->proc); + uninstall_breakpoints(th); + capture_state(th->proc); + resume_threads(th->proc); } - return 1; + return th->stopped; default: th->stopped = 1; th->signal = WSTOPSIG(status); th->cont = 0; - th->status = "SIGNAL DELIVERY"; + th->shouldcont = 0; + strcpy(th->status, "SIGNAL DELIVERY"); th->state = NULL; - if (!recursion) { - stopped = interrupt_all_threads(th->proc); + if (primary) { + interrupt_all_threads(th->proc); uninstall_breakpoints(th); - capture_state(th, stopped); + capture_state(th->proc); + resume_threads(th->proc); } return 1; @@ -505,58 +505,70 @@ int dbg_wait(struct thread *th, int recursion) { } int dbg_intr(struct thread *th) { - if (th->id < 0 || th->stopped) { + if (th->id <= 0 || th->stopped) { return -1; } ptrace(PTRACE_INTERRUPT, th->id, NULL, NULL); + th->shouldcont = 0; return 0; } -int dbg_cont(struct thread *th, int cont) { - if (th->id < 0 || !th->stopped) { +int dbg_cont(struct thread *th) { + if (th->id <= 0 || !th->stopped) { return -1; } - struct list *threads = &th->proc->threads; - for (struct thread *t = threads->head; t != threads->end; t = t->next) { - ptrace(PTRACE_SINGLESTEP, t->id, NULL, t->signal); + ptrace(PTRACE_SINGLESTEP, th->id, NULL, th->signal); + th->stopped = 0; + th->signal = 0; + th->cont = PTRACE_CONT; + th->shouldcont = 1; + strcpy(th->status, "RUNNING"); + th->clearstates = 1; + return 0; +} - t->stopped = 0; - t->signal = 0; - t->cont = cont; - t->status = "RUNNING"; - t->clearstates = 1; +int dbg_syscall(struct thread *th) { + if (th->id <= 0 || !th->stopped) { + return -1; } + ptrace(PTRACE_SINGLESTEP, th->id, NULL, th->signal); + th->stopped = 0; + th->signal = 0; + th->cont = PTRACE_SYSCALL; + th->shouldcont = 1; + strcpy(th->status, "RUNNING"); + th->clearstates = 1; return 0; } -int dbg_realcont(struct thread *th) { - if (th->id < 0 || !th->stopped) { +int dbg_stepin(struct thread *th) { + if (!th->stopped) { return -1; } - struct list *threads = &th->proc->threads; - for (struct thread *t = threads->head; t != threads->end; t = t->next) { - ptrace(PTRACE_CONT, t->id, NULL, NULL); + if (th->state != th->states.tail) { + th->state = th->state->next; + return 0; + } - t->stopped = 0; - t->signal = 0; - t->cont = 0; - t->status = "RUNNING"; - t->clearstates = 1; + if (th->id <= 0) { + return -1; } + ptrace(PTRACE_SINGLESTEP, th->id, NULL, th->signal); + th->stopped = 0; + th->signal = 0; + th->cont = PTRACE_SINGLESTEP; + th->shouldcont = 1; + strcpy(th->status, "RUNNING"); + th->clearstates = 0; return 0; } -int dbg_step(struct thread *th, int stepover) { - // todo: support step-out - //if (th->id < 0 || !th->stopped) { - // return -1; - //} - +int dbg_stepover(struct thread *th) { if (!th->stopped) { return -1; } @@ -566,39 +578,39 @@ int dbg_step(struct thread *th, int stepover) { return 0; } - if (th->id < 0) { + if (th->id <= 0) { return -1; } - csh cshandle; - cs_open(CS_ARCH_X86, CS_MODE_64, &cshandle); - cs_insn *insn = cs_malloc(cshandle); + csh handle; + cs_open(CS_ARCH_X86, CS_MODE_64, &handle); + cs_insn *insn = cs_malloc(handle); uint64_t address = th->state->regs.rip; size_t size = 128; const uint8_t *code = deref(th, address, size); - cs_disasm_iter(cshandle, &code, &size, &address, insn); + cs_disasm_iter(handle, &code, &size, &address, insn); + + int ret = -1; + if (insn->id == X86_INS_CALL) { + struct breakpoint *b = add_breakpoint(th->proc, address); + b->user = 0; + b->stack = th->state->regs.rsp; + b->tid = th->id; + b->enabled = -1; - if (insn->id == X86_INS_CALL && stepover) { - add_breakpoint(th->proc, address, th->state->regs.rsp, th->id, -1); - th->cont = PTRACE_CONT; + ret = dbg_cont(th); } else { - th->cont = 0; + ret = dbg_stepin(th); } - ptrace(PTRACE_SINGLESTEP, th->id, NULL, th->signal); - - th->stopped = 0; - th->signal = 0; - th->status = "RUNNING"; - cs_free(insn, 1); - cs_close(&cshandle); - return 0; + cs_close(&handle); + return ret; } -int dbg_pets(struct thread *th) { +int dbg_stepback(struct thread *th) { if (!th->stopped) { return -1; } @@ -633,10 +645,6 @@ void *deref(struct thread *th, unsigned long address, size_t size) { -///* current problem to solve: -// * if a SINGLESTEP is interrupted (it was over a blocking syscall for example), -// * a CONT out of that interruption will stop AS IF the SINGLESTEP had completed. -// */ //int dbg_stepout(struct tracee *dbg) { // unsigned long bp = dbg->state->regs.rbp; @@ -12,6 +12,7 @@ struct breakpoint { unsigned long text; int installed; int hits; + int user; unsigned long stack; pid_t tid; @@ -28,7 +29,6 @@ struct map { struct state { LINKEDLIST; struct user_regs_struct regs; - struct user_fpregs_struct fpregs; struct list maps; }; @@ -36,8 +36,9 @@ struct process { LINKEDLIST; pid_t id; int child; - struct list threads; struct list breakpoints; + struct list threads; + char status[128]; }; struct thread { @@ -52,24 +53,25 @@ struct thread { int stopped; int signal; int cont; + int shouldcont; - const char *status; + char status[128]; }; -//extern struct list global_processes; -//extern struct thread *global_thread; - -extern void add_breakpoint(struct process *proc, unsigned long address, unsigned long stack, pid_t tid, int enabled); -extern int is_breakpoint(struct process *proc, unsigned long address); +extern struct breakpoint*add_breakpoint(struct process*proc,unsigned long address); +extern struct breakpoint*get_breakpoint(struct process*proc,unsigned long address); extern struct process *dbg_attach(pid_t pid, int child); -extern int dbg_detach(struct process *proc); -extern int dbg_wait(struct thread *th, int recursion); +extern void dbg_detach(struct process *proc); +extern int dbg_free(struct thread *th); + +extern int dbg_wait(struct thread *th, int primary); extern int dbg_intr(struct thread *th); -extern int dbg_cont(struct thread *th, int cont); -extern int dbg_realcont(struct thread *th); -extern int dbg_step(struct thread *th, int stepover); -extern int dbg_pets(struct thread *th); +extern int dbg_cont(struct thread *th); +extern int dbg_syscall(struct thread *th); +extern int dbg_stepin(struct thread *th); +extern int dbg_stepover(struct thread *th); +extern int dbg_stepback(struct thread *th); extern void *deref(struct thread *th, unsigned long address, size_t size); @@ -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 { |