diff --git a/src/debugger.c b/src/debugger.c index 0170382..c760cb4 100644 --- a/src/debugger.c +++ b/src/debugger.c @@ -1,7 +1,8 @@ #include "debugger.h" -debugger* new_debugger(pid_t pid) { +debugger* new_debugger(char* pname, pid_t pid) { debugger* d = malloc(sizeof(debugger)); + d->pname = pname; d->breakpoints = NULL; d->n_breakpoints = 0; d->pid = pid; @@ -289,7 +290,7 @@ const reg_descriptor* get_register_from_name(const char* name) { } void dump_register(debugger* d, reg_descriptor r) { - printf("%s: 0x%" PRIx64 "\n", r.name, get_register_value(d, r.r)); + printf("%s: 0x%"PRIx64"\n", r.name, get_register_value(d, r.r)); } void dump_registers(debugger* d) { @@ -298,16 +299,56 @@ void dump_registers(debugger* d) { for (i = 0; i < n_registers; i++) dump_register(d, reg_descriptors[i]); } +inline uint64_t read_mem(debugger* d, uint64_t addr) { + return ptrace(PTRACE_PEEKDATA, d->pid, (void*)addr, 0); +} + +inline void write_mem(debugger* d, uint64_t addr, uint64_t val) { + ptrace(PTRACE_POKEDATA, d->pid, (void*)addr, val); +} + +inline uint64_t get_pc(debugger* d) { + return get_register_value(d, rip); +} + +inline void set_pc(debugger* d, uint64_t pc) { + set_register_value(d, rip, pc); +} + +void wait_for_signal(debugger* d) { + int status; + waitpid(d->pid, &status, 0); +} + +void step_over_breakpoint(debugger* d) { + int i; + uint64_t loc = get_pc(d) - 1; + + for (i = 0; i < d->n_breakpoints; i++) { + if (d->breakpoints[i]->addr == (void*)loc) { + breakpoint* b = d->breakpoints[i]; + + if (b->enabled) { + set_pc(d, loc); + + disable(b); + ptrace(PTRACE_SINGLESTEP, d->pid, NULL, 0); + wait_for_signal(d); + enable(b); + } + } + } +} + void run_target(char* program) { if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) perror("Error while creating child: ptrace failed"); else execl(program, program, NULL); } -void debug_continue(pid_t pid) { - int status; - ptrace(PTRACE_CONT, pid, NULL, 0); - - waitpid(pid, &status, 0); +void debug_continue(debugger* d) { + step_over_breakpoint(d); + ptrace(PTRACE_CONT, d->pid, NULL, 0); + wait_for_signal(d); } short debug_loop(char* command, debugger* d) { @@ -317,7 +358,7 @@ short debug_loop(char* command, debugger* d) { command = args[0]; if (!strcmp(command, "c")) { - debug_continue(d->pid); + debug_continue(d); } else if (!strcmp(command, "b")) { if (!args[1]) puts("'b' needs an argument"); else set_breakpoint(d, (void*)strtol(args[1], NULL, 16)); @@ -328,6 +369,14 @@ short debug_loop(char* command, debugger* d) { if (!args[1]) dump_registers(d); else if (!args[2]) dump_register(d, *get_register_from_name(args[1])); else set_register_value(d, get_register_from_name(args[1])->r, atol(args[2])); + } else if(!strcmp(command, "m")) { + uint64_t addr = strtol(args[2], NULL, 16); + if (!args[3]) { + printf("%"PRIx64"\n", read_mem(d, addr)); + } else { + uint64_t val = strtol(args[3], NULL, 16); + write_mem(d, addr, val); + } } else { printf("%s: Unknown command\n", command); } @@ -336,10 +385,10 @@ short debug_loop(char* command, debugger* d) { return quit; } -void run_debugger(pid_t pid) { +void run_debugger(char* pname, pid_t pid) { int status; char* line = NULL; - debugger* d = new_debugger(pid); + debugger* d = new_debugger(pname, pid); short quit = 0; waitpid(pid, &status, 0); @@ -356,6 +405,6 @@ void debug(char* program) { pid_t pid = fork(); if (!pid) run_target(program); - else if (pid > 0) run_debugger(pid); + else if (pid > 0) run_debugger(program, pid); else perror("Error while creating debugger: unable to fork."); } diff --git a/src/debugger.h b/src/debugger.h index 6c24b73..ce0b9ce 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -7,6 +7,8 @@ #ifdef __APPLE__ #include + +#define PTRACE_SINGLESTEP PT_STEP #else #include @@ -14,6 +16,7 @@ typedef short task_t; #endif typedef struct { + char* pname; breakpoint** breakpoints; int n_breakpoints; pid_t pid;